Repository navigation
chore: migrate to @nextcloud/eslint-config 9 - #248
Merged
Merged
Conversation
oleksandr-nc
force-pushed
the
chore/eslint-config-9
branch
8 times, most recently
from
September 29, 2026 13:00
2d5abd6 to
6417d4e
Compare
Its ESLint 10 reads a flat config only, so .eslintrc.cjs becomes eslint.config.js, whose rules apply to the app sources, leaving the exemptions version 9 grants test files in place. The lint workflow watched .eslintrc.* and .eslintignore, neither of which exists any more, and webpack.js was the last place configuring ESLint the old way: nothing declares its dependencies, so it could not run at all. The import rules are gone from the shared config, so 'import/extensions' goes with them, as do the babel parser options and the appVersion global the sources do not use, which the shared config declares anyway. 'no-console' was built into the old config and is now spelled out. The sources follow what the new rules ask for: sorted imports, blank lines between multi line component options, and camel cased attributes and events in templates. Unused callback parameters are gone, and the dashboard component is called GithubDashboard, because a name of one word can collide with an HTML element. One rule asks for the ellipsis character in a translatable string and so pointed at the widget's 'Loading...' message, which the dashboard component can never show, because it draws its own placeholder while it loads: the branch is gone rather than retranslated. The shared config brings @nextcloud/no-deprecated-library-props, which holds the prop renames of the library, gates each on the installed version and reports them. It calls itself fixable, but none of its forty reports carries a fixer, so it only pointed at NcPopover's focus-trap: the rename to noFocusTrap, and inverting the value it carried, are by hand. The old spelling was not declared any more, so the popover built a focus trap around content that holds a name and nothing tabbable, and focus-trap threw every time the popover opened. The .native modifier of three mouse listeners is one the Vue 3 compiler drops while keeping the listener, so removing it changes nothing; that holds for these three, not for key events, where the modifier is compiled as a key name and swallows the handler. NcLoadingIcon was given the name of its spinner as 'title'. The prop is called name, and the component writes it into the aria-label of a span with role img, so the spinner of the author popover carried an empty accessible name while the translated string sat on a tooltip. The widget passed its label to the dashboard component as 'showMoreText'. The prop is called showMoreLabel, so the link under a full widget read 'More items …' instead of what the widget asked for. Two more strings the widget cannot show go with it: a data property of the old name that the template never read, and the emptyContentMessage the dashboard component only uses as the fallback of a slot this widget always fills. Folding a comment, the popover of a comment author, the name of its spinner and the link under a full widget had no tests, and now have them. eslint.config.js has no place in the released archive, and neither the .eslintrc.js the packaging lists named nor the webpack.js and webpack.config.js they excluded exist here. The lint scripts passed --ext, which ESLint 10 ignores. The change filters named .eslintrc.* and an .eslintignore this app never had, and name the config file now, which their '**.js' entry matches only by the extension this app happens to use. Signed-off-by: Oleksander Piskun <oleksandr2088@icloud.com>
oleksandr-nc
force-pushed
the
chore/eslint-config-9
branch
from
September 29, 2026 13:28
6417d4e to
de3b5a7
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
@nextcloud/eslint-config9 brings ESLint 10, which reads a flat config only and ignores.eslintrc.*.The config
.eslintrc.cjsbecomeseslint.config.js, spreadingrecommendedJavascriptbecause the components here are plain JavaScript. The overrides that still exist are kept,no-consoleis spelled out because the old config had it built in, and three things are dropped:import/extensions, since the shared config no longer ships eslint-plugin-import, the babel parser options, and theappVersionglobal the sources never use.The config now knows the library
Version 9 adds
@nextcloud/no-deprecated-library-props, which holds the prop renames of@nextcloud/vueand gates each one on the installed version. It declares itselffixable, but none of its forty reports carries a fixer —eslint --fixonly camelCases the attribute and leaves the error standing — so it pointed atNcPopover's:focus-trap="false"and the rename tonoFocusTrap, together with inverting the value, is by hand.It was worth doing. The old spelling is not declared any more, so
NcPopoverbuilt its focus trap, and the content of this popover is a name with nothing tabbable in it —focus-traprefuses to activate around that and throws. Every time the popover opened it loggedYour focus-trap must have at least one container with at least one tabbable node in it at all timesand lefttabindex="-1"on the popper; withnoFocusTrapthe trap is never built, the popper keepstabindex="0"and the errors are gone.One attribute that said nothing at all
Three listeners of the issue and pull request reference widget carried the
.nativemodifier. The Vue 3 compiler drops it and keeps the listener —@mouseenter.nativecompiles toonMouseenter— so these listeners worked and removing the modifier changes nothing beyond satisfying the rule. That holds for mouse events: on a key event the modifier is compiled as a key name and the handler never fires.One spinner nobody could hear
NcLoadingIconwas handed the name of the spinner astitle. The prop isname, and the component writes it into thearia-labelof a<span role="img">, so the spinner of the author popover rendered asaria-label=""— an image with no accessible name — while the translated Loading data sat on atitleattribute that only a mouse can reach.nameputs it where assistive technology reads it, and adds the<title>inside the svg.One prop that had stopped working
The widget passed its label as
showMoreText. The prop ofNcDashboardWidgetisshowMoreLabel, so the link under a full widget read More items … instead of the label the widget asked for.Two more strings that could never appear go with it: a
showMoreTextentry indata()that the template never read, and:emptyContentMessage, whichNcDashboardWidgetonly renders as the fallback of anempty-contentslot this widget always supplies.The sources
What the new rules ask for, which
eslint --fixapplied: imports sorted, blank lines between multi line component options, attributes and events camel cased in templates. By hand: unused callback parameters are gone, and the dashboard component is calledGithubDashboard, since a component name of one word can collide with an HTML element.One rule asks for the ellipsis character in a translatable string, which pointed at the widget's Loading....
NcDashboardWidgetdraws its own placeholder whileloadingis set and only renders theempty-contentslot once it is not, so that branch can never be shown: it is gone rather than retranslated, and the app ends up with one source string fewer instead of one more.Along the way
The rules of this app apply to its own sources, so the exemptions version 9 grants test files survive. The change filters of both workflows named
.eslintrc.*and an.eslintignorethis app never had, and name the config file now — which their**.jsentry already matches, by the extension this app happens to use.webpack.jsconfigured ESLint the old way and could not run at all, since nothing declares its dependencies, so it is gone. Andeslint.config.jsis excluded from the released archive, where neither the.eslintrc.jsof the packaging lists nor thewebpack.jsandwebpack.config.jsthey excluded exist.🤖 AI (if applicable)