Repository navigation
fix(check): compile with the repository's own TypeScript, bundled only as fallback - #48
Merged
Merged
Conversation
…y as fallback Signal B now judges a repository with the TypeScript it installs (node_modules/typescript in the workspace or the nearest ancestor, the resolution fix's verification has used since #40), and falls back to ts-morph's bundled compiler only when the repository installs none. The errors and their positions are the ones the repository's own tsc prints: a repository on TypeScript 4.9 was judged by TypeScript 6's rules and error locations before. - compiler.ts holds the resolver (moved from fix/verify.ts) plus repositoryCompiler, loaded once per install directory, and describeCompiler for the coverage line. - With the repository's compiler, a baseline program is built once per workspace from the ts-morph program's root files and the options that compiler reads from the tsconfig, with the same workspace-source paths; the overlay shares that baseline. With the bundled one the ts-morph program stays the baseline, as before. - The host's resolver is installed both ways compilers ask: resolveModuleNameLiterals (TypeScript 5+) and resolveModuleNames (TypeScript 4). - The cause tracers take the compiler with the programs, so node kinds and flags are the judging compiler's. - Coverage records the compilers (CompileCoverage.compilers), merged across workspaces, and the coverage line says which judged: "compiled 11 of 11 files in 2 workspaces with the repo's TypeScript 5.9.3" or "with the bundled TypeScript 6.0.2". Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018u9b3Pp5H68DdYZGp5Qg1U Signed-off-by: Lucas Braum <lucas.braum@deskfy.io>
…ne above it excalidraw-app has no tsconfig.json; the root's `include` covers it. Loaded as a workspace it got synthetic options, which the bundled compiler's defaults papered over (esModuleInterop, JSX) and the repository's TypeScript 4.9 did not: every default import and every JSX element in that workspace errored at the target. Both the ts-morph program and the native baseline now read the nearest ancestor tsconfig's options (never its file list) when the workspace has none; only a repository with no tsconfig anywhere gets synthetic defaults, with the bundled compiler's modern defaults made explicit for older compilers. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018u9b3Pp5H68DdYZGp5Qg1U Signed-off-by: Lucas Braum <lucas.braum@deskfy.io>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018u9b3Pp5H68DdYZGp5Qg1U Signed-off-by: Lucas Braum <lucas.braum@deskfy.io>
…script, nothing else runs SECURITY.md, CONTRIBUTING.md's rules, the README privacy section and the CLI's privacy statement (the same text in --help) now say that check and verify load the typescript package the repository installs, resolved from its node_modules, to compile with, and that neither runs the repository's scripts or other code outside fix's verification step. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018u9b3Pp5H68DdYZGp5Qg1U Signed-off-by: Lucas Braum <lucas.braum@deskfy.io>
Merged
lucasbraum
pushed a commit
that referenced
this pull request
Oct 8, 2026
…reaking precision 96%, 4 false positives) The four breaking false positives left are engine or ground-truth-environment issues, not rules: dev-docs/Homepage (a workspace whose tsconfig extends a package that is not installed), two useTransform(ref) call sites in other workspaces than the declaration that is the one cause, and next-mdx-remote-client/rsc after a companion move the real upgrade never made. The pack stays a candidate. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AKRx4kuV6oi25MP5WguxW9 Signed-off-by: Claude <noreply@anthropic.com>
6 of 8 tasks
lucasbraum
pushed a commit
that referenced
this pull request
Oct 9, 2026
…reaking precision 96%, 4 false positives) The four breaking false positives left are engine or ground-truth-environment issues, not rules: dev-docs/Homepage (a workspace whose tsconfig extends a package that is not installed), two useTransform(ref) call sites in other workspaces than the declaration that is the one cause, and next-mdx-remote-client/rsc after a companion move the real upgrade never made. The pack stays a candidate. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AKRx4kuV6oi25MP5WguxW9 Signed-off-by: Claude <noreply@anthropic.com>
lucasbraum
pushed a commit
that referenced
this pull request
Oct 9, 2026
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and publish to npm yourself or [setup this action to publish automatically](https://github.com/changesets/action#with-publishing). If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## uptide@0.6.0 ### Minor Changes - [#46](#46) [`458aa14`](458aa14) Thanks [@lucasbraum](https://github.com/lucasbraum)! - What changed in `check`: - **Breaking means confirmed.** A type-surface change is reported as breaking only when the compiler rejects your code against the target at that site, the runtime probe saw the export go, or a migration pack found it, in the verified tier as in the generic one. What nothing confirmed is listed as "possible impact", apart from the breaking count. - **Coverage, under every package.** `compiled 355 of 356 files in 5 workspaces; skipped: <reason (count)>` says how much of the code that uses the package the compiler judged, and the verdict says "types partly verified" when not every file was. - **TypeScript-version-aware defaults.** A repository on TypeScript 5 is read with TypeScript 5's defaults for what its tsconfig leaves unset (`strict` off, automatic `@types`), not the bundled TypeScript 6's. Monorepos compile far more of their files: workspace packages declared `workspace:*` under Yarn and npm resolve to their source, scoped programs keep the tsconfig's ambient declaration files, and a workspace that only peer-depends on a package finds the hoisted copy. - **Companions.** `check` and `fix` move `@types/<pkg>` with `<pkg>`, and a package released in lockstep with it (react-dom with react): `check react` 18 → 19 moves react-dom, @types/react and @types/react-dom together. - **One finding for a root cause that is one edit.** A compiler option (the global `JSX` namespace `@types/react` 19 removes, read by `"jsx": "preserve"`) and a repository parameter several call sites trip are each one finding at the place to edit, with the compiler errors as evidence. - [#51](#51) [`a18bebd`](a18bebd) Thanks [@lucasbraum](https://github.com/lucasbraum)! - `check` reports one breaking finding when call sites in different workspaces trace back to the same local declaration (a parameter or prop whose type names something from the upgraded package): the finding is anchored at the declaration, where the one edit is, and the call sites are listed under it as evidence with an `N call sites in M workspaces` line, in the terminal, the HTML report and the JSON report. Before, a site alone in its workspace stayed a finding of its own, so a hook typed `RefObject<HTMLElement>` and called from three workspaces was three findings plus the one that mattered. The JSON report gains `root` on call-site findings and `workspace` on evidence sites; nothing is renamed or removed. The pack test scorer counts the anchor as the predicted site and never the evidence under it. - [#49](#49) [`2e5c510`](2e5c510) Thanks [@lucasbraum](https://github.com/lucasbraum)! - Two fixes to `check`: - **A project whose tsconfig cannot be resolved is not compiled.** A tsconfig that `extends` a package or file that is not installed describes options the repository never builds with, so what a compiler reports there is not a place to change. `check` skips it, never turns its diagnostics into findings, and says so in the coverage line (a file governed by such a nested project is dropped from the workspace that happens to reach it): `compiled 5 of 7 files in 2 workspaces; not compiled: docs/tsconfig.json (extends "@tsconfig/docusaurus/tsconfig.json" cannot be resolved)`. - **A package that only peers on the package is left in place when its peer range rejects the target.** What always moves with the package stays as before: the release group published at the target's own version (`react-dom`), `@types/*`, the exact pins of the target, and the packages a pack names in `companions` (each with the official page that says so), even when their installed range already accepts the target. Any other package whose installed peer range rejects the target is not moved and not compiled at another version; `check` lists it under possible impact, never as breaking: `? possible impact, peer conflict: next-mdx-remote-client 1.1.2 declares react >= 18.3.0 < 19.0.0`. - [#53](#53) [`d33bdd0`](d33bdd0) Thanks [@lucasbraum](https://github.com/lucasbraum)! - A verified migration pack for React 18 → 19, scored against excalidraw/excalidraw and tldraw/tldraw at the commit before their own upgrade. Rewrites by rule: `useRef<T>()` → `useRef<T>(undefined)`, `ref={(el) => (x = el)}` → a block body, and `React.MutableRefObject` → `React.RefObject`. `RefObject<T | null>`, the removed global `JSX` namespace, untyped `element.props`, the removed react-dom APIs and `PropsWithRef` go to the agent with the guide; what the compiler cannot see (errors no longer re-thrown, removed legacy APIs, `act` moved to "react", Strict Mode and Suspense changes) is listed for review. 2 public repositories, 100% precision on breaking findings (89 sites, none false), recall 69% on breaking sites; the sites it misses are listed in the pack test output. ### Patch Changes - [#48](#48) [`94611a9`](94611a9) Thanks [@lucasbraum](https://github.com/lucasbraum)! - `check` compiles your code with the repository's own TypeScript (the `node_modules/typescript` its build uses, found the way `fix` has found it since verification), and falls back to the bundled compiler only when the repository installs none. Errors and their positions are the ones your `tsc` would print: a repository on TypeScript 4.9 is no longer judged by TypeScript 6's rules. The coverage line says which compiler judged: `compiled 355 of 356 files in 5 workspaces with the repo's TypeScript 4.9.5`. A workspace without a tsconfig of its own is now configured by the nearest one above it (a monorepo root whose `include` covers the workspace), for its options only; synthetic defaults apply only when no tsconfig exists anywhere. Co-authored-by: uptide-release[bot] <338861287+uptide-release[bot]@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.
What and why
check's compile signal judged every repository with the TypeScript ts-morph bundles (6.0.2), whatever the repository installs. A repository on TypeScript 4.9 was read by TypeScript 6's rules and its error positions: a JSX child "not assignable to ReactNode" sits on the element's first line in 4.9 and on the child in 6, which alone accounted for 7 of the react pack's 11 remaining false positives in excalidraw.checknow compiles with the repository's own TypeScript, found the wayfix's verification has found it since #40 (node_modules/typescriptin the workspace or the nearest ancestor, neverNODE_PATHor a global folder), and falls back to the bundled compiler only when the repository installs none. The coverage line says which one judged:How:
adapters/typescript/compiler.tsholds the resolver (moved fromfix/verify.ts, same behavior, same tests) plusrepositoryCompiler(loaded once per install directory) anddescribeCompiler.paths; the overlay shares that baseline. With the bundled compiler the ts-morph program stays the baseline, as before. Signal A (usages) still runs on ts-morph.resolveModuleNameLiterals(TypeScript 5+) andresolveModuleNames(TypeScript 4).CompileCoverage.compilersrecords which compiler judged, merged across workspaces (one entry per distinct version);coverageLineprints it.include) got synthetic options. The bundled compiler's defaults papered over that (esModuleInterop, JSX); TypeScript 4.9 did not, and every default import and JSX element in that workspace errored at the target. Both programs now read the nearest ancestor tsconfig's options (never its file list) when the workspace has none. This also lifted excalidraw's coverage from 355 of 356 to 358 of 358 (thewith-script-in-browserexample resolves its imports now).--helpprivacy statement (kept word for word with the README) now say thatcheckandverifyload thetypescriptpackage the repository installs, resolved from itsnode_modules, to compile with, and never run the repository's scripts or other code outsidefix's verification step.Cost: a repository with its own TypeScript is parsed twice (ts-morph for Signal A, its compiler for Signal B). The react pack test went from about 12 to 9 minutes anyway, since the baseline is built once per workspace and shared.
How it was verified
New tests:
fix/compiler.test.ts(compiler naming, bundled fallback, one load per install directory),check/verdict.test.ts(coverage line with one, several and mixed compilers),check/check.test.ts(compilers merged across workspaces),adapters/typescript/compile.test.ts(coverage names this repository's own TypeScript 5.9.3, which the fixture finds above it),adapters/typescript/repo-inherited.test.ts(inherited tsconfig options, own file list).config-cause.test.tspasses the compiler. The whole suite runs the overlay through the native path, since the fixtures sit under this repository's TypeScript.pnpm lint && pnpm typecheck && pnpm testpass (core 900 tests, cli 346).Storefront (
fixtures/repos/storefront, built CLI): findings, counts and verdicts identical to main; only the coverage lines changed, tocompiled 11 of 11 files in 2 workspaces with the repo's TypeScript 5.9.3andcompiled 7 of 7 files in 1 workspace with the repo's TypeScript 5.9.3. README sample updated accordingly.Pack tests, before (main, same commit as #46's final numbers) and after, breaking findings:
react per repo: excalidraw 9 FP → 2 (predicted 61, expected 73), tldraw unchanged at 9 FP / 26 FN. The 6 "TS 6 vs 4.9 location" false positives in
packages/excalidraware gone, as is thewith-script-in-browserone. The 4 remaining breaking false positives:dev-docs/.../Homepage/index.tsx:52(TS2322 at a JSX child in a workspace on the root's 4.9, same shape as before),tldraw apps/docs/components/content/index.tsx:18(next-mdx-remote-client/rscafter the companion move), and the twouseTransform(rSvg)single-site-per-workspaceref-object-nullablefindings. The other 7 of the 11 are deprecated or unverified, never counted as breaking. These go to #45.Checklist
pnpm lint && pnpm typecheck && pnpm testpasspnpm changeset)🤖 Generated with Claude Code
https://claude.ai/code/session_018u9b3Pp5H68DdYZGp5Qg1U