Skip to content

n/no-unsupported-features/* crash the linter on Markdown under ESLint 10 #1084

Description

@prisis

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions