Skip to content

ESLint crashes repo-wide under TypeScript 7 native (sonarjs + @typescript-eslint incompatible) #148

Description

@prisis

Summary

Since the TS7/oxc migration landed on alpha (ce59723f, repo typescript = 7.0.2 native), ESLint crashes in every package — it can't parse a single file. pnpm run lint:eslint fails with TypeError for all ~50 projects, so the Lint (eslint) CI job is red on every PR against alpha (surfaced whenever a PR touches paths that re-trigger the path-filtered lint jobs).

This is a toolchain-vs-TS7 incompatibility, independent of any feature branch.

Root cause (two layers)

The eslint toolchain predates TypeScript 7 native and reads the classic JS compiler API, which the native package's module shape omits.

Layer 1 — eslint-plugin-sonarjs@4.0.3 (pinned transitively by @anolilab/eslint-config@28.0.1):

TypeError: Cannot read properties of undefined (reading 'FunctionType')
  at .../eslint-plugin-sonarjs/cjs/S2201/rule.js:244
  const FunctionTypeNodeKind = typescript_1.default.SyntaxKind.FunctionType; // SyntaxKind undefined on native

It does a bare require("typescript") (no declared typescript dependency or peer), so it grabs the hoisted v7-native package.

Layer 2 — @typescript-eslint/typescript-estree@8.59.4 (peer typescript >=4.8.4 <6.1.0):

TypeError: Cannot read properties of undefined (reading 'Cjs')
  at .../typescript-estree/dist/create-program/shared.js:59
  exports.DEFAULT_EXTRA_FILE_EXTENSIONS = new Set([ ts.Extension.Cjs, ... ]); // Extension.Cjs absent on native

typescript@7.0.2 is outside its supported peer range and isn't CJS-require-loadable the way it expects.

Why a scoped fix doesn't work

  • sonarjs has no dependency edge for typescript, so a pnpm override (eslint-plugin-sonarjs>typescript) has nothing to target. A .pnpmfile.cjs readPackage hook injecting a classic typescript dep does fix sonarjs — but only moves the crash to Layer 2.
  • typescript-estree resolves the peer typescript that each package provides, which is the v7-native one the build requires (catalog tsc.typescript: 7.0.2). Isolating a separate classic TS for the parser without changing the build's TS isn't achievable via pnpm overrides/hooks (verified: both classic 5.9.3 and 6.0.3 have the full API; 7.0.2 native can't be CJS-required at all).

The real fix (pick one)

  1. Bump the eslint TypeScript toolchain to a TS7-native-compatible release — a @typescript-eslint version whose peer allows TS7 and that reads it correctly, plus a @anolilab/eslint-config bump that carries a compatible eslint-plugin-sonarjs. (Newer @typescript-eslint/typescript-estree 8.62/8.64 are already in the tree transitively — worth checking whether any published line supports TS7 yet.)
  2. Run ESLint against classic TypeScript while the build uses v7 native — a dedicated classic typescript for the lint toolchain, wired so sonarjs + the whole @typescript-eslint stack resolve it (non-trivial given the peer resolution).
  3. Drop eslint-plugin-sonarjs (or the type-aware rules) from @anolilab/eslint-config until upstream supports TS7 — clears Layer 1 but not Layer 2.

Pinned versions (pnpm-workspace catalogs)

  • typescript: 7.0.2 (native)
  • eslint: 10.7.0
  • @anolilab/eslint-config: 28.0.1 → pins eslint-plugin-sonarjs@4.0.3
  • @typescript-eslint/parser: >=8.59.1 (installed 8.59.4)

Repro

pnpm run lint:eslint            # crashes for every project
pnpm --filter "@lunora/fingerprint" run lint:eslint   # minimal repro

Impact

Lint (eslint) is red on every PR against alpha. Unblocking observed on PR #147 (structured logging) where all other checks were made green.

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