Upgrade Fluent UI to TypeScript 6 - #31
Open
mainframev wants to merge 42 commits into
Open
Conversation
- Pin root TypeScript to 6.0.3. - Update the Vite starter template TypeScript pin to ~6.0.3. - Upgrade typescript-eslint packages (typescript-eslint, @typescript-eslint/eslint-plugin, @typescript-eslint/rule-tester, @typescript-eslint/type-utils, @typescript-eslint/utils) to 8.64.0, the closest available release whose typescript peer range (>=4.8.4 <6.1.0) officially covers TypeScript 6.0.3 (verified identical to 8.65.0's peer contract; 8.65.0 itself only adds an unrelated TS7-detection warning and was unreachable from this environment's registry mirror at commit time). - Upgrade ts-jest to 29.4.11, the closest available release whose typescript peer range (>=4.3 <7) covers TypeScript 6.0.3 (same peer contract as 29.4.12; 29.4.12 was unreachable from this environment's registry mirror at commit time). - Regenerate the patch-package patch for @typescript-eslint/eslint-plugin against 8.64.0 (content unchanged, only the target version differs). - Regenerate yarn.lock with Yarn classic (v1.23.34, the package manager pinned by this worktree's .yarnrc/.yarn/releases) and deduplicate the resulting typescript-eslint resolutions. - Verified ts-loader, ts-node, fork-ts-checker-webpack-plugin, @microsoft/api-extractor, and @nx/js declare permissive or bundled typescript version constraints and require no changes. yarn check:installed-dependencies-versions passes. Running nx test/lint on a sample package now fails with the expected TS5101/TS5107 baseUrl/moduleResolution=node10 deprecation errors from tsconfig.base.json — this is anticipated and left for the follow-up tsconfig migration task, not fixed here. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ependency bump Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rity Task 2 code-review fix: the regenerated yarn.lock for the TypeScript 6.0.3 compiler-toolchain upgrade introduced internal Azure DevOps mirror URLs (ms-feed-*.pkgs.visualstudio.com/1es-public/...) and weaker SHA-1 integrity entries for the 24 packages that were newly resolved or re-resolved by that task (typescript@6.0.3, the typescript-eslint@8.64.0 family, ts-jest@29.4.11, and their transitive dependencies). - Replaced all ms-feed-*.pkgs.visualstudio.com resolved URLs with the canonical https://registry.yarnpkg.com/... convention already used throughout the rest of the lockfile. - Replaced all sha1- integrity values (re-encodings of the same shasum already present in each entry) with authentic sha512- integrity retrieved from the r.cnpmjs.org npm registry mirror, which mirrors npm's original signed package metadata verbatim (each entry's metadata carries a valid npm registry ECDSA signature, keyid SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U, confirming the metadata is unmodified/authentic and not fabricated). - Verified every replaced shasum (the SHA-1 hex already embedded in each resolved URL fragment) matches byte-for-byte between the old lockfile entries and the independently-fetched metadata, confirming the underlying tarballs were never tampered with -- only the URL/integrity encoding was non-canonical. - No tsconfigs, source files, or peer ranges were changed; no package.json version pins were changed. TypeScript 6.0.3, typescript-eslint 8.64.0 family, and ts-jest 29.4.11 versions are preserved exactly as approved. Validated: - yarn install --frozen-lockfile succeeds (integrity checks pass against live tarball downloads). - yarn check:installed-dependencies-versions passes. - yarn check:change passes (no change file needed for a lockfile-only fix). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Task 3 of the TypeScript 6 migration: update the shared root tsconfig base configs and the generator that produces the merged config. - tsconfig.base.json (v9), tsconfig.base.v8.json, tsconfig.base.wc.json: replace deprecated `moduleResolution: node`/`Node` with `bundler` (these are bundled/transpiled library configs, not direct-Node runtimes), drop the deprecated `baseUrl`, and rewrite every `paths` target to be explicitly relative (`./...`) so aliases keep resolving identically now that TypeScript 6 resolves `paths` relative to the tsconfig file itself instead of `baseUrl`. - tools/workspace-plugin/src/generators/tsconfig-base-all: update the generator to emit `moduleResolution: bundler` and no `baseUrl` in the generated tsconfig.base.all.json, and regenerate that file. Added a regression test asserting the generated config has no `baseUrl`, no legacy Node/Classic module resolution, and keeps every path alias explicitly relative. - scripts/generators/src/create-package/plop-templates-node/tsconfig.json: newly generated direct-Node packages now use the modern paired `module`/`moduleResolution: NodeNext` setup (matching the existing @tsconfig/node20-based direct-Node packages in this repo) and no longer set `baseUrl`. Project-level package tsconfigs are intentionally left untouched here (Task 4). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Task 4 of the TypeScript 6 migration: audit and migrate every remaining
repository-owned project tsconfig, plus the build tooling that injects
deprecated compiler options into `tsc` invocations.
Classification & module resolution (73 configs)
- browser / package-library / bundler- or Jest-transformed / fixture /
declaration projects -> `moduleResolution: bundler` (valid with
`module: commonjs` in TS 6): all v8 packages and legacy apps, the 23
`scripts/*/tsconfig.spec.json` Jest configs, react-integration-tester
spec config, codemods mock projects, eslint-rules and build-executor
fixtures.
- code executed directly by modern Node -> paired `module: NodeNext` +
`moduleResolution: NodeNext`: `apps/ssr-tests` (mocha on Node 22) and
the two `ts-minbar-test-*` harnesses. The `scripts/*` packages already
inherit node16 resolution from `@tsconfig/node20`.
baseUrl removal (34 configs + 9 tooling call sites)
- Dropped every remaining `baseUrl`. All five affected configs that also
declare `paths` already used targets relative to their own tsconfig, so
alias resolution is unchanged under TS 6 `pathsBasePath` semantics.
- `--baseUrl <dir>` was also used by build tooling as a hack to "turn off
path aliases". TS 6 errors on it (TS5101) and it cannot be expressed via
CLI flags anymore, so a shared `createTsConfigWithoutPathAliases()`
helper now writes a transient `{"extends": <config>, "paths": null}`
config for the single `tsc` run and removes it afterwards. Applied to
the v9 `type-check`/`generate-api` executors, the v8 `ts`/`type-check`/
`generate-api` just-scripts tasks and the web-components
`type-check`/`compile`/`generate-ssr` scripts. Verified byte-identical
declaration output vs. the old `--baseUrl` hack. The API Extractor
override configs already set `paths: undefined`, so their redundant
`baseUrl: '.'` was simply removed. Also removed the four
`tsc -p . --baseUrl .` flags from app `type-check` scripts.
Explicit rootDir (62 configs)
- TS 6 no longer infers the common source directory for emitting projects
and errors with TS5011. Left unfixed, v8 packages and `scripts/*` would
emit to `<outDir>/src/**` instead of `<outDir>/**`. Added the reported
`rootDir: "./src"` which restores the pre-TS6 (and published) layout -
verified by building `set-version` and `keyboard-key`.
ES5 targets
- `apps/ssr-tests` (SSR) and `apps/perf-test` (performance app) move to
modern targets; ssr-tests simply inherits `@tsconfig/node20`'s ES2022
and is `noEmit`, so nothing is emitted differently.
- `react-portal-compat-context` still ships ES5 but downlevels through its
own `.swcrc` (`jsc.target: es5`), so type-checking at ES2015 changes no
published JS. Its `lib` stays ES5 so the source keeps to the ES5 API
surface.
- The remaining v8 packages/apps move from `target: es5` to `es2015`
(lowest modern target) because TS 6 hard-errors on ES5; `lib` arrays are
intentionally untouched so the type surface - and therefore the source -
is unchanged.
Other TS 6 deprecations
- `downlevelIteration` (api-docs), `esModuleInterop: false`
(chart-docsite) and redundant `DOM.Iterable` (web-components, vite
starter template) removed. `types: []` inheritance audited across all
732 configs - every config that relies on ambient globals already
declares them, so no `types` entries were added.
- The StackBlitz/CodeSandbox tsconfig generators now emit
`moduleResolution: bundler` and drop `DOM.Iterable`; snapshots updated.
Tooling compatibility (no Nx patching, no `ignoreDeprecations`)
- Added `@swc-node/register@1.9.2` (the version `@nx/js` itself installs)
as a root devDependency so Nx 21.6.10 stops falling back to ts-node,
whose hardcoded `moduleResolution: NodeJs` failed with TS5107 before any
repo target could run. `@swc-node/core` is pinned to `1.13.3` via
`resolutions` to keep its `@swc/core >= 1.4.13` peer satisfied by the
repo's `@swc/core@1.11.24`. Lockfile entries use canonical
registry.yarnpkg.com URLs with authentic sha512 integrity, cross-checked
against npm-signed registry metadata and recomputed from the tarballs.
- `patches/@swc-node+register+1.9.2.patch`: `@swc-node/register` maps
tsconfig `baseUrl` to `jsc.baseUrl` but ignores `pathsBasePath`, so SWC
panics on the now baseUrl-less workspace config whenever `paths` are
present. The patch implements TS 6 semantics (fall back to
`pathsBasePath`), matching what Nx 23 does upstream.
- `patches/just-task+1.5.0.patch`: `just-task` hardcodes
`moduleResolution: 'node'` when registering ts-node for `just.config.ts`,
which broke every v8 just-scripts target under TS 6.
- `tools/eslint-rules` `base-hook-no-forbidden-runtime` now falls back to
`ts.resolveModuleName` because TS 6 does not populate the program level
resolution cache under `moduleResolution: bundler`, which silently
disabled the rule.
Intentional exceptions (documented)
- `apps/ts-minbar-test-react/files/tsconfig.json` (`target: es5`) and
`apps/ts-minbar-test-react-components/files/tsconfig.json`
(`moduleResolution: node`) are consumer scaffolds compiled by
TypeScript 5.4 - the minimum version this repo supports for consumers -
inside a temp project, never by the repo compiler. Migrating them would
defeat the purpose of the minimum-bar test.
Validation
- `nx run-many -t test -p workspace-plugin,eslint-rules,eslint-plugin,
codemods,scripts-tasks,react-integration-tester,
react-storybook-addon-export-to-sandbox` - all green (241 + 85 + 85 +
35 + 10 + 37 + 50 tests).
- `nx run-many -t lint -p workspace-plugin,scripts-tasks,web-components,
chart-web-components` - green.
- `nx run keyboard-keys:type-check`, `nx run keyboard-keys:build`,
`nx run set-version:build`, `nx run keyboard-key:build` - green, with
the v8 output layout unchanged (`lib/index.js`, `lib-commonjs/index.js`).
- `packages/web-components` `type-check` and `apps/ssr-tests` type-check
run to completion with zero TS5xxx config diagnostics.
- Repo-wide program-level sweep of all 732 tsconfigs reports no
compiler-option diagnostics outside the two documented minbar fixtures.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ed tsc options Task 4 left the shared v8 build pipeline unbuildable under TypeScript 6: `scripts/tasks/src/ts.ts` still invoked `tsc` with `target: es5` + `module: amd` for `ts:amd`, which TS 6 rejects with TS5107 (both options removed) and - because v8 packages now use `moduleResolution: bundler` - additionally with TS5095. On top of that, moving the v8 tsconfigs from `target: es5` to `es2015` silently changed `lib`/`lib-commonjs` of every v8 package from the ES5 they have always published to ES2015, since no build stage downleveled them afterwards (`ts:postprocess` is a no-op and `babel:postprocess` only touches `*.styles.js` of packages with a `.babelrc.json` - `packages/tokens` is the only one). The published v8 artifact contract (ES5 `lib`, `lib-commonjs` and AMD `lib-amd` incl. declarations and source maps) is now preserved by moving the ES5/AMD emit out of the compiler, which is exactly the split the converged packages that ship AMD (`@fluentui/react-portal-compat*`) already use - `tsc` type checks and emits declarations + modern JS, SWC emits the legacy JS. No `ignoreDeprecations`, no TypeScript downgrade and no change to `moduleResolution: bundler`. Shared tasks - `scripts/tasks/src/swc/transpile.ts`: new `transpileEmittedJs()` which runs SWC over already emitted `.js` files - it downlevels to a given target and either keeps (`es6`/`commonjs`) or converts (`amd`) the module format. `tsc` source maps are chained via `inputSourceMap`, so the final `.map` still points at the original `.ts` (verified: `sources: ["<file>.ts"]`, `sourceRoot: "../src/"`, `sourcesContent`), and the `//# sourceMappingURL` comment is re-appended at the end of the file so it doesn't end up inside the AMD module factory. `.swcrc` lookup is disabled - the config is fully owned by this task - and helpers are inlined, because v8 packages ship `tslib` and SWC can only emit `@swc/helpers` imports, which would mean adding a runtime dependency to ~40 published packages. - `ts.downlevel` (`ts:downlevel`): downlevels `lib` and `lib-commonjs` in place to ES5. Runs for every package where `shipsAMD()` is true (all 42 projects built by the v8 preset), honours `--module` and skips module outputs that were not compiled. - `ts.amd` (`ts:amd`): builds `lib-amd` from the emitted ESM output and copies `**/*.d.ts` from `lib` (declarations are module format agnostic - the previous tsc AMD run emitted byte identical ones). Still followed by `postprocess:amd`, which keeps stripping `process.env` checks from the SWC output. Sequencing - `ts:compile` now only runs the compiler (`ts:commonjs`, `ts:esm`) and the new `ts:transpile` stage runs the post compilation transforms after `copy-compiled`, because that is what materializes `lib`/`lib-commonjs` for packages compiling into `dist/out-tsc` (`chart-utilities`). `ts:amd` keeps its previous condition (production, non converged). Tests (`nx run scripts-tasks:test` - 31 tests, was 10) - `swc/transpile.spec.ts`: module format preservation, AMD conversion, ES5 output asserted through the TS parser (no arrow/class/template/ let-const/destructuring nodes), source map chaining and the actionable error when there is no compiler output. - `ts.spec.ts`: `tscTask` is no longer configured with the removed `target: es5`/`module: amd`, downlevel/amd behaviour incl. declaration copying and `--module` handling. - `presets.spec.ts`: new preset sequencing suite (`ts`, `ts:compile`, `ts:transpile`, `ts:amd`, `build:react`) for production, non production, converged and `--module` variants. Verification - `nx run scripts-tasks:test` and `nx run scripts-tasks:lint` (0 errors) green; `tsc -p scripts/tasks/tsconfig.lib.json --noEmit` reports only the two pre-existing errors in `storybook.ts`/`webpack.ts`. - Production builds (`FLUENT_PROD_BUILD=1`) of `keyboard-key`, `dom-utilities`, `merge-styles`, `react-window-provider`, `theme`, `style-utilities`, `react-icon-provider`, `utilities` (166 files) and `react-icons-mdl2` (1744 files): every `lib`, `lib-commonjs` and `lib-amd` file is ES5 clean (TS parser sweep), keeps its module format (all `lib-amd` files are `define(...)` wrapped), ships declarations and chained source maps; `dist` bundles of the `ships-bundle`/`ships-umd` packages stay ES5. `lib-amd` + `lib-commonjs` of `keyboard-key` were additionally executed (AMD loader shim / `require`) and behave identically. - Non production builds keep skipping AMD, as before. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Follow up on the project-level TypeScript 6 migration, fixing the blocking and important quality findings of the Task 4 review. C1 - preserve the pre-TS6 published ECMAScript baseline - `ts:downlevel` was gated by `shipsAMD()`, which is unrelated to the ES5 baseline: it downleveled modern packages (`react-icons-mdl2(-branded)`, `react-icon-provider`, `chart-utilities`, `storybook`) while packages built via `build:node-lib` (`api-docs`, `jest-serializer-merge-styles`, `test-utilities`, `webpack-utilities`) and `monaco-editor` silently lost their ES5 emit. - Introduced the explicit `ships-es5` project tag (same mechanism as the existing `ships-amd`/`ships-bundle`/`ships-umd` tags) carried by the 36 projects whose tsconfig declared `target: es5` before the migration, and gate `ts:downlevel` on `metadata.shipsES5()` only. `build:node-lib` and the custom `monaco-editor` `ts` task run it as well. - `lib-amd` keeps its pre-TS6 shape: it was always emitted by a dedicated `tsc --target es5 --module amd` run which overrode the package target, so the SWC AMD transform stays on ES5 for every package which ships it - verified for `react-icons-mdl2` (ES2019 `lib`, ES5 `lib-amd`). C2 - verify the published artifacts, not only the file list - Extracted the AST syntax check into `scripts/tasks/src/ecma-syntax.ts` (`findSyntaxAboveTarget`, `detectModuleShape`), reused by the SWC specs and by `verify-packaging`. - `verify-packaging` now asserts, for `lib`/`lib-commonjs`/`lib-amd`: the expected ECMAScript baseline (`ships-es5` -> ES5, otherwise the resolved tsconfig target, `lib-amd` -> ES5), the module shape (ESM/CJS/AMD wrapping), declaration counterpart coverage, and `lib-amd` <-> `lib` parity. Whole-file-list checks are cheap; only an evenly spread sample of 40 files per folder is parsed to keep CI fast. I1 - stop inlining SWC helpers into every emitted file - `externalHelpers: true` for the downlevel/AMD transform; `@swc/helpers` is declared as a runtime dependency by all 36 affected published packages (with change files), which is the contract converged SWC compiled packages already ship. - `@swc/helpers` had to move from 0.5.1 to 0.5.23 (within the `^0.5.1` range every package already declares): 0.5.1 predates `_call_super`, which `@swc/core@1.11.24` emits for downleveled classes, so bundling `merge-styles` failed with an unresolved subpath export. - Measured on `@fluentui/utilities`: `lib` 565 -> 505 KB (281 -> 24 inlined helper definitions), `lib-commonjs` 644 -> 586 KB, `lib-amd` 730 -> 601 KB. I2 - restore the alias disabled type-check of apps - Added the `type-check-project` wrapper (`scripts/tasks/bin`), which runs `tsc` through the transient "no path aliases" config, and pointed `public-docsite`, `vr-tests`, `vr-tests-react-components` and `vr-tests-web-components` at it. Behavioural test included; verified that plain `tsc -p .` type checks workspace *sources* while the wrapper resolves to built declarations. I3 - Node executed jest/ts-jest configs - The 23 `scripts/*/tsconfig.spec.json` use paired `NodeNext` now (matching `@tsconfig/node20`), no new diagnostics. - `tools/react-integration-tester/tsconfig.spec.json` keeps `commonjs` + `bundler` (both valid and non deprecated in TS 6) because jest resolves the extensionless dynamic imports of its tests - documented in the config. - `scripts/ts-node/src/register.js` passed no compiler options, so ts-node fell back to `moduleResolution: node10` and TS 6 rejected it (TS5107), breaking `yarn start`/`yarn generate` and the `scripts-executors` tests. I4 - cache module resolution in the eslint rule fallback - `base-hook-no-forbidden-runtime` reuses one `ts.ModuleResolutionCache` per program instead of resolving every import from scratch. I5 - harden the transient tsconfig helpers (4 aligned implementations) - Unique file name per process/invocation, explicit cleanup in `scripts/tasks/src/ts.ts` (also on failure) instead of relying on the exit hook, one process listener per module (plus SIGINT/SIGTERM which re-raise), and an actionable error when the config to extend does not exist. I6 - idempotent, prunable SWC output - The transform keeps a content addressed manifest in the project's `node_modules/.cache`, so already transpiled output is never transpiled (nor its source maps re-chained) again, partial invocations only process what changed, and `lib-amd` is treated as a derived directory whose stale files (js/map/d.ts) are pruned. I7 - document/test the `esModuleInterop` behaviour change - `docs/architecture/v8-published-artifacts.md` documents the artifact contract, the new `@swc/helpers` dependency and the CJS/AMD interop change TS 6 forces (`esModuleInterop` defaults to true and cannot be turned off). - `scripts/tasks/src/swc/interop.spec.ts` executes the emitted AMD module in a minimal AMD loader and asserts the namespace/default interop shape and module identity. I8 - harden the `@swc-node/register` patch - Fails with an actionable message when `paths` are declared but neither `baseUrl` nor `pathsBasePath` is available, instead of silently resolving aliases against the cwd. Regression tests in `scripts/package-manager/src/patches.spec.ts`, and `patches/README.md` documents both patches and the `@swc-node/core` resolution pin. Also fixes two `rootDir` regressions from the previous commit (`font-icons-mdl2`, `react-file-type-icons` failed with TS5011). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
C1/I1 follow-up - fully close the "@swc/helpers" floor gap: - Bump every repository declaration of "@swc/helpers" from "^0.5.1"/"~0.5.1" to "^0.5.23" (132 package.json files across packages/, packages/react-components/, and tools/) so the declared lower bound actually includes the version that provides "_call_super" - the previous "^0.5.1" floor was technically still satisfied by a version that predates it, only the root devDependency pin (already "0.5.23") masked that in this workspace's hoisted install. Root package.json is intentionally left as its pre-existing exact "0.5.23" pin, which syncpack.config.js already exempts from the workspace-wide semver group. - Declare "@swc/helpers": "^0.5.23" as a runtime dependency on the 5 private ES5/AMD producers that emit external helper imports without declaring it: packages/storybook, packages/react-examples, apps/public-docsite-resources, apps/public-docsite and apps/theming-designer (all non-converged v8 packages built through the default `ts` pipeline, so they emit "lib-amd" in production and/or run the ES5 downlevel via their `ships-es5` tag). Audited every other `ships-es5`/`ships-amd` producer and every private v8 package's build task: `packages/codemods`, `packages/common-styles`, `apps/perf-test`, `apps/vr-tests`, `apps/ssr-tests` and `apps/rit-tests-v8` either never run the SWC downlevel/AMD transform (`build:node-lib` without the `ships-es5` tag) or are explicitly excluded from the production v8 build in `azure-pipelines.release.yml`, so they don't need the dependency. C2 follow-up - `verifyRuntimeHelpers` (scripts/tasks/src/verify-packaging.ts) now validates the package's *declared dependency range*, not only the hoisted copy that happens to be installed: - it still resolves every imported helper specifier against the installed copy (existing behaviour, unchanged), - it now also asserts the package declares "@swc/helpers" at all once a helper import is found, and - it computes the declared range's lower bound with `semver.minVersion` and asserts it is `>=` the version that was just verified to provide every imported helper - so a future regression of the range back to "^0.5.1" fails verification even though some other package in the workspace still pins a newer copy and keeps it physically resolved/hoisted. - Added 3 new scripts/tasks/src/verify-packaging.spec.ts cases (missing dependency declaration, range regression, accepted range) and extended `setup()` with a `dependencies` option. Manually verified against a real package (`@fluentui/utilities`, production build): passes as-is, fails with the added assertion message when its declared range is edited back to "^0.5.1", passes again once reverted. Sandbox scaffold - packages/react-components/react-storybook-addon-export-to-sandbox bumped the generated sandbox's "typescript" devDependency from "~4.7.0" to "~6.0.0": the scaffolded tsconfig already sets `moduleResolution: "bundler"`, which TypeScript 4.7 does not support. Updated the 5 inline snapshots in sandbox-scaffold.spec.ts to match. Dependency bookkeeping: - yarn.lock regenerated (`yarn install --offline`) for the range bump; fixed up the single re-resolved "@swc/helpers" entry back to the canonical "registry.yarnpkg.com" URL and authentic sha512 integrity (this sandbox's registry mirror re-resolves through an internal Azure DevOps feed with sha1 hashes, same issue fixed for other packages by 179179d) - cross-checked shasum/integrity against the r.cnpmjs.org registry mirror. - Added 88 beachball change files (87 for the "@swc/helpers" range bump on published react-components/v8 packages that don't already have a pending change file for this branch, plus 1 for the sandbox scaffold TypeScript bump); the 36 packages already covered by an existing pending "add @swc/helpers" change file were left alone to avoid duplicates. The 5 producers that gained the dependency for the first time are all private, so beachball does not require a change file for them. - `yarn syncpack list-mismatches`, `yarn check:installed-dependencies-versions` and `yarn install --frozen-lockfile` all pass. Verified: `nx run scripts-tasks:test`, `nx run scripts-tasks:lint`, `nx run react-storybook-addon-export-to-sandbox:test` all pass; `yarn check:change` passes for every package touched by this commit (the pre-existing `@fluentui/chart-web-components`/`@fluentui/codemods`/ `@fluentui/web-components` gaps predate this change and are unrelated Task 5 work, left untouched per scope). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- @fluentui/codemods: @swc/helpers dependency - @fluentui/chart-web-components: @swc/helpers dependency - @fluentui/web-components: @swc/helpers dependency Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Private packages (@fluentui/eslint-plugin, @fluentui/theme-designer) should not have change files.
…nges Packages with disallowedChangeTypes [major, minor, patch] must use 'none' or 'prerelease' change types. Updated the following packages: - @fluentui/tokens - @fluentui/react-theme-sass - @fluentui/babel-preset-global-context - @fluentui/global-context - @fluentui/react-alert - @fluentui/react-infobutton - @fluentui/react-virtualizer This allows yarn check:change to pass without errors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add the ambient find-free-port declaration to scripts/tasks/tsconfig.spec.json (mirroring tsconfig.lib.json) so tsc -p scripts/tasks/tsconfig.spec.json --noEmit no longer reports TS7016 for presets.spec.ts's transitive import of webpack.ts. - Fix verifyRuntimeHelpers in verify-packaging.ts: use semver.satisfies(resolvedVersion, declaredRange) instead of requiring the declared range's floor to be >= the resolved version, so a correctly-widening range like ^0.5.1 is accepted when the resolved helper is 0.5.23, while a range that truly excludes the resolved version (eg ^0.4.0) is still caught. Updates error text and tests accordingly so future compatible @swc/helpers bumps don't break every package. - Correct patches/README.md and the @swc-node/register patch comments: @swc-node/register is only an optional peer dependency of nx, not something @nx/js installs. This branch adds it directly to devDependencies to make Nx pick SWC transpile-only execution over its TS6-incompatible ts-node fallback. The removal criterion is now actionable: bump/remove the pin and patch once an unpatched @swc-node/register release maps pathsBasePath upstream. - Fix the import-order lint warning in scripts/tasks/src/swc/transpile.spec.ts (parent vs sibling import groups need a blank line between them). - Robustness: make withCleanup recognize any thenable, not just native Promise; make the type-check-project CLI reject -p/--project without a value instead of silently falling back to the default project; add direct test coverage (incl. node --check) for scripts/tasks/bin/type-check-project.js. Verified: scripts-tasks test/lint/type-check (TS7016 gone; only the pre-existing unrelated storybook.ts TS2578 and deferred Task 5 eslint-plugin-react-components API Extractor failures remain), scripts-package-manager test/lint, workspace-plugin test/lint (244 tests, 37 suites). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…essions
Compiler and DOM/lib regressions:
- pin `strict: false` in the v8/legacy tsconfig family: TypeScript 6 flipped the
`strict` default to `true`, which silently turned on `strictFunctionTypes`,
`strictPropertyInitialization` and friends for maintenance-only v8 packages
(`@fluentui/react` alone reported 400 new errors). The configs already opted
into `strictNullChecks`/`noImplicitAny` explicitly, so the previous contract is
now written down instead of inherited from a compiler default.
- drop the obsolete `@ts-expect-error` directives around `style.anchorName` /
`style.positionAnchor` in web-components `tooltip`; TypeScript 6 ships those
properties in `lib.dom.d.ts`.
- add `overallProgress` to the react-motion-components-preview `Animation` mock,
which the updated DOM lib now requires.
- keep the deprecated `document.createEvent` fallback in `@fluentui/utilities`
`EventGroup.raise`, which the updated DOM lib now flags, behind the same
targeted `@typescript-eslint/no-deprecated` suppression the adjacent
`initEvent` call already uses.
- type the `date-time-utilities` `toLocaleTimeString` mock with
`Intl.LocalesArgument` instead of `string | string[]`.
- make the `getMetadata` `_options` parameter in `scripts/storybook` optional -
TypeScript 6 no longer treats an inline JSDoc-typed trailing parameter as
optional.
- remove the now unused `@ts-expect-error` on the `storybook/internal/core-server`
import in `scripts/tasks`.
- declare `*.css` in `typings/static-assets` and request the `static-assets`
ambient types in the web-components/chart-web-components storybook configs, so
side-effect stylesheet imports resolve under `noUncheckedSideEffectImports`.
- resolve `markdown-to-jsx` types through its `import` condition in
react-docsite-components; its `require` declarations omit `MarkdownToJSX`.
- make `useDebounce` generic in public-docsite-v9 and drop the now provably dead
`platform === 'web'` comparison in the public-docsite template page, which
TypeScript 6 narrows out of the `default` switch branch.
- import `SlotClassNames`/`JSXElement`/`TagAppearance`/`TagSize` from the
`@fluentui/react-utilities` and `@fluentui/react-tags` package entries instead
of their internal `/src/index` paths, which modern module resolution rejects.
- replace the remaining `React.RefAttributes` usages in react-charts and
react-calendar-compat with `RefAttributes` from `@fluentui/react-utilities`,
which typescript-eslint 8.64 now reports through the workspace rule.
Declaration/API Extractor regressions:
- API Extractor 7.51.0 classifies relative `import('./module')` types in
declaration output as external packages whenever a modern `moduleResolution`
is used, which produced `.d.ts` rollups importing unpublished modules
(react-breadcrumb, react-field, react-overflow,
react-headless-components-preview) and failed `react-components:build`.
The affected exports are now annotated with statically imported types.
- `@fluentui/eslint-plugin-react-components` exports `RuleOptions` from the entry
point and gives the flat config `plugins` map an explicit index signature, so
TypeScript 6 stops emitting an unusable `[name]` computed key plus a dangling
`../package.json` import.
- guard the regression class: `api-extractor` now fails the build when a rollup
contains relative imports, covered by `scripts/tasks/src/api-extractor.spec.ts`.
Test/transform regressions:
- resolve `compilerOptions.paths` in the SSR esbuild plugin through TypeScript's
`pathsBasePath` instead of the removed `baseUrl`; 61 of 67 `test-ssr` targets
were failing to bundle.
- request `types: ["node"]` in the tool tsconfigs that ts-node uses to load
`jest.config.ts`, since TypeScript 6 defaults `types` to `[]`.
- spy on the underlying CommonJS `react` module in `foundation-legacy` slots
tests: TypeScript 6 forces `esModuleInterop`, so the namespace object is now
built from non-configurable accessors.
- hoist `tickValues` above its use in the react-charting LineChart RTL tests; the
previous ES5 output hoisted the binding as `var`, which hid the temporal dead
zone violation.
- exclude the lint-only `@fluentui/eslint-plugin` edge from the three
`@nx/js:swc` tool builds, matching `workspace-plugin`. Nx rewrites dependency
path mappings to workspace-relative paths, which TypeScript 6 rejects without
`baseUrl`.
API reports are updated for the intentional declaration changes only: canonical
`@typescript-eslint/utils/ts-eslint` import paths, the `RuleModule & { name }`
intersection from typescript-eslint 8.64, the preserved
`<Value = AccordionItemValue>` generic default, the alias-preserving provider and
forward-ref annotations, and the `RefAttributes` swap.
…parsing
Declaration rollup guard:
- move the self contained `.d.ts` rollup guard into a dedicated `dts-rollup`
module and wire it into `tools/workspace-plugin/src/executors/generate-api`,
which is the path all 93 vNext packages use. The guard previously only ran on
the legacy `just-scripts` task, so the regression class it was added for was
unguarded for v9.
- the executor now checks every rollup variant api-extractor emitted
(untrimmed + public/beta/alpha trimmed) after each `Extractor.invoke`,
including the programmatic configs produced by `createSubpathEntryConfig` for
export subpath entries. A `Set` of already scanned paths is threaded through a
single run so a rollup emitted by more than one entry point config is parsed
only once.
- the guard runs after the actionable api-extractor diagnostics are surfaced, in
both the executor and the legacy task, so a broken rollup can no longer mask
the api-extractor error output.
- replace the line based regular expression with TypeScript AST scanning. Import
declarations, export declarations, `import x = require()` and `ImportTypeNode`
(inline `import('./types').Foo`, exported or not, anywhere in a declaration)
are all detected, while string literal *types* such as `'.2f'`, `'.'` or
`'../not-an-import'` are no longer false positives.
- `tools/workspace-plugin` must not depend on any project in the monorepo
(`scripts/check-dep-graph.js`), so the module is duplicated byte identical in
`scripts/tasks/src/dts-rollup.ts`; the spec next to each copy contains the same
test matrix plus a parity assertion that fails if the two ever diverge.
SSR tsconfig parsing:
- `tsConfigPathsPlugin` now inspects `parsedConfig.errors` and fails with
`ts.formatDiagnostics` output before any path alias is used. Previously an
invalid `extends` or an unknown compiler option produced an empty `paths` map
and the bundle silently fell back to `node_modules` resolution.
- resolve mappings against `baseUrl ?? pathsBasePath`, mirroring TypeScript's own
`getPathsBasePath`, and fail with an actionable message when neither is
available instead of guessing the config directory.
- add `esbuild-plugin.test.ts` with a fixture that mirrors the repository
topology (child config extending a base config that declares `paths`, no
`baseUrl`, alias target outside the child config directory) plus
invalid-extends and invalid-option cases proving parse errors throw.
Cleanups:
- drop the unused root `tsconfig-paths` dependency - the SSR plugin was its only
consumer and now uses the TypeScript API; `tsconfig-paths-webpack-plugin` keeps
it as a transitive dependency.
- use type only imports for `ApiExtractorOptions`/`TaskFunction` in
`scripts/tasks/src/api-extractor.ts`.
- explain why `Overflow`/`Provider` keep their inferred
`ForwardRefExoticComponent` shape instead of `ForwardRefComponent`.
- drop the stale "classNames that may be falsey" note in the public-docsite
template page, which no longer passes a falsey argument to `css()`.
`tools/visual-regression-utilities` intentionally does not get the
`!eslint-plugin` implicit dependency exclusion: unlike the three tools that did,
it has no `@nx/js:swc` build target, so the lint only edge never reaches the
dependency path mapping rewrite that motivated the exclusion.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- api-extractor.ts (scripts/tasks): only run the self contained dts rollup guard when API Extractor succeeded, matching the vNext generate-api executor so API Extractor diagnostics are never masked. Add api-extractor.spec.ts covering onResult wiring for the succeeded/failed ordering. - dts-rollup.ts (both parity copies): expand the rollup guard to also flag absolute filesystem module specifiers and triple-slash 'reference path' directives, while still ignoring package specifiers, node: builtins, URLs, and harmless string literal types. Update the parity spec accordingly. - Move dts-rollup.spec.ts and esbuild-plugin.test.ts fixtures from source-tree __fixtures__ directories to os.tmpdir(), with cleanup in afterEach so interrupted runs cannot leave files behind. - typings/static-assets/index.d.ts: give 'declare module *.css' an explicit empty body so side-effect imports still resolve but value/default/named imports no longer silently become any. Add a focused behavioural test (static-assets-css.spec.ts) that fails against the old shorthand declaration. - react-docsite-components/tsconfig.json: replace the workspace-wide customConditions: ["import"] override with a narrowly scoped 'paths' mapping that only redirects markdown-to-jsx's type resolution to its import-condition declaration file (which declares the MarkdownToJSX namespace), instead of flipping export conditions for every dependency. - Make the dts-rollup parity check cache-safe: scripts-tasks and workspace-plugin project.json now declare the other project's dts-rollup.ts/.spec.ts as explicit test target inputs, so changing either copy busts the other project's test cache. Verified with a content-change probe. - esbuild-plugin.ts (scripts/test-ssr): filter parsedConfig.errors to Error category diagnostics only, since TypeScript can also return Warning/Suggestion category diagnostics in that array. Added tests covering both the non-error and still-fails-on-real-error cases. Validated: scripts-tasks test/lint/type-check, workspace-plugin generate-api/executor tests and full test suite, scripts-test-ssr test/lint/type-check, react-docsite-components type-check/test/lint, react-button generate-api (clean diff), react-charting build (legacy api-extractor task), and 'yarn check:change' (no beachball change files required - all touched packages are private except react-docsite-components, whose tsconfig change is build-tooling only and does not alter emitted declarations). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The repo toolchain now builds and tests on TypeScript 6.0.3, but the published peer ranges of the tooling packages still described a TypeScript 4-only (or unbounded) world: - `@fluentui/react-conformance` and `@fluentui/react-conformance-griffel` declared `typescript: ^4.3.0`, which excludes every release after 4.9 - consumers on TS 5.x/6.x got an unmet peer warning even though the packages work. - `@fluentui/eslint-plugin-react-components` declared `typescript: >= 5.0.0` with no upper bound, so it also advertised the unreleased TypeScript 7 compiler. - `@fluentui/eslint-plugin` (private) declared `typescript: ^5.0.0`, which the repo's own TypeScript 6.0.3 install no longer satisfies. Ranges are widened, not replaced: the conformance packages keep their 4.3 floor (inherited from `react-docgen-typescript`'s own `>= 4.3.x` peer) and now read `>=4.3.0 <7.0.0`; the ESLint plugins read `>=5.0.0 <7.0.0`. Verified by type-checking each package's published `dist/index.d.ts` through a consumer-style program on TypeScript 4.9.5, 5.4.5, 5.7.3, 5.9.3 and 6.0.3 (with version-matched `typescript` declarations), and by running the `@fluentui/react-conformance` jest suite - which drives the compiler API at runtime - against each of those versions. The compiler APIs used (`createProgram`, `createCompilerHost`, `findConfigFile`, `parseJsonConfigFileContent`, `SyntaxKind`, node type guards) predate the declared 4.3 floor and still exist in 6.0.3. The `typescript-eslint: >= 8.46.2` peer is intentionally left alone: typescript-eslint 8.46.2 itself declares `typescript: >=4.8.4 <6.0.0`, so the TS6 + tseslint 8.46.2 combination is already excluded by composition and raising our floor would only break working TS5 consumers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…sions Resolves the six failures found during final TypeScript 6 validation. F1 - `NX_PREFER_TS_NODE: true` forced Nx onto its `ts-node` fallback, which hardcodes `moduleResolution: node10` and therefore fails with TS5107 under TypeScript 6. Removed from all seven GitHub workflows and from `.devops/templates/variables.yml` so Nx uses the `@swc-node/register` path this branch installs and tests. F2/F4 - `@swc-node/register@1.9.2` falls back to the pre TypeScript 6 default of `esModuleInterop: false` when the option is not spelled out, so every `import x from '<commonjs module>'` inside the workspace TypeScript Nx executes resolved to `undefined` (`path`, `semver`, `micromatch`). `tsconfig.base.json` now declares `"esModuleInterop": true` explicitly, which is a no-op for the compiler (it is the TypeScript 6 default) and restores the interop wrappers for generators, executors and `verify-packaging`. F3 - `apps/ts-minbar-test-react*/tsconfig.json` got an explicit `rootDir` of `./src`, which the NodeNext migration made mandatory (TS5011). F5 - `packages/react-examples/tsconfig.rit.json` sets `resolvePackageJsonExports: false`, so the compatibility test keeps seeing the built deep subpaths of `@fluentui/react-experiments` under `bundler` resolution without broadening that package's public `exports`. F6 - Cypress loads its config in a child process with its own bundled `ts-node` pinned to node10, so no TypeScript file reachable from a `cypress.config.*` can be compiled under TypeScript 6. The whole Node side is now CommonJS JavaScript with `// @ts-check`: all 38 configs, the shared `@fluentui/scripts-cypress` entry point and the RIT/generator templates. Path aliases are handed to the bundler explicitly through the compiler reported `pathsBasePath` (`scripts/cypress/src/ts-paths.js`) instead of the removed `baseUrl`. The RIT generated tsconfig lost its `baseUrl` (TS5101) and defaults to `bundler` resolution (TS5107) for the same reason. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…TS6 migration - ts-paths.js: pass tsConfigPath as configFileName to parseJsonConfigFileContent so pathsBasePath is computed correctly through extends chains. Inspect and throw formatted Error-category diagnostics from parseJsonConfigFileContent instead of silently ignoring invalid extends targets/compiler options. - Add ts-paths.test.js covering inherited paths with no baseUrl and parse errors (missing extends target, unknown/invalid compiler options, unreadable config, and Warning/Suggestion vs Error diagnostic filtering), analogous to the test-ssr esbuild-plugin helper tests. - Route the new .test.js file through the Jest-typed tsconfig.spec.json project and exclude src/index.d.ts from it (its ambient Cypress globals collide with @types/jest globals); exclude .test.js/.spec.js from tsconfig.lib.json. - Add explicit BaseConfig JSDoc annotation (from @fluentui/scripts-cypress) to packages/react-examples/cypress.config.js and the react-integration-tester cypress.config.js.template so @ts-check no longer reports a duplicate component identifier when spreading baseConfig. Update the RIT e2e inline snapshot to match. - Remove the stale ./cypress.config.ts entry from eslint-plugin's configHelpers.js configFiles list (redundant with the existing ./*.js glob, and cypress.config.js is JS-only per docs/workflows/testing.md). - Correct comments/docs that falsely claimed tsconfig-paths@4.2 skips configs without baseUrl; it only skips when no tsconfig/jsconfig is found at all, and otherwise anchors paths at the nearest config file rather than the one declaring them. Explain the real reason ts-paths.js uses TypeScript's own parser and pathsBasePath: to keep inherited paths mapping roots correct through extends chains under TS6 baseUrl deprecation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e, RIT alias fix, POSIX paths 1. scripts/cypress/src/ts-paths.js: parse tsconfig with a restricted ParseConfigHost (readDirectory -> []) instead of ts.sys, so resolving the workspace path-alias base directory no longer enumerates the entire monorepo (~710ms -> ~1.3ms). Filters the resulting TS18003 "no inputs found" diagnostic, which is an expected artifact of the stubbed readDirectory rather than a real config error. Removed the unused "paths" field from WorkspacePathAliases (no caller consumed it) and updated JSDoc/tests accordingly, including a new regression test asserting no real filesystem walk occurs. 2. scripts/cypress/src/index.d.ts is now the single source of truth for BaseConfig; base.config.js's duplicate @typedef is replaced with an import of it from ./index. 3. registerTsPaths (scripts/storybook/src/utils.js) now accepts an optional explicit baseUrl, threaded to TsconfigPathsPlugin, so paths declared in an extended base tsconfig (pathsBasePath-relative under TS6) aren't silently anchored at the wrong directory. Backward compatible for all other callers. apps/rit-tests-v8/cypress.config.js now computes and passes that baseUrl via the newly exported readWorkspacePathAliases (re-exported from @fluentui/scripts-cypress's public entry). Added tests for registerTsPaths and the new public export. 4. tools/react-integration-tester/src/setup.ts: added toPosixPath() and applied it to every relative-path template value embedded in generated tsconfig/RIT project files, so Windows-style backslashes don't corrupt generated JSON/JS module specifiers. Updated setup.test.ts with unit tests and a Windows-path integration test. 5. Added an inline comment in packages/react-examples/tsconfig.rit.json explaining why resolvePackageJsonExports:false is required to keep @fluentui/react-experiments/lib/* deep-import compatibility tests working. Validated: scripts-cypress test/type-check/lint, scripts-storybook test/type-check/lint, react-integration-tester test/type-check/lint, rit-tests-v8 cypress.config.js runtime load (TsconfigPathsPlugin.baseUrl now resolves to the workspace root), and manual checkJs across base.config.js, packages/react-examples/cypress.config.js, and apps/rit-tests-v8/cypress.config.js. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.
Summary
Upgrades the Fluent UI monorepo to TypeScript 6.0.3 and completes the migration tracked by microsoft#36409.
ignoreDeprecationsFork validation
This PR intentionally targets
mainframev/fluentui:masterbefore an upstream PR. The fork's CI, package/tooling checks, React-version integration, E2E, VRT screenshot generation, PR website build, and bundle-size build workflows are enabled formainframevand tuned for four-core Ubuntu runners.Azure-dependent VRT comparison and website deployment remain upstream-only because fork credentials are unavailable. Bundle-size builds still run; an inaccessible upstream baseline is reported as a warning in the fork rather than masking build failures.
Validation completed locally
Notes
scripts-executors:testinteractive hang reproduces on bothmasterand this branch.TypeScript benchmark comparison
Fork baseline: #32 (TypeScript 5.7.3, same base commit and Ubuntu benchmark job).
Compare the
TypeScript benchmark / type-checkjob between both PRs. The job runs all 225 type-check targets uncached with Node 22 and four-way Nx parallelism. Preliminary local results were 376s for TypeScript 5.7.3 and 368s for TypeScript 6.0.3 (8s / 2.1% faster).