Skip to content

ci, build: type-check tests, build the playground, and rebuild conformance - #299

Merged
gnidan merged 4 commits into
mainfrom
build-ci-typecheck
Sep 17, 2026
Merged

gnidan merged 4 commits into
mainfrom
build-ci-typecheck

Conversation

@gnidan

@gnidan gnidan commented Sep 16, 2026

Copy link
Copy Markdown
Member

Test files stopped type-checking once packages started building from tsconfig.build.json, which excludes test/, .test.ts, and pointers' bin/. Add a tsconfig.typecheck.json to each of the eight packages (the seven public ones plus conformance), extending the base tsconfig.json (which already includes tests, colocated alongside src for most packages) with noEmit, composite: false, and incremental: false, so tsc runs a plain single-project check instead of a composite build and never writes into dist/. Plain tsc -p tsconfig.json --noEmit still updates dist/*.tsbuildinfo because composite requires incremental; dropping composite avoids that.

Cross-package imports resolve through node_modules package boundaries (main/types fields), not through tsconfig paths pointing at sibling source, so TypeScript's project-reference source-redirect doesn't apply regardless of composite/declarationMap settings, and a check run that way reports on whatever each dependency's last build produced. Each tsconfig.typecheck.json therefore maps every @ethdebug/* package in its dependency closure to that package's src/index.ts and sets rootDir to the repo root so those sources sit inside it: every check now reads live source, with no dependency on build order or on dist/ being current. Those mappings replace the base config's # alias paths rather than extending them, since a child paths map fully overrides the parent's - which is what we want, because one flat alias table cannot serve two packages that both define #machine or #types. Without paths for them, # specifiers resolve under nodenext through the nearest package.json imports map and pick up its types condition, pointing at src. That makes the types conditions load-bearing, so bugc's imports map, which listed only built files, gains them, and the wildcards in programs-react's map fall back to the other of .ts/.tsx. Build output is byte-identical: within a package, paths in its tsconfig.json already resolved these to the same sources. Because a dependency's source is now compiled under the dependent's compilerOptions, per-package strictness has to stay uniform; tsconfig.base.json says so at the top, and notes why format's exactOptionalPropertyTypes is harmless here.

Add a typecheck script per package, a root typecheck that runs them via lerna (skipping only format-web and bug-playground, so conformance is included), and a Type-check step in CI, in lint-and-format so it runs once rather than once per Node version in the test matrix. A second CI step runs bin/check-typecheck-sources.ts, which lists each type-check program's files and fails if any of them sits in a packages/*/dist tree. TypeScript falls through from a missing types target to default with no diagnostic, so without that check a typo or a moved file would quietly send one alias back to built declarations.

Root build used --no-private, which skips conformance now that it's private. Its dist/ was then only produced by postinstall, so a plain yarn build after a clean checkout left it missing. Root build (and now typecheck) instead --ignore the two packages that have no dist to produce (format-web, bug-playground), and conformance gets a build script (rm -rf dist && tsc) matching its base-config build, since it has no tsconfig.build.json and ships nothing. CI's build-playground job now also runs the root yarn build directly, so a break in any package's build is caught there too, not just in build-web.

Nothing in CI ever built packages/playground, so a break in the Vite build, or in bugc-react's compiled CSS that the playground imports from dist/, would go unnoticed until someone ran it locally. Add a build-playground job mirroring build-web.

bin/start watched programs-react but never bugc-react or pointers-react, so editing either left the running playground stale now that it imports their compiled output from dist/. Add both to the watch set. Each of the three React packages' watch script now runs an initial CSS copy and then keeps copying continuously - concurrently running tsc --watch alongside nodemon re-running copyfiles on every src/**/*.css change - the same pattern format already uses for its schema YAMLs, instead of a one-shot copy at startup.

@github-actions

github-actions Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-09-17 00:36 UTC

Since the packages build from tsconfig.build.json, which excludes
tests, nothing type-checked the test files, the test/ helpers, or
pointers' example runner. Each package now has a tsconfig.typecheck.json
that extends its base config with noEmit and without composite or
incremental, so it checks everything the base config includes and
writes nothing into dist/. A typecheck script runs it per package,
root `yarn typecheck` runs all of them through Lerna, and CI runs
that once in the lint job.

Dependencies are checked as live source, not as built declarations.
The typecheck config sets rootDir to the repository root and maps
each @ethdebug/* dependency in the package's closure to that
package's src/index.ts through paths. The package's own # aliases
are deliberately left out of paths: # imports in every file,
including pulled-in dependency source, resolve through the nearest
package.json imports map under nodenext, which takes the types
condition pointing at src/. That avoids alias collisions across
packages (#machine exists in both evm and pointers). bugc's imports
map gains the types conditions the other packages already had, and
programs-react's gain .ts and .tsx fallbacks.

TypeScript falls through from a missing types target to default
without a diagnostic, which would silently send one alias back to
stale dist declarations. bin/check-typecheck-sources.ts lists every
typecheck program's files and fails on any dist/ or
node_modules/@ethdebug path; CI runs it after the type-check.
Because dependency source compiles under the dependent's options,
per-package strictness must stay uniform; tsconfig.base.json says so.
pointers' base config gains an exclude for node_modules and dist,
matching its siblings.
Root `yarn build` used `lerna run build --no-private`, which skips
conformance now that it is private, so its dist/ was built only by
postinstall. Ignore the two packages that are not libraries by name
instead, and give conformance a clean build script like the others.
The playground imports bugc-react's stylesheets from dist/ and no
workflow built it, so a broken path went unnoticed. A build-playground
job mirrors build-web. It also runs the root `yarn build` first, so a
break in any package's build is caught here, not only in build-web.
bugc-react and pointers-react were not in the watch set, and the
React watch scripts only ran tsc, so stylesheet edits never reached
dist/ and the playground that imports them. Each React watch now
copies the stylesheets once, then runs tsc --watch alongside a
nodemon watcher that re-copies CSS on change. bin/start uses bash
explicitly; it already relied on bash syntax.
@gnidan
gnidan merged commit 0760dbc into main Sep 17, 2026
7 checks passed
@gnidan
gnidan deleted the build-ci-typecheck branch September 17, 2026 00:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant