Repository navigation
Conversation
`tryParseUnknown` swallowed both the JSON and the YAML parse error, so a malformed spec produced a bare "Content is not of supported format JSON/YAML." with no indication of what actually went wrong. Attach the YAML error as `cause` and drop the unused outer binding. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ESLint 9 dropped `.eslintrc` support, so the format had to move before the major could be adopted. The five `.eslintrc.yml` files become a shared `config/eslint.config.base.js` re-exported by a one-line `eslint.config.js` per package; the five `.eslintignore` files become the `ignores` entry in the shared config. The extends chain is re-expressed as `@eslint/js`, the `typescript-eslint` package and `eslint-plugin-prettier/recommended`. `@typescript-eslint/ eslint-plugin` and `@typescript-eslint/parser` are no longer direct dependencies -- `typescript-eslint` provides both. Dependency group: eslint ^8.57.1 -> ^10.9.1 eslint-config-prettier ^9.1.2 -> ^10.1.8 eslint-plugin-json ^3.1.0 -> ^5.0.0 eslint-plugin-prettier ^5.5.4 -> ^5.5.6 @typescript-eslint/* ^7.18.0 -> typescript-eslint ^8.68.0 + @eslint/js ^10.0.1, globals ^17.11.0 Two flat-config specifics worth calling out: - The linted extension set is spelled out explicitly. eslintrc derived it from the default (`.js`) plus the `overrides[].files` patterns that `plugin:@typescript-eslint/recommended` contributed; flat config collects nothing implicitly, so without it `eslint .` would silently lint JavaScript only and still pass. - That glob is deliberately not the `files` of a config that `extends` the shared configs. `tseslint.config()` overwrites an extended config's own `files`, which would spill the TypeScript-only compatibility layer (`no-undef` off, `prefer-const` on, ...) onto plain JavaScript. `reportUnusedDisableDirectives` is pinned to "off" to match eslintrc; flat config defaults it to "warn", which would warn on every generated client file because those carry a blanket `/* eslint-disable */`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
mfal
marked this pull request as ready for review
September 7, 2026 08:11
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.
Why
Bumping
eslintto v10 failed outright because ESLint 9 removed.eslintrcsupport:
So the config format had to move first.
What changed
config/.eslintrc.ymlconfig/eslint.config.base.js.eslintrc.ymlextending iteslint.config.jsre-exporting it.eslintignore(dist/)ignores: ["**/dist/"]in the shared configeslint:recommended@eslint/jsplugin:@typescript-eslint/recommendedtypescript-eslintplugin:prettier/recommended+prettiereslint-plugin-prettier/recommendedDependencies:
All picked as the newest release older than 7 days, per
npmMinimalAgeGate.typescript-eslinthad to come along: v7 peers oneslint ^8.56.0only.@typescript-eslint/eslint-pluginand@typescript-eslint/parserare dropped asdirect dependencies because
typescript-eslintprovides both — this makes #302redundant.
eslint-plugin-jsonis bumped as part of the group, but note it is notreferenced by any config, before or after.
Rule-set evidence
yarn lintbeing green is not evidence that no rule was lost, so every rule wasdiffed explicitly.
eslint --print-configwas captured for one file per packageunder both setups and compared after normalising severities.
The legacy side was reproduced in an isolated install (eslint 8.57.1 +
@typescript-eslint 7.18.0 + the original
config/.eslintrc.yml); it matches thereal pre-migration output rule-for-rule (0 differences), so it is also
trustworthy for the
.jsprobe that the real tree could no longer produce afterthe upgrade.
All four packages resolve to a byte-identical config, as they did before.
.tsfiles — 6 rules lost, 13 gained@typescript-eslint/ban-types@typescript-eslint/no-loss-of-precision@typescript-eslint/no-var-requires@typescript-eslint/no-require-imports, enabled belowno-class-assignts(2629), a compile error. Still on for.jsfiles.no-withts(1101)/ts(2410). Still on for.jsfiles.no-inner-declarationseslint:recommendedin ESLint 9 (block-scoped function declarations are valid since ES2015). Genuine loss, upstream decision.Gained:
@typescript-eslint/no-empty-object-type,no-unsafe-function-type,no-wrapper-object-types(theban-typessplit),no-require-imports,no-unused-expressions,prefer-namespace-keyword, plus the ESLint 9/10recommended additions
no-constant-binary-expression,no-empty-static-block,no-loss-of-precision,no-unassigned-vars,no-unused-private-class-members,no-useless-assignment,preserve-caught-error..jsfiles — 5 lost, 14 gainedSame first three plus
no-inner-declarations, plusno-new-symbol(deprecatedin ESLint 9, replaced by
no-new-native-nonconstructor, which is gained).no-class-assignandno-withstay on here, as they should.The first attempt at this config did lose 17 rules on
.jsfiles:tseslint.config()overwrites an extended config's ownfiles, so putting theextension glob on the object that
extendsthe shared configs spilled theTypeScript-only compatibility layer (
no-undefoff,no-const-assignoff,prefer-conston, …) onto plain JavaScript. The config is structured to avoidthis, and there is a comment saying so.
Severity changes
None. Zero rules changed severity in either direction.
Option changes
20 rules print different options, but all except two are ESLint 10 materialising
meta.defaultOptions(a print-config change introduced in 9.15) at values equalto the ESLint 8 defaults — verified against the ESLint 8 rule sources. The two
real ones are upstream ESLint 9/10 decisions:
no-constant-condition: defaultcheckLoopstrue→"allExceptWhileTrue", sowhile (true)is now allowed (loosening).no-shadow-restricted-names: newreportGlobalThis, defaulting totrue, so shadowingglobalThisis now reported (tightening).Not visible in the printed options but real: typescript-eslint v8 follows
ESLint 9 in defaulting
no-unused-vars'caughtErrorsto"all"instead of"none". This surfaced two genuine unused catch bindings — see below.Repo-specific rules
linebreak-style,quotes,semi,@typescript-eslint/no-unused-varsand@typescript-eslint/no-explicit-anyresolve identically, including options, andstill win over
eslint-config-prettieras they did under eslintrc.The
test-typesoverride@typescript-eslint/no-unused-expressionsis off for*.test-types.ts{,x}.It resolves to
offfor those files and forcing it on produces 6 errors in thetsd-style type tests, so the override is both effective and load-bearing.
Globals
env: {browser, es2021, node}becomesglobals.browser+globals.node;the ES globals come from
languageOptions.ecmaVersion: "latest"automatically.Verified empirically —
Array,Promise,Intl,Error,globalThis,windowandBufferall resolve, andno-undefstill catches genuinelyundefined names.
22 names present under eslint 8 no longer resolve. All are obsolete or
worklet-scope-only web APIs removed from the
globalspackage between v13 andv17 (
ApplicationCache,openDatabase,HTMLShadowElement,defaultStatus,AudioWorkletGlobalScope,registerProcessor, …); 456 modern ones were added.This only affects
no-undef, which is off for TypeScript anyway.Which files get linted
Under eslintrc the extension set came from the default (
.js) plus theoverrides[].filespatterns contributed byplugin:@typescript-eslint/recommended. Flat config collects nothingimplicitly, so the glob is spelled out — without it
eslint .would lintJavaScript only and still report success.
Per-package file lists are identical before and after, except for two additions
each: the new
eslint.config.js, and.prettierrc.js, which ESLint 8 skipped asa dotfile and flat config no longer does. Both lint clean.
reportUnusedDisableDirectivesis pinned to"off". eslintrc never reportedthese; flat config defaults to
"warn", which warns on 6 generated client filesbecause those carry a blanket
/* eslint-disable */. Turning it on is areasonable follow-up, but it needs a generator change and would be a separate
decision.
Source change
caughtErrors: "all"and the newpreserve-caught-errorrule flaggedUniversalContentLoader.tryParseUnknown, which swallowed both parse errors andthrew a bare "Content is not of supported format JSON/YAML." with no indication
of what went wrong. Committed separately as
fix(generator):— the YAML error isnow attached as
cause.Verification
yarn lint— 4 projects, clean (also with--skip-nx-cache)yarn nx run-many -t build --skip-nx-cache— 4 projectsyarn nx run-many -t test --skip-nx-cache— 4 projects + 9 dependent tasks, includingtest:client-generation-cleanon a committed treeyarn test:licenses— exit 0Note for the reviewer
The task description said the
no-unused-expressionsoverride for*.test-types.tsalready existed. It did not — nothing in the repo referencedthat rule. Under typescript-eslint v7 the rule was not part of
recommended, sonothing suppressed anything; v8 added it, which is exactly when the type tests
would have started failing. The override is added here.
🤖 Generated with Claude Code