Skip to content

feat: Migrate to TypeScript 6.0.3 (prepare for 7) - #11767

Merged
ovr merged 20 commits into
masterfrom
migrate-typescript-6-0-3
Sep 7, 2026
Merged

feat: Migrate to TypeScript 6.0.3 (prepare for 7)#11767
ovr merged 20 commits into
masterfrom
migrate-typescript-6-0-3

Conversation

@ovr

@ovr ovr commented Sep 4, 2026

Copy link
Copy Markdown
Member

Check List

  • Tests have been run in packages where changes have been made if available
  • Linter has been run for changed code
  • Tests for the changes have been added if not covered yet
  • Docs have been added / updated if required

Description of Changes Made

Bumps typescript from ~5.2.2 to ~6.0.3 in all 43 packages that pin it (cubejs-client-ngx stays on ~5.4.5, pinned by Angular 18) and clears the tsconfig options TypeScript 6.0 turns into hard errors: moduleResolution: node and baseUrl are gone in favour of module/moduleResolution: nodenext, types: ["*"] restores the previous @types/* auto-include now that the default is [], and rootDir is stated explicitly where TS 6 requires it (TS5011). Two packages need a different mode — cubejs-schema-compiler uses moduleResolution: bundler with module: commonjs because antlr4's .d.cts re-exports .d.ts files that are ESM under its own type: module (TS2834, so antlr4 resolves to nothing), and the bundled client-react/playground use bundler too. Because nodenext emits import() verbatim instead of downlevelling it, the two live dynamic-import sites (container.ts loading the user's cube.js, getDriver.ts) are back on require — jest cannot execute a native dynamic import in its CJS VM, an absolute-path ESM import is fatal on Windows, and a native import would put the whole CommonJS module on .default. The remaining source changes are a handful of root causes rather than a long tail (getEnv's Parameters<Vars[T]> alone accounted for 1592 of the 2074 initial errors), @typescript-eslint moves to ^8 with eslint ^8.57.1 and @stylistic/eslint-plugin-ts for the four rules v8 dropped, and cubejs-testing moves to the end of the root reference list because TS 6 keeps a failed module resolution in the cache shared across tsc --build, which broke materialize/crate/redshift on cold builds only.

Verified with a clean yarn tsc, yarn build, yarn lint, packages/cubejs-playground yarn build:lib and per-package yarn unit; the only failures are pre-existing (schema-compiler error-reporter, raw-time-dimension-timezone, client-vue3) or environmental locally (backend-native port conflict, sqlite3 native binding).

🤖 Generated with Claude Code

@ovr
ovr requested review from a team as code owners September 4, 2026 14:40
@github-actions github-actions Bot added driver:mongodb Issues relating to the MongoBI driver driver:redshift Issues relating to the Redshift driver driver:mysql Issues relating to the MySQL/MariaDB driver driver:bigquery Issues related to the BigQuery driver driver:snowflake Issues relating to the Snowflake driver client:core Issues relating to the JavaScript client SDK driver:clickhouse Issues related to the ClickHouse driver driver:athena Issues related to the AWS Athena driver driver:mssql Issues relating to the MSSQL driver driver:prestodb Issues relating to the PrestoDB driver driver:postgres Issues relating to the Postgres driver client:react Issues relating to the React client SDK client:playground Issues relating to the Developer Playground cube store Issues relating to Cube Store backend:cli Issues relating to the CLI utility driver:druid Issues relating to the Druid driver driver:crate rust Pull requests that update Rust code driver:dremio driver:questdb javascript Pull requests that update Javascript code driver:firebolt data source driver driver:databricks driver:duckdb labels Sep 4, 2026
ovr and others added 17 commits September 7, 2026 17:09
`tsc --build` only knew the dependency order from the order of the 43 entries in the root
`tsconfig.json`, because almost no package declared its own `references`. A sequential builder
tolerates that; anything that builds projects in parallel does not, and it was already leaking
into TS 6 as the cold-build-only failure that the "keep cubejs-testing last" workaround papered
over. References are now generated from each package's workspace dependencies (142 edges, no
cycles), so the root list is back to its original order and the workaround is gone.

`rust/cubestore` and `cubejs-client-ws-transport` gain `composite: true` — both are referenced
but were never valid reference targets (TS6306).

Three inferred types in schema-compiler's `.js` were wrong rather than merely loose, and the
generated declarations spread them across every consumer:

| Member | Emitted before | Now |
| --- | --- | --- |
| `BaseQuery.resolveFullMemberPathFn` | `(arg0: member) => string`, where `member` names nothing | `(member: string) => string` |
| `BaseQuery.collectLeafMeasures` | `unknown[]` | `string[]` |
| `TestUtil.debugLog` | `(...args: any[]) => void` inferred from `arguments` | declared rest parameter |

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adding `composite` to cubejs-client-ws-transport carried `declarationDir`'s trailing comment
along with it, where it describes something else entirely.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Answers a review question. Redirecting `antlr4` through `paths` and keeping nodenext was
measured: 280 errors, because the failing extensionless specifiers are inside antlr4's own
`.d.ts` files, whose ESM format comes from antlr4's `type: module` and cannot be changed from
the consumer side. The comment now also states the cost of `bundler` — type-checking against
the `import` condition while emitting require() — and the one dependency it currently affects.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
`docker build` failed with TS6053 for three of the references added in 94276df. The images
copy a subset of the workspace: `testing-drivers.Dockerfile` leaves out the frontend packages
and both it and `dev.Dockerfile` leave out `cubejs-testing`, so a reference to one of those
resolves to a directory with no tsconfig.json.

| Dropped reference | Why it is absent |
| --- | --- |
| server-core -> templates | not copied by testing-drivers.Dockerfile; `@cubejs-backend/templates` comes from the registry there |
| dbt-schema-extension -> testing | `cubejs-testing` is in no image, and it is a devDependency |
| materialize-driver -> testing | same |

Verified by hiding both packages' tsconfig.json and compiling the three packages, which is the
state the image build sees.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`getDriver` threw `driverModule.default is not a constructor` in every drivers-tests job.
Replacing the dynamic import with `require` dropped the `esModuleInterop` wrapper that used to
put the module on `.default`, and the driver packages come in two shapes:

| Shape | Packages | Constructor |
| --- | --- | --- |
| `module.exports = DriverClass` from the `index.js` shim | athena, bigquery, postgres, trino, clickhouse, mssql, mysql, snowflake, redshift, oracle, … | the module itself |
| TypeScript `export default` | databricks-jdbc (`main: dist/src/index.js`) | `.default` |

Now branches on `__esModule`, which is what `__importStar` did. Verified by running the
compiled `getDriver('postgres')`, and the same interop in the `cube.js` loader was re-checked
against both a `module.exports = {...}` and an `export default {...}` config.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Reverts the require() form. Two things were in the way and both are now handled:

| Problem | Fix |
| --- | --- |
| nodenext demands a `.js` suffix on relative specifiers, which jest's resolver does not map back to the `.ts` source | `moduleNameMapper` entry in the shared jest config, inherited by all 31 package configs |
| the compiled `dist` is loaded untransformed by other packages' jest runs, where a native `import()` needs `--experimental-vm-modules` | set on `test-driver`, through which all 59 driver suites run |

Measured against the real compiled BaseDriver from another package's jest run: without the flag
`A dynamic import callback was invoked without --experimental-vm-modules`, with it the import
resolves and the call reaches the GCS SDK. Unit sweep across all 28 packages matches the
baseline.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The Cypress step of the dev-image job failed before running a single test:

```
Your configFile is invalid: packages/cubejs-testing/cypress.config.ts
error TS5107: Option 'moduleResolution=node10' is deprecated and will stop functioning in
TypeScript 7.0.
```

Cypress 14 compiles the config with its bundled ts-node while hard-coding
`moduleResolution: 'node'`, and injects `downlevelIteration` into ts-loader for the specs — then
hands both to whichever TypeScript the project resolves, now 6.0.3. Cypress 15.14.0 added
official TypeScript 6 support: the config loader no longer forces node10 and the bundled
`webpack-batteries-included-preprocessor` stopped injecting `downlevelIteration`. Bumping to
15.21.1 removes both, so nothing has to be silenced with `ignoreDeprecations` and every Cypress
file stays TypeScript.

That left one real error, ours: `cypress/tsconfig.json` still carried the `baseUrl` this branch
removed everywhere else — my earlier sweep globbed `packages/*/tsconfig*.json` and missed a
directory level. It was dead anyway: no tsconfig on the Cypress chain defines `paths`, and every
spec and support import is relative or a bare package name.

Verified locally against a stub server on :3080 — config loads, `cypress/support/*.ts` and the
specs compile with no TS diagnostics; the only failures are the assertions that need a real Cube
app. The plugin packages' `cypress` peer ranges were already stale at 14 and warn the same way.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Addresses a review comment. `cypress/tsconfig.json` inherited `include: ["src", "test"]` from
the package config, but that directory holds `e2e`, `support`, `plugins`, `fixtures`,
`queries.ts` and `global.d.ts` — so the project had zero input files and `yarn tsc` never
checked a single Cypress file. That is why the deprecated `baseUrl` sitting in it could only
surface as a red dev-image job after a full Docker build and birdbox startup.

The project now points at the directories that exist and extends `tsconfig.base.json` directly
rather than the package config, so it does not inherit `nodenext` — these files are bundled by
Cypress's webpack preprocessor for a browser, hence `module: esnext` + `moduleResolution:
bundler` and a DOM lib. It is registered in the root reference list, and root `clean` now also
removes its build output.

Three type errors were hiding behind the dead `include`:

| Error | Cause |
| --- | --- |
| TS2322 ×2 in `support/commands.ts` | `getByTestId`/`getByQa` were declared as `Chainable<Element>`, but `cy.get()` returns `Chainable<JQuery<HTMLElement>>` |
| TS7016 in `support/e2e.ts` | `cypress-image-snapshot` ships no types; declared as an ambient module rather than adding `@types/cypress-image-snapshot`, which types v3 while we run v4 and would collide with the hand-written `matchImageSnapshot` augmentation |

Verified: cold `yarn tsc` and `yarn lint` green, and a Cypress run against a stub server still
loads the config and compiles the support files and specs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Addresses a review comment. The `require()` I had switched to is what `module: commonjs`
downlevelled `import()` into on master (`Promise.resolve(...).then(s => __importStar(require(s)))`
in the 5.2.2 output), so it was not a regression — but it does keep the loader from ever
supporting an ESM config. `pathToFileURL` solves the actual problem, which was handing the ESM
loader a bare absolute path (fatal on Windows), so the dynamic import stays.

The namespace shape differs from `__importStar`'s, so the unwrap is now two steps: a CommonJS
`cube.js` arrives with `module.exports` on `default`, which puts a transpiled `exports.default`
one level deeper.

Verified against every config shape by calling the compiled loader directly:

| `cube.js` | Result |
| --- | --- |
| `module.exports = {...}` | loaded |
| `export default {...}` in a `"type": "module"` project | loaded |
| `export default await ...` (top-level await) | loaded — this threw `ERR_REQUIRE_ASYNC_MODULE` on master |
| transpiled `exports.__esModule` + `exports.default` | loaded |
| ESM with named exports only | `Configuration file must export the configuration as default.`, as before |

No jest suite reaches this path (birdbox starts Cube as its own process), so the native import
needs no VM flag.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`types: ["*"]` restored the pre-TS-6 behaviour, but it also means any
`@types/*` package that lands in the hoisted root `node_modules` injects
its globals into all 43 projects — a package can compile against globals
it never declared a dependency on.

Each project now lists what it actually needs: `["node", "jest"]` for the
backend packages that compile their tests in-project, `["vitest/globals"]`
for client-core, and `[]` for the frontend packages, which get no `node`.

`tsconfig.jest.json` needs the `jest` entry of its own — ts-jest compiles
through that file rather than the per-package tsconfig, so `tsc --build`
staying green says nothing about whether the suites can run.

mssql-driver pinned `typeRoots` to a local `node_modules/@types` that does
not exist, which made `node` unresolvable (TS2688). Its `src/types/mssql.d.ts`
is a `declare module 'mssql'` augmentation already picked up through
`include: ["src"]`, so the typeRoots entry was load-bearing for nothing.

The 23 package.json changes declare the `@types/*` packages those projects
were previously getting for free from root hoisting. Both ranges were
already resolved in yarn.lock, so the lockfile is unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`cypress-image-snapshot` is not updatable — 4.0.1 is latest, published in
2021, with no `types` field, and DefinitelyTyped only ever covered v3. So
the bodyless `declare module` was the only way to keep the import compiling,
at the cost of typing the whole module as `any`.

`@simonsmith/cypress-image-snapshot` is the maintained fork and ships
first-party types, including the `Cypress.Chainable.matchImageSnapshot`
augmentation this file used to hand-write. Its `exports` map has `./command`
and `./plugin` subpaths, which resolve under the project's `bundler`
resolution, and it peers `cypress >=15.10.0` against our 15.21.1.

`addMatchImageSnapshotPlugin` no longer takes `config`.

The `addMatchImageSnapshotCommand` call in support/e2e.ts is checked again —
verified by breaking it both ways:

| edit                    | before      | after                                     |
| ----------------------- | ----------- | ----------------------------------------- |
| `captures: 'viewport'`  | compiles    | TS2561, suggests `capture`                |
| `capture: 'viewPort'`   | compiles    | TS2820, suggests `'viewport'`             |

No committed image baselines exist (CI uploads `cypress/screenshots` as an
artifact rather than diffing against a checked-in snapshot), so the fork's
different snapshot directory layout has nothing to regress.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two projects were still reaching ambient globals transitively, through a
`/// <reference types="..." />` inside a dependency's `.d.ts` — `types`
does not gate reference directives, so an unrelated `@types/*` bump can
take the globals away and break the build with a confusing error.

| package | before | after |
| --- | --- | --- |
| `@cubejs-client/ws-transport` | `[]` | `["node"]` |
| `@cubejs-backend/testing` | `["cypress", "@4tw/cypress-drag-drop"]` | `["node", "jest"]` |

`ws-transport` uses `console`, `setInterval`, `setTimeout` and
`clearInterval` with `lib: ["es2017"]` and no `dom`, so it needs
`@types/node`, now an explicit devDependency (already resolved by the
existing `@types/node@^22` lockfile entry).

`testing` no longer contains any Cypress file — 4774f69 moved those to
`cypress/tsconfig.json`, which declares the Cypress types itself — so
that override only stripped `node` and `jest` from the ~40 jest suites
in `test/`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Follow-up on the review of #11767. Five configs stated something other
than what the code does:

- `cubejs-materialize-driver` had no reference for
  `@cubejs-backend/testing-shared`, which `test/MaterializeDriver.test.ts`
  imports and `include` covers; it built only because the root reference
  list happens to put `cubejs-testing-shared` before it. Its
  `@cubejs-backend/testing` devDependency is imported nowhere, so it is
  replaced by the one that is.
- `cubejs-server-core` dropped `../cubejs-templates`, but
  `src/core/DevServer.ts` imports it and it is a real `dependencies`
  entry. The reference is back and `testing-drivers.Dockerfile` now
  copies the package — it is a backend dependency of server-core, so it
  does not belong under the "we dont need client libraries" banner.
- `cubejs-playground` turned off `noUncheckedSideEffectImports` for the
  whole package to cover exactly two CSS imports (`App.tsx:2`,
  `GraphiQLSandbox.tsx:6`). A `declare module '*.css'` next to the
  existing `svg.d.ts` covers them with the check left on.
- `cypress/tsconfig.json` listed `e2e` in `include`, where every file is
  JavaScript and `allowJs` is off — the entry matched nothing.
- `BaseQuery.js` stacked two JSDoc blocks on `resolveFullMemberPathFn`;
  TypeScript reads the nearest one, so the description was dropped from
  the emitted `.d.ts`. Merged into one block.

Verified with a cold `yarn tsc` (all tsbuildinfo removed), a forced
build of the cypress project, `tsc -p packages/cubejs-playground`,
`yarn lint` in materialize-driver and `yarn lint:npm`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`module: nodenext` keeps `await import()` in the CommonJS emit instead of
downleveling it to `require`, so BaseDriver's lazy storage-fs loads throw
`A dynamic import callback was invoked without --experimental-vm-modules`
under Jest's CJS runtime. Enable the flag for the jest suites that reach
those loads.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ovr
ovr force-pushed the migrate-typescript-6-0-3 branch from af36f03 to 389b650 Compare September 7, 2026 15:11
@claude

claude Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Claude finished @ovr's task in 2m 17s —— View job


Re-review of the rebase onto v1.7.35 — no new authored content, no new findings. Rebase is clean; 3 prior threads still apply.

Full review — what actually changed, verification, and thread status

  • Establish what changed since the last reviewed state
  • Verify the rebase against master's new base (v1.7.35 version bumps)
  • Re-check the migration's own invariants across the tree
  • Check the one new root-level structural addition for Docker safety
  • Resolve stale threads / dedupe against prior comments
  • Post review

Scope

This synchronize is a force-push with no new authored content. The merge base moved from 61f1fa5 (lerna 10) to c93da32 v1.7.35, the lerna release commit that bumps every workspace package to 1.7.35. The 19 commits are the same 19 by title, and their author dates all predate my last review — the newest, 389b650 fix(build): run driver jest suites with --experimental-vm-modules, is dated 2026-09-07 16:29 +0200, i.e. the commit I reviewed as af36f03. So what's genuinely new to review is the interaction between this PR and the release bump.

Verified — the rebase itself

  • The one version-bearing line the PR owns was carried correctly. ebd8f3c swapped materialize's devDep, and the rebase landed it at the new release version rather than leaving a stale pin: the diff against master is exactly -"@cubejs-backend/testing": "1.7.35"+"@cubejs-backend/testing-shared": "1.7.35", and packages/cubejs-testing-shared/package.json:3 really is 1.7.35. No other 1.7.3x literal appears anywhere in the PR's packages/*/package.json delta, which is what a correct rebase of a toolchain bump onto a release commit should look like — the PR touches ranges (typescript, @types/*, @typescript-eslint/*) and lerna touches versions, so the two edits are disjoint everywhere else.
  • No conflict residue. No <<<<<<</>>>>>>> markers in any .json/.ts/.js in the tree.
  • The pin is uniform at the new base: 43 typescript: ~6.0.3 across packages/* + rust/* + root, and exactly one ~5.4.5 (cubejs-client-ngx, as documented). No ~5.2.2 remnant.
  • No TS 6-invalid option reached the tree from master. Re-swept every tsconfig*.json: the only files still carrying baseUrl or moduleResolution: "node" are packages/cubejs-client-ngx (deliberately on 5.4.5) and packages/cubejs-playground/vizard (separate package.json/lockfile, pins its own typescript, built via cd ./vizard && yarn build). Both correctly out of scope, and the release commit added no new workspace package needing coverage.
  • lerna 10 survived: root dependencies still has "lerna": "^10.0.1", untouched by the PR's devDependencies edits.
  • The new root reference is Docker-safe. tsconfig.json's only delta against master is { "path": "packages/cubejs-testing/cypress" }, and neither image copies the root tsconfig.json — both Dockerfiles copy only tsconfig.base.json (dev.Dockerfile:32, testing-drivers.Dockerfile:29) and build via yarn lerna run build, i.e. per-package tsc following each package's own references. Root yarn build is lerna run build:client-core && tsc --build packages/cubejs-client-react && rollup -c, which never reads the root project list either. So adding a project that points at a directory neither image copies cannot reintroduce the TS6053 class of failure that 4b0a6f5 fixed — that failure lived in the per-package reference graph, which is unchanged here.
  • yarn clean still covers the new project's emit (packages/cubejs-testing/cypress/{tsconfig.tsbuildinfo,dist}), which the packages/*/{…} glob would have missed.

Findings

None. Nothing in this push changes code, config values, or the build graph relative to the state I reviewed — the delta is entirely a new merge base.

Comments

No comment changes in this push, and none needed.

Prior threads

Three remain unresolved and still applicable. I re-read all three files in the rebased tree and none is addressed: MemberLabelText.tsx:6 is still ComponentType<Props>, getDriver.ts:13 still hand-rolls driverModule.__esModule ? driverModule.default : driverModule, and packages/cubejs-databricks-jdbc-driver/package.json:22 is still "unit-tests": "jest dist/test --forceExit" with no --experimental-vm-modules.

Thread Status
databricks-jdbc unit-tests — the one suite that reaches the lazy import() didn't get the flag Untouched (sharpest of the three)
testing-drivers/getDriver.ts:13 — third divergent hand-rolled interop Untouched
MemberLabelText.tsx:6ComponentType<Props> erases prop typing Untouched

Nothing became stale, so nothing to resolve, and no duplicate inline comments posted. The force-push marked several already-resolved threads outdated; I left those alone.

Not checked

No node_modules in this job, so no yarn tsc / yarn build / yarn lint. Because the previous head's objects aren't fetchable here, "no new authored content" rests on the commit titles plus author dates rather than a tree-level diff against af36f03 — if any of those commits was amended rather than merely replayed, I would not have seen it. The rebase-quality checks above are the part I verified directly against the working tree. CI on the new base is the authority on the build claim.

· · branch migrate-typescript-6-0-3 ·

Its unload tests reach BaseDriver's lazy `import('./storage-fs/azure.fs.js')`,
which nodenext keeps as a real dynamic import in the CommonJS emit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Claude finished @ovr's task in 53s —— View job


Re-review of 1c7e929 — suggestion applied verbatim; no new findings. 1 thread resolved, 2 prior still apply.

Full review — scope, verification, and thread status

  • Diff the new commit against the previously reviewed state
  • Verify the flag reaches the suite that needs it
  • Re-check that no other suite reaches the lazy loads
  • Resolve stale threads / dedupe against prior comments
  • Post review

Scope

1c7e929 is the only new commit and it's a one-line change: NODE_OPTIONS=--experimental-vm-modules on packages/cubejs-databricks-jdbc-driver's unit-tests script. That's exactly the finding from my last review, applied as suggested.

Verified

  • It's the right script. "test": "npm run unit-tests" delegates to it, so both entry points inherit the flag; unit-tests is the only jest invocation in that package.json.
  • It's still the only suite that needs it. Re-swept every test file in packages/ for .unload(packages/cubejs-databricks-jdbc-driver/test/DatabricksDriver.test.ts (lines 68, 78, 108, 123) remains the sole hit, and it's the only place BaseDriver's await import('./storage-fs/*.fs.js') is evaluated under jest's CJS runtime. The flag is now on all six packages that plausibly touch a dynamic import (base-driver, athena, clickhouse, prestodb, databricks-jdbc, testing-drivers); the other four remain belt-and-braces rather than load-bearing, which is harmless.
  • The .js-stripping mapper still applies here. packages/cubejs-databricks-jdbc-driver/jest.config.js spreads ../../jest.base.config, so moduleNameMapper's ^(\.{1,2}/.*)\.js$ is inherited; jest dist/test resolves the relative storage-fs specifiers inside base-driver's dist either way, since that tree has no .ts siblings.

The one thing this commit doesn't change, and can't: push.yml:137 runs lerna run unit, and this script is named unit-tests, so it still isn't in the CI matrix. Pre-existing and out of scope for a toolchain bump — flagging it only so it's clear the fix is verified by reading, not by a green job.

Findings

None. Nothing else in the tree changed.

Comments

No comment changes in this commit, and none needed — if someone strips the flag the error names itself (A dynamic import callback was invoked without --experimental-vm-modules), and the reasoning lives in the commit message.

Prior threads

Thread Status
databricks-jdbc unit-tests — the one suite that reaches the lazy import() lacked the flag Resolved — this commit
testing-drivers/getDriver.ts:13 — third divergent hand-rolled interop Untouched
MemberLabelText.tsx:6ComponentType<Props> erases prop typing Untouched

No duplicate inline comments posted, and no new ones needed.

Not checked

No node_modules in this job, so no yarn tsc and no jest run — the commit message's claim that the databricks suite now passes is taken at face value, and the sweep above is from reading the tree. CI is the authority on the build.

· · branch migrate-typescript-6-0-3 ·

@ovr ovr changed the title chore(deps): migrate to TypeScript 6.0.3 chore(deps): Migrate to TypeScript 6.0.3 (prepare for 7) Sep 7, 2026
@ovr ovr changed the title chore(deps): Migrate to TypeScript 6.0.3 (prepare for 7) feat(deps): Migrate to TypeScript 6.0.3 (prepare for 7) Sep 7, 2026
@ovr ovr changed the title feat(deps): Migrate to TypeScript 6.0.3 (prepare for 7) feat: Migrate to TypeScript 6.0.3 (prepare for 7) Sep 7, 2026
@ovr
ovr merged commit 98ac580 into master Sep 7, 2026
124 of 131 checks passed
@ovr
ovr deleted the migrate-typescript-6-0-3 branch September 7, 2026 16:04
ovr added a commit that referenced this pull request Sep 7, 2026
`@cubejs-backend/linter` was an eslintrc shareable config extending `airbnb-base`,
consumed by 45 packages plus `rust/cubestore` through a per-package `eslintConfig`
block. CI ran `lerna run --concurrency 1 lint`, i.e. 49 sequential ESLint 8
processes. That toolchain is also at the end of the road: ESLint 8.57.1 is out of
support, and #11767 already had to shuffle four formatting rules into
`@stylistic/eslint-plugin-ts` because typescript-eslint 8 dropped them.

The package now ships an oxlint config instead. `airbnb-base.json` is the mechanical
port of the old rule set, generated from `eslint --print-config` so it is verifiable
rather than hand-transcribed; `.oxlintrc.json` sits on top of it and holds the
deliberate departures, each with its reason. The repo-root `.oxlintrc.json` extends
that and owns the ignore list, so linting is a single root operation and the 49
per-package `lint` scripts and `eslintConfig` blocks are gone.

oxlint implements no formatting rules, so `@stylistic/eslint-plugin` is loaded through
`jsPlugins` to keep the 48 whitespace rules airbnb-base relies on.

| | before (ESLint) | after (oxlint) |
| --- | --- | --- |
| invocations | 49 sequential processes | 1 |
| wall clock, whole repo | minutes | 2.7s (`yarn lint` 4.3s incl. `lint:npm`) |
| files linted | 739 | 873 |
| errors | 0 | 0 |
| warnings | 178 | 149 |

Rule coverage of the 192 rules the old config resolved to: 125 map onto oxlint
natively with identical options, 48 move to `@stylistic/*`, 8 are renamed or re-homed
(`no-new-object` to `no-object-constructor`, `global-require` to `node/global-require`,
`no-buffer-constructor` to `unicorn/no-new-buffer`, and the `@typescript-eslint`
twins of `no-unused-vars` / `no-shadow` / `semi` collapse onto the TS-aware core
rules; the four formatting rules #11767 moved to `@stylistic/ts/*` land on the same
`@stylistic/*` targets, so that change is absorbed). 14 have no equivalent and are
listed at the top of `airbnb-base.json`; the ones worth chasing later are `camelcase`,
`import/order`, `import/no-extraneous-dependencies`, and `consistent-return` /
`dot-notation` / `no-return-await`, which exist only as type-aware `typescript/*`
rules.

Parity was checked by diffing per-file diagnostics against an ESLint run on the
pre-migration tree. Of the 50 previously-linted files involved, 46 match exactly; the
4 that differ are all oxlint being more lenient about destructuring placeholders and
rest siblings. The 40 `quotes` warnings in the baseline are gone because `--fix`
resolved them.

Three things needed configuring rather than porting, all commented in
`packages/cubejs-linter/.oxlintrc.json`: eslint-plugin-import had no TypeScript
resolver, so `import/no-cycle`, `import/export` and the two `no-named-as-default`
rules never actually ran (they now report 173 dependency cycles and 2 real duplicate
exports -- left off, to be fixed separately); oxlint honours neither
`/* globals ... */` nor `/* eslint-env jest */`, so the jest globals come from an
`overrides` entry; and `@stylistic/quotes` gets `allowTemplateLiterals` because
`--fix` otherwise rewrites the driver parameter-escaping tests into backslash soup.

The source changes are `oxlint --fix` output. They are all formatting, and they exist
because `@stylistic` understands TypeScript syntax where ESLint's core rules did not
-- `indent` in generic argument lists and type annotations, `object-curly-spacing`
and `quote-props` in type literals, `space-before-blocks` on interface bodies. Four
files carry a hand-written `eslint-disable` for intentional code: bit twiddling in
the zip helper test, a never-resolving promise in the native test server, and a lazy
`require` in the cypress config.

Also drops the stale `.eslintrc.js` path filters from the workflows (that file has
not existed for some time) and fixes the linter package's `repository.directory`,
which pointed at `packages/cubejs-mssql-driver`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ovr added a commit that referenced this pull request Sep 7, 2026
`@cubejs-backend/linter` was an eslintrc shareable config extending `airbnb-base`,
consumed by 45 packages plus `rust/cubestore` through a per-package `eslintConfig`
block. CI ran `lerna run --concurrency 1 lint`, i.e. 49 sequential ESLint 8
processes. That toolchain is also at the end of the road: ESLint 8.57.1 is out of
support, and #11767 already had to shuffle four formatting rules into
`@stylistic/eslint-plugin-ts` because typescript-eslint 8 dropped them.

The package now ships an oxlint config instead. `airbnb-base.json` is the mechanical
port of the old rule set, generated from `eslint --print-config` so it is verifiable
rather than hand-transcribed; `.oxlintrc.json` sits on top of it and holds the
deliberate departures, each with its reason. The repo-root `.oxlintrc.json` extends
that and owns the ignore list, so linting is a single root operation and the 49
per-package `lint` scripts and `eslintConfig` blocks are gone.

oxlint implements no formatting rules, so `@stylistic/eslint-plugin` is loaded through
`jsPlugins` to keep the 48 whitespace rules airbnb-base relies on.

| | before (ESLint) | after (oxlint) |
| --- | --- | --- |
| invocations | 49 sequential processes | 1 |
| wall clock, whole repo | minutes | 2.7s (`yarn lint` 4.3s incl. `lint:npm`) |
| files linted | 739 | 873 |
| errors | 0 | 0 |
| warnings | 178 | 149 |

Rule coverage of the 192 rules the old config resolved to: 125 map onto oxlint
natively with identical options, 48 move to `@stylistic/*`, 8 are renamed or re-homed
(`no-new-object` to `no-object-constructor`, `global-require` to `node/global-require`,
`no-buffer-constructor` to `unicorn/no-new-buffer`, and the `@typescript-eslint`
twins of `no-unused-vars` / `no-shadow` / `semi` collapse onto the TS-aware core
rules; the four formatting rules #11767 moved to `@stylistic/ts/*` land on the same
`@stylistic/*` targets, so that change is absorbed). 14 have no equivalent and are
listed at the top of `airbnb-base.json`; the ones worth chasing later are `camelcase`,
`import/order`, `import/no-extraneous-dependencies`, and `consistent-return` /
`dot-notation` / `no-return-await`, which exist only as type-aware `typescript/*`
rules.

Parity was checked by diffing per-file diagnostics against an ESLint run on the
pre-migration tree. Of the 50 previously-linted files involved, 46 match exactly; the
4 that differ are all oxlint being more lenient about destructuring placeholders and
rest siblings. The 40 `quotes` warnings in the baseline are gone because `--fix`
resolved them.

Three things needed configuring rather than porting, all commented in
`packages/cubejs-linter/.oxlintrc.json`: eslint-plugin-import had no TypeScript
resolver, so `import/no-cycle`, `import/export` and the two `no-named-as-default`
rules never actually ran (they now report 173 dependency cycles and 2 real duplicate
exports -- left off, to be fixed separately); oxlint honours neither
`/* globals ... */` nor `/* eslint-env jest */`, so the jest globals come from an
`overrides` entry; and `@stylistic/quotes` gets `allowTemplateLiterals` because
`--fix` otherwise rewrites the driver parameter-escaping tests into backslash soup.

The source changes are `oxlint --fix` output. They are all formatting, and they exist
because `@stylistic` understands TypeScript syntax where ESLint's core rules did not
-- `indent` in generic argument lists and type annotations, `object-curly-spacing`
and `quote-props` in type literals, `space-before-blocks` on interface bodies. Four
files carry a hand-written `eslint-disable` for intentional code: bit twiddling in
the zip helper test, a never-resolving promise in the native test server, and a lazy
`require` in the cypress config.

Also drops the stale `.eslintrc.js` path filters from the workflows (that file has
not existed for some time) and fixes the linter package's `repository.directory`,
which pointed at `packages/cubejs-mssql-driver`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend:cli Issues relating to the CLI utility client:core Issues relating to the JavaScript client SDK client:playground Issues relating to the Developer Playground client:react Issues relating to the React client SDK cube store Issues relating to Cube Store cubejs-jdbc-driver data source driver driver:athena Issues related to the AWS Athena driver driver:bigquery Issues related to the BigQuery driver driver:clickhouse Issues related to the ClickHouse driver driver:crate driver:databricks driver:dremio driver:druid Issues relating to the Druid driver driver:duckdb driver:firebolt driver:materialize driver:mongodb Issues relating to the MongoBI driver driver:mssql Issues relating to the MSSQL driver driver:mysql Issues relating to the MySQL/MariaDB driver driver:pinot driver:postgres Issues relating to the Postgres driver driver:prestodb Issues relating to the PrestoDB driver driver:questdb driver:redshift Issues relating to the Redshift driver driver:snowflake Issues relating to the Snowflake driver driver:trino Issues relating to the Trino driver javascript Pull requests that update Javascript code rust Pull requests that update Rust code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants