What happens
With @anolilab/eslint-config 28.0.1 on ESLint 10.7.0, applying any n/no-unsupported-features/* rule in a config entry without a files key attaches it to Markdown documents too (via @eslint/markdown's language). ESLint then dies while loading the rule:
TypeError: Error while loading rule 'n/no-unsupported-features/node-builtins':
Cannot read properties of undefined (reading 'globalScope')
at Object.create (…/eslint-plugin-n/lib/rules/no-unsupported-features/node-builtins.js:72:41)
A Markdown document has no scopeManager, and the rule dereferences sourceCode.scopeManager.globalScope unconditionally:
create(context) {
const sourceCode = getSourceCode(context)
const tracker = new ReferenceTracker(
/** @type {NonNullable<typeof sourceCode.scopeManager.globalScope>} */ (
sourceCode.scopeManager.globalScope
)
)
Because it throws at load time rather than during linting, a single committed .md file takes down the entire run for that package — it reports a crash instead of results, and it cannot be fixed by editing the Markdown.
eslint-plugin-n 18.x does not fix this
Worth stating up front, since "just upgrade" is the obvious first answer. The same unguarded dereference is present at tag v18.2.2; the NonNullable<…> around it is a type assertion with no runtime effect. Upgrading the plugin is not a workaround.
Repro
In any package whose config sets n/no-unsupported-features/node-builtins in a blanket rules block:
echo "# hi" | pnpm exec eslint --stdin --stdin-filename notes.md # → the TypeError above
The same probe in a package that does not set the rule is clean, which is what localises it to the unscoped application rather than to the preset's Markdown wiring itself.
Ask
Scope the preset's n/ rules with a files key (or ship a Markdown-scoped off-block inside the preset), so each consumer doesn't have to rediscover this.
Our workaround is a files: ["**/*.md", "**/*.md/**"] block turning the three n/no-unsupported-features/* rules off, which we now carry in 48 configs. It stays correct and inert after a preset-side fix, so there's no migration cost to fixing it upstream.
What happens
With
@anolilab/eslint-config28.0.1 on ESLint 10.7.0, applying anyn/no-unsupported-features/*rule in a config entry without afileskey attaches it to Markdown documents too (via@eslint/markdown's language). ESLint then dies while loading the rule:A Markdown document has no
scopeManager, and the rule dereferencessourceCode.scopeManager.globalScopeunconditionally:Because it throws at load time rather than during linting, a single committed
.mdfile takes down the entire run for that package — it reports a crash instead of results, and it cannot be fixed by editing the Markdown.eslint-plugin-n18.x does not fix thisWorth stating up front, since "just upgrade" is the obvious first answer. The same unguarded dereference is present at tag
v18.2.2; theNonNullable<…>around it is a type assertion with no runtime effect. Upgrading the plugin is not a workaround.Repro
In any package whose config sets
n/no-unsupported-features/node-builtinsin a blanketrulesblock:The same probe in a package that does not set the rule is clean, which is what localises it to the unscoped application rather than to the preset's Markdown wiring itself.
Ask
Scope the preset's
n/rules with afileskey (or ship a Markdown-scoped off-block inside the preset), so each consumer doesn't have to rediscover this.Our workaround is a
files: ["**/*.md", "**/*.md/**"]block turning the threen/no-unsupported-features/*rules off, which we now carry in 48 configs. It stays correct and inert after a preset-side fix, so there's no migration cost to fixing it upstream.