fix(linter): improve convert-to-flat-config output fidelity#35330
Open
leosvelperez wants to merge 6 commits intomasterfrom
Open
fix(linter): improve convert-to-flat-config output fidelity#35330leosvelperez wants to merge 6 commits intomasterfrom
leosvelperez wants to merge 6 commits intomasterfrom
Conversation
- Stop emitting the `**/dist`/`**/out-tsc` ignores block when the source config didn't include those patterns. - Rewrite stale `.eslintrc(.base)?.json` refs inside rule option values (e.g. `@nx/dependency-checks`'s `ignoredFiles`) to their flat-config counterparts so references don't point at deleted files. - Drop dead `FlatCompat` scaffold emitted for overrides whose only compat-looking field was a parser; parsers now use hoisted static imports and don't need compat. - Accept `.eslintrc` (no extension) as a convertible source. - Dedupe `files`/`excludedFiles` arrays after glob mapping.
- Extract `renameLegacyEslintrcFile` shared by `addExtends` and the stale-ref rewriter to collapse duplicated regex logic. - Extract `preprocessRules` helper — the rename + rewrite pipeline ran identically on top-level and override rules. - Merge `ignorePatterns` filter into a single predicate. - Collapse `mapFilePaths` `files`/`excludedFiles` arms into a local `normalize` helper. - Use `basename(source) === '.eslintrc'` instead of inline regex. - Drop dead `if (!rules || typeof rules !== 'object')` guard in `renameLegacyWorkspaceRules`; tighten signature. - Drop `as unknown as T` casts from `rewriteStaleEslintrcRefs` by typing it as `unknown -> unknown` and casting once at the boundary.
The converter left references to the deleted `.eslintrc[.base].json`
and `.eslintignore` files scattered across nx.json (targetDefaults
inputs, namedInputs) and project.json (targets inputs, namedInputs),
as well as inside the generated flat config itself (`ignoredFiles`
in rule options referencing `.eslintignore`).
Generalize the rewrite:
- Extend `renameLegacyEslintrcFile` to also handle `.eslintignore`.
- Replace the hardcoded triple in `updateNxJsonConfig` with a sweep
over every `targetDefaults[*].inputs` and `namedInputs[*]`, still
ensuring the lint target / production named input carry the new
`eslint.config.<fmt>` entry.
- Walk every project via `getProjects`, rewriting `targets[*].inputs`
and `namedInputs[*]`.
- Handle both plain-string inputs and `{ fileset }` shapes; leave
runtime/env/dependentTasksOutputFiles/externalDependencies alone.
- Dedupe after rewriting so newly-added flat-config entries don't
collide with legacy entries they replaced.
- Preserve the original `{ fileset }` entry reference in
`rewriteLegacyInputs` when the fileset doesn't change, so
`inputsEqual` no longer reports spurious mutations and skips the
needless `updateProjectConfiguration` write.
- Update `rewriteStaleEslintrcRefs` doc comment to mention `.eslintignore`
— the helper has been handling it since the input-sweep change.
…ionless .eslintrc support
- Restore master's narrow ignorePatterns filter. The previous version
dropped every pattern starting with `!`, losing the un-ignore half of
pairs like `['dist/**', '!dist/keep.js']` that flat config still
honors. Only the `!**/*` sentinel is now filtered out.
- Extend the legacy-filename regex in `renameLegacyEslintrcFile` and the
local-extends match in `addExtends` to accept extensionless `.eslintrc`
(ESLint treats it as JSON by convention). Without this, leaves
`extends: ['../../.eslintrc']` were rewritten as
`...compat.extends('../../.eslintrc')` — pointing at a file the
converter just deleted.
- Replace the "sentinel" terminology with a concrete explanation of
which `ignorePatterns` entries are dropped and why.
- Tighten `inputsEqual` into a one-liner using `Array.prototype.every`.
- Rename the new test to describe the behavior it guards against
("paired with broader ignores") rather than the internals.
✅ Deploy Preview for nx-dev ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for nx-docs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Contributor
|
View your CI Pipeline Execution ↗ for commit eaf432d
☁️ Nx Cloud last updated this comment at |
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.
Current Behavior
Running
@nx/eslint:convert-to-flat-configagainst a workspace with legacy.eslintrcconfigs produces flat configs that don't faithfully reflect the source, and leaves stale references to the deleted files behind:{ ignores: ['**/dist', '**/out-tsc'] }block prepended, even when the legacy config never ignored those paths.parser(e.g.jsonc-eslint-parserforpackage.json) get a full@eslint/eslintrcFlatCompat scaffold —FlatCompatimport,dirname,fileURLToPath,js, theconst compat = new FlatCompat({...})block — that's never referenced.@nx/dependency-checks'signoredFiles) keep pointing at.eslintrc.json/.eslintrc.base.json/.eslintignoreafter those files are deleted.nx.jsongets the neweslint.config.<fmt>entry added to the lint target andproductionnamed input, but legacy.eslintrc.json/.eslintignoreentries stay in place. OthertargetDefaultsinputs andnamedInputsare never rewritten.project.jsonfiles aren't touched at all — everytargets[*].inputsornamedInputs[*]that referenced the deleted files stays stale.extends: '../../.eslintrc'(extensionless — ESLint's JSON-by-convention form) aren't supported: the source file isn't converted, and if a leaf extends one that was converted elsewhere the leaf ends up with...compat.extends('../../.eslintrc')pointing at nothing.ignorePatternsentries that started with!were being dropped wholesale, destroying real un-ignores like['dist/**', '!dist/keep.js']that flat config still honors.files/excludedFilesarrays with source-side duplicates (e.g.package.json,./generators.json,./executors.jsonrepeated in the same override) are emitted with the duplicates intact.Expected Behavior
Conversion preserves the semantics and intent of the legacy config, rewrites everything that referred to the deleted files, and drops noise that serves no purpose in flat config:
**/dist/**/out-tscignore block is no longer added. If the legacy config didn't ignore those paths, the converted one doesn't either — migration stays faithful to the source. (lint-projectstill adds them for fresh scaffolding, where there's no source intent to preserve.).eslintrc[.base].jsonor.eslintignoreare rewritten to the flat-config equivalent. Accidentally collapsed duplicates inside string arrays are deduped.nx.jsonis swept generically — everytargetDefaults[*].inputsandnamedInputs[*]gets legacy filenames rewritten, with dedup so the rewrite doesn't collide with freshly-added entries.{ fileset }shapes are handled; non-path shapes (runtime,env,externalDependencies,dependentTasksOutputFiles, named-input refs) are left untouched.project.jsonreceives the same sweep acrosstargets[*].inputsandnamedInputs[*]..eslintrcis now a convertible source, andextendspaths that point at../../.eslintrc(or.eslintrc.base) are rewritten to the generated base config and imported asbaseConfig.ignorePatternslike!dist/keep.jssurvive the conversion; only the legacy**/*/!**/*/node_modulescatch-alls are dropped.files/excludedFilesarrays are deduped after glob mapping, so source-side duplicates and glob-normalization collisions collapse.