Systematically fix typechecking - #332
Merged
Merged
Conversation
Package-level reference graph from workspace deps and devDeps, with tsconfig entry resolution and a generate preview stub (--write no-op). Pathclerk cycle inventory (resolve before phase 5 CI gate): 1. @pathclerk/daemon-clients-common -> @pathclerk/daemon-sdk -> ... 2. @saflib/env -> @saflib/commander -> @saflib/node -> ... 3. @saflib/express -> @saflib/ory-kratos -> ... 4. @saflib/sdk -> @saflib/vue -> @saflib/ory-kratos-sdk -> ... 5. @saflib/sdk -> @saflib/vue -> ... 6. @saflib/vue -> @saflib/ory-kratos-sdk -> ... Also refresh list-importers spot-check baseline 1071 -> 1151. Co-authored-by: Cursor <cursoragent@cursor.com>
Add composite/declaration/emitDeclarationOnly to the monorepo and Vue presets, scaffold packages with dist/types emit + tsc -b, and ignore generated declaration/incremental artifacts. Co-authored-by: Cursor <cursoragent@cursor.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.
I'm doing an overhaul of SAF based on scaling issues I've run into. A big one is typechecking, which has gone over memory limits easily. Here's the summary of changes (other milestones referenced are further improvements to overall code structure):
M1 PR Summary: TypeScript Project References for Incremental Typechecking
Problem
Before M1, the repo typechecked as one monolithic program: root
tsconfig.jsonhad noreferences, sovue-tsc -bat the root pulled in ~448k lines across ~107 packages with no incrementality. That meant slow rebuilds, high memory use, and frequentTS6305/ composite emit failures when packages weren't wired as a proper reference graph.Solution (high level)
Turn the monorepo into a TypeScript solution graph: every workspace package is a
compositeproject with its ownreferences, declaration emit goes todist/types/, and a generator keeps the graph in sync withpackage.jsonworkspace deps. Rootnpm run typecheckis nowvue-tsc -bover that graph instead of one giant compile.1. Shared tsconfig presets (
saflib)Split shared presets from package-specific config — the main structural fix.
Previously, shared presets like
@saflib/monorepo/tsconfig.jsonand@saflib/vue/tsconfig.app.jsoncontainedoutDir,include, andreferences. TypeScript resolves those relative to the preset file, not the consuming package, which caused declarations to emit next to source files and broke composite boundaries.Changes:
saflib/monorepo/tsconfig.base.json— shared compiler options only (composite,declaration,emitDeclarationOnly, strictness). NooutDir.saflib/monorepo/tsconfig.json— monorepo package's own solution root.saflib/vue/tsconfig.app.base.json— exported Vue preset (no package-specificinclude/references). Overrides@vue/tsconfig'snoEmit: true, addstypes: ["vite/client"].saflib/vue/tsconfig.app.json—@saflib/vue's own compile config withoutDir: ./dist/types.saflib/vue/package.json— exports./tsconfig.app.json→./tsconfig.app.base.jsonso consumers extend the preset, not the package's leaf config.Per-package pattern (applied across ~109 packages via generator):
{ "extends": "@saflib/monorepo/tsconfig.json", "compilerOptions": { "outDir": "./dist/types", "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo", "noEmit": false, "emitDeclarationOnly": true }, "references": [ /* generated from workspace deps */ ] }Vue packages keep the
tsconfig.app.json/tsconfig.node.jsonsplit; external references always point at a package's roottsconfig.json, never the.appleaf.2. Reference graph generator (
@saflib/imports)New
saf-imports referencescommands:references cyclesreferences generate --writereferences+ solution rootsreferences checkGenerator rules (
saflib/imports/src/references/generate.ts):dependencies∪devDependenciesensurePackageEmitOptions()— per-packageoutDir,noEmit: false,emitDeclarationOnly: true, excludedist/typesand workflow templatestsconfig.base.json,tsconfig.app.base.json){ "./saflib" }hub + daemon/deploy leaves@pathclerk/daemon-monolithreferences everydaemon/service/*packagedist/artifacts (e.g.saflib-workflows) from the graph3. Breaking dependency cycles (Phase 3.5)
compositeforbids reference cycles. ~11 cycles across 4 clusters were broken with behavior-preserving refactors:@pathclerk/daemon-formscompleteProposedFormDataChangesaliased toemptyProposedFormDataChangesin@pathclerk/daemon-spec/emptiesResult: 0 reference cycles.
4. Cross-package import fixes
Composite +
emitDeclarationOnlyrequires package-boundary imports. Relative imports like../../common/foo.tspull source into the wrong compilation unit →TS6059/TS6307/TS7056.Pattern applied across daemon clients, sdk, saflib/vue:
main.ts/strings.ts→@pathclerk/daemon-clients-common/...@pathclerk/daemon-admin-clients/processing-forms-bundle-plugin(deleted shim)@pathclerk/daemon-spec/empties@pathclerk/daemon-account-spa/fixturessaflib/vue/src/events.ts→@saflib/linkspackage.jsonexports were added/updated where needed;references generate --writerun after export changes.5. Declaration emit edge cases
Composite emit surfaced typing issues hidden by the monolithic build:
SdkMutation<T>helper (daemon/service/sdk/mutation-types.ts) — avoidsTS7056on large mutation hook exports; impl/export + cast pattern for hooks that exceed serializer limitsQueryOptions<unknown, Error>annotations that brokeuseQuery()overloads; used proper wire types (MatterDossier,ListPacketReviewContextMattersData) or: anyon exports that hitTS7056UseQueryReturnType<any, any>on page loaders forAsyncPagecompatibilityassets.d.ts— restored atsaflib/vue/src/assets.d.tsanddaemon/clients/root/assets.d.tsfor CSS module declarationsvitest-config.d.ts—UserConfiginstead ofUserConfigExportformergeConfigcompatibility6. Emit hygiene (
.gitignore)Composite emit initially wrote
.d.tsnext to source (badoutDirresolution). After fixing presets:.d.tsfiles.gitignore(pathclerk + saflib):**/dist/types/,*.tsbuildinfo,**/*.d.ts.map, co-located**/*.d.tswith exceptions for hand-authoredassets.d.tsandvitest-config.d.tsdist/types/without clearingnode_modules/.tmp/*.tsbuildinfocauses false "up to date" skips → massTS6305. Fix:--forceafter clean.7. Scaffolding & CI
tsconfig.jsonfordaemon/dev, workflow template dev packagetsconfig.node.jsonrefs from packages without avite.config.ts(saflib/vue,daemon/clients/app)references checkadded beforenpm run typecheckin pathclerk and saflib workflowssaflib/imports/docs/03-project-references.md— dev loop, generate/check, cycle troubleshooting, stale incremental buildssaf-imports baseline generatewithrootBuildWallMsandwarmSinglePackageWallMs; updatedbaseline.jsonand spec success metricsResults
http)Import graph module counts unchanged (M1 scope was wiring only, not barrel deletion — that's M2).
What this enables
package.jsonexportsreferences generate --write+ CIreferences checkkeeps the graph from rottingOut of scope (deferred to M2+)
sideEffectsaudit