From 22eb46e92fd5afeeed1c84fd2b6d0d3296bbade6 Mon Sep 17 00:00:00 2001 From: "g. nicholas d'andrea" Date: Wed, 16 Sep 2026 19:04:58 -0400 Subject: [PATCH 1/4] ci: type-check test files against live package source 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. --- .github/workflows/ci.yml | 6 + bin/check-typecheck-sources.test.ts | 36 ++++ bin/check-typecheck-sources.ts | 52 +++++ package.json | 1 + packages/bugc-react/package.json | 1 + packages/bugc-react/tsconfig.typecheck.json | 16 ++ packages/bugc/package.json | 192 ++++++++++++++---- packages/bugc/tsconfig.typecheck.json | 14 ++ packages/conformance/package.json | 1 + packages/conformance/tsconfig.typecheck.json | 15 ++ packages/evm/package.json | 1 + packages/evm/tsconfig.typecheck.json | 13 ++ packages/format/package.json | 1 + packages/format/tsconfig.typecheck.json | 8 + packages/pointers-react/package.json | 1 + .../pointers-react/tsconfig.typecheck.json | 13 ++ packages/pointers/package.json | 1 + packages/pointers/tsconfig.json | 1 + packages/pointers/tsconfig.typecheck.json | 12 ++ packages/programs-react/package.json | 16 +- .../programs-react/tsconfig.typecheck.json | 13 ++ tsconfig.base.json | 14 ++ 22 files changed, 386 insertions(+), 42 deletions(-) create mode 100644 bin/check-typecheck-sources.test.ts create mode 100644 bin/check-typecheck-sources.ts create mode 100644 packages/bugc-react/tsconfig.typecheck.json create mode 100644 packages/bugc/tsconfig.typecheck.json create mode 100644 packages/conformance/tsconfig.typecheck.json create mode 100644 packages/evm/tsconfig.typecheck.json create mode 100644 packages/format/tsconfig.typecheck.json create mode 100644 packages/pointers-react/tsconfig.typecheck.json create mode 100644 packages/pointers/tsconfig.typecheck.json create mode 100644 packages/programs-react/tsconfig.typecheck.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7feb6a33ad..445f63e05e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,6 +23,12 @@ jobs: - name: Lint run: yarn lint + - name: Type-check + run: yarn typecheck + + - name: Check type-check programs use live source + run: yarn tsx bin/check-typecheck-sources.ts + run-tests: runs-on: ubuntu-latest strategy: diff --git a/bin/check-typecheck-sources.test.ts b/bin/check-typecheck-sources.test.ts new file mode 100644 index 0000000000..ee0bcc6845 --- /dev/null +++ b/bin/check-typecheck-sources.test.ts @@ -0,0 +1,36 @@ +import { describe, expect, it } from "vitest"; +import { builtFiles } from "./check-typecheck-sources.js"; + +const listing = [ + "/repo/node_modules/typescript/lib/lib.es2020.d.ts", + "/repo/packages/format/src/index.ts", + "/repo/packages/pointers/src/read.ts", + "/repo/node_modules/@types/node/index.d.ts", + "", +]; + +describe("builtFiles", () => { + it("accepts source files and third-party declarations", () => { + expect(builtFiles(listing.join("\n"))).toEqual([]); + }); + + it("reports a sibling package's built declarations", () => { + const stdout = [ + ...listing, + "/repo/packages/format/dist/src/index.d.ts", + ].join("\n"); + expect(builtFiles(stdout)).toEqual([ + "/repo/packages/format/dist/src/index.d.ts", + ]); + }); + + it("reports declarations reached through node_modules/@ethdebug", () => { + const stdout = [ + ...listing, + "/repo/node_modules/@ethdebug/format/dist/src/index.d.ts", + ].join("\n"); + expect(builtFiles(stdout)).toEqual([ + "/repo/node_modules/@ethdebug/format/dist/src/index.d.ts", + ]); + }); +}); diff --git a/bin/check-typecheck-sources.ts b/bin/check-typecheck-sources.ts new file mode 100644 index 0000000000..fccc41bf7f --- /dev/null +++ b/bin/check-typecheck-sources.ts @@ -0,0 +1,52 @@ +import { execFileSync } from "node:child_process"; +import { existsSync } from "node:fs"; +import { join } from "node:path"; +import { fileURLToPath, pathToFileURL } from "node:url"; +import { readWorkspaces } from "./publish-tagged.js"; + +const built = [/packages\/[^/]+\/dist\//, /node_modules\/@ethdebug\//]; + +export function builtFiles(stdout: string): string[] { + return stdout + .split("\n") + .map((line) => line.trim()) + .filter((line) => line.length > 0 && built.some((re) => re.test(line))); +} + +function tsc(root: string, packageDir: string): string { + const local = join(packageDir, "node_modules", ".bin", "tsc"); + return existsSync(local) ? local : join(root, "node_modules", ".bin", "tsc"); +} + +function listFiles(root: string, packageDir: string): string { + return execFileSync( + tsc(root, packageDir), + ["-p", "tsconfig.typecheck.json", "--listFiles", "--noEmit"], + { cwd: packageDir, encoding: "utf8", stdio: ["ignore", "pipe", "inherit"] }, + ); +} + +function main(): number { + const root = fileURLToPath(new URL("..", import.meta.url)); + let failed = false; + for (const workspace of readWorkspaces(root)) { + if (!existsSync(join(workspace.dir, "tsconfig.typecheck.json"))) { + continue; + } + const bad = builtFiles(listFiles(root, workspace.dir)); + if (bad.length > 0) { + failed = true; + console.error(`${workspace.name}: type-check reads built declarations:`); + for (const path of bad) { + console.error(` ${path}`); + } + } else { + console.log(`${workspace.name}: ok`); + } + } + return failed ? 1 : 0; +} + +if (import.meta.url === pathToFileURL(process.argv[1]).href) { + process.exit(main()); +} diff --git a/package.json b/package.json index 1be0987453..e307da343a 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "scripts": { "build": "yarn lerna run build --no-private", "bundle": "tsx ./bin/bundle-schema.ts", + "typecheck": "yarn lerna run typecheck --ignore @ethdebug/format-web --ignore @ethdebug/bug-playground", "test": "vitest run", "test:coverage": "vitest run --coverage", "start": "./bin/start", diff --git a/packages/bugc-react/package.json b/packages/bugc-react/package.json index 19efeedd6d..094f5cda2a 100644 --- a/packages/bugc-react/package.json +++ b/packages/bugc-react/package.json @@ -46,6 +46,7 @@ "scripts": { "build": "rm -rf dist && tsc --build tsconfig.build.json && copyfiles -u 1 \"src/**/*.css\" dist/src", "prepare": "yarn build", + "typecheck": "tsc -p tsconfig.typecheck.json", "watch": "tsc --watch --preserveWatchOutput", "test": "vitest run" }, diff --git a/packages/bugc-react/tsconfig.typecheck.json b/packages/bugc-react/tsconfig.typecheck.json new file mode 100644 index 0000000000..2d774f1e30 --- /dev/null +++ b/packages/bugc-react/tsconfig.typecheck.json @@ -0,0 +1,16 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": true, + "composite": false, + "incremental": false, + "rootDir": "../..", + "paths": { + "@ethdebug/bugc": ["../bugc/src/index.ts"], + "@ethdebug/evm": ["../evm/src/index.ts"], + "@ethdebug/format": ["../format/src/index.ts"], + "@ethdebug/pointers": ["../pointers/src/index.ts"], + "@ethdebug/bugc/examples": ["../bugc/src/examples/index.ts"] + } + } +} diff --git a/packages/bugc/package.json b/packages/bugc/package.json index 853ea9958c..76d5a677bd 100644 --- a/packages/bugc/package.json +++ b/packages/bugc/package.json @@ -26,44 +26,158 @@ "bugc": "./dist/bin/bugc.js" }, "imports": { - "#ast": "./dist/src/ast/index.js", - "#ast/spec": "./dist/src/ast/spec.js", - "#ast/visitor": "./dist/src/ast/visitor.js", - "#ast/analysis": "./dist/src/ast/analysis/index.js", - "#cli": "./dist/src/cli/index.js", - "#compiler": "./dist/src/compiler/index.js", - "#errors": "./dist/src/errors/index.js", - "#evm": "./dist/src/evm/index.js", - "#evm/spec": "./dist/src/evm/spec/index.js", - "#evm/analysis": "./dist/src/evm/analysis/index.js", - "#evmgen": "./dist/src/evmgen/index.js", - "#evmgen/analysis": "./dist/src/evmgen/analysis/index.js", - "#evmgen/errors": "./dist/src/evmgen/errors.js", - "#evmgen/state": "./dist/src/evmgen/state.js", - "#evmgen/operations": "./dist/src/evmgen/operations.js", - "#evmgen/generation": "./dist/src/evmgen/generation/index.js", - "#evmgen/serialize": "./dist/src/evmgen/serialize.js", - "#evmgen/pass": "./dist/src/evmgen/pass.js", - "#evmgen/program-builder": "./dist/src/evmgen/program-builder.js", - "#ir": "./dist/src/ir/index.js", - "#ir/spec": "./dist/src/ir/spec/index.js", - "#ir/analysis": "./dist/src/ir/analysis/index.js", - "#irgen": "./dist/src/irgen/index.js", - "#irgen/pass": "./dist/src/irgen/pass.js", - "#irgen/errors": "./dist/src/irgen/errors.js", - "#irgen/type": "./dist/src/irgen/type.js", - "#irgen/generate": "./dist/src/irgen/generate/index.js", - "#irgen/debug/variables": "./dist/src/irgen/debug/variables.js", - "#optimizer": "./dist/src/optimizer/index.js", - "#optimizer/*": "./dist/src/optimizer/*.js", - "#parser": "./dist/src/parser/index.js", - "#parser/pass": "./dist/src/parser/pass.js", - "#result": "./dist/src/result.js", - "#typechecker": "./dist/src/typechecker/index.js", - "#typechecker/pass": "./dist/src/typechecker/pass.js", - "#types": "./dist/src/types/index.js", - "#types/analysis": "./dist/src/types/analysis/index.js", - "#types/spec": "./dist/src/types/spec.js", + "#ast": { + "types": "./src/ast/index.ts", + "default": "./dist/src/ast/index.js" + }, + "#ast/spec": { + "types": "./src/ast/spec.ts", + "default": "./dist/src/ast/spec.js" + }, + "#ast/visitor": { + "types": "./src/ast/visitor.ts", + "default": "./dist/src/ast/visitor.js" + }, + "#ast/analysis": { + "types": "./src/ast/analysis/index.ts", + "default": "./dist/src/ast/analysis/index.js" + }, + "#cli": { + "types": "./src/cli/index.ts", + "default": "./dist/src/cli/index.js" + }, + "#compiler": { + "types": "./src/compiler/index.ts", + "default": "./dist/src/compiler/index.js" + }, + "#errors": { + "types": "./src/errors/index.ts", + "default": "./dist/src/errors/index.js" + }, + "#evm": { + "types": "./src/evm/index.ts", + "default": "./dist/src/evm/index.js" + }, + "#evm/spec": { + "types": "./src/evm/spec/index.ts", + "default": "./dist/src/evm/spec/index.js" + }, + "#evm/analysis": { + "types": "./src/evm/analysis/index.ts", + "default": "./dist/src/evm/analysis/index.js" + }, + "#evmgen": { + "types": "./src/evmgen/index.ts", + "default": "./dist/src/evmgen/index.js" + }, + "#evmgen/analysis": { + "types": "./src/evmgen/analysis/index.ts", + "default": "./dist/src/evmgen/analysis/index.js" + }, + "#evmgen/errors": { + "types": "./src/evmgen/errors.ts", + "default": "./dist/src/evmgen/errors.js" + }, + "#evmgen/state": { + "types": "./src/evmgen/state.ts", + "default": "./dist/src/evmgen/state.js" + }, + "#evmgen/operations": { + "types": "./src/evmgen/operations.ts", + "default": "./dist/src/evmgen/operations.js" + }, + "#evmgen/generation": { + "types": "./src/evmgen/generation/index.ts", + "default": "./dist/src/evmgen/generation/index.js" + }, + "#evmgen/serialize": { + "types": "./src/evmgen/serialize.ts", + "default": "./dist/src/evmgen/serialize.js" + }, + "#evmgen/pass": { + "types": "./src/evmgen/pass.ts", + "default": "./dist/src/evmgen/pass.js" + }, + "#evmgen/program-builder": { + "types": "./src/evmgen/program-builder.ts", + "default": "./dist/src/evmgen/program-builder.js" + }, + "#ir": { + "types": "./src/ir/index.ts", + "default": "./dist/src/ir/index.js" + }, + "#ir/spec": { + "types": "./src/ir/spec/index.ts", + "default": "./dist/src/ir/spec/index.js" + }, + "#ir/analysis": { + "types": "./src/ir/analysis/index.ts", + "default": "./dist/src/ir/analysis/index.js" + }, + "#irgen": { + "types": "./src/irgen/index.ts", + "default": "./dist/src/irgen/index.js" + }, + "#irgen/pass": { + "types": "./src/irgen/pass.ts", + "default": "./dist/src/irgen/pass.js" + }, + "#irgen/errors": { + "types": "./src/irgen/errors.ts", + "default": "./dist/src/irgen/errors.js" + }, + "#irgen/type": { + "types": "./src/irgen/type.ts", + "default": "./dist/src/irgen/type.js" + }, + "#irgen/generate": { + "types": "./src/irgen/generate/index.ts", + "default": "./dist/src/irgen/generate/index.js" + }, + "#irgen/debug/variables": { + "types": "./src/irgen/debug/variables.ts", + "default": "./dist/src/irgen/debug/variables.js" + }, + "#optimizer": { + "types": "./src/optimizer/index.ts", + "default": "./dist/src/optimizer/index.js" + }, + "#optimizer/*": { + "types": "./src/optimizer/*.ts", + "default": "./dist/src/optimizer/*.js" + }, + "#parser": { + "types": "./src/parser/index.ts", + "default": "./dist/src/parser/index.js" + }, + "#parser/pass": { + "types": "./src/parser/pass.ts", + "default": "./dist/src/parser/pass.js" + }, + "#result": { + "types": "./src/result.ts", + "default": "./dist/src/result.js" + }, + "#typechecker": { + "types": "./src/typechecker/index.ts", + "default": "./dist/src/typechecker/index.js" + }, + "#typechecker/pass": { + "types": "./src/typechecker/pass.ts", + "default": "./dist/src/typechecker/pass.js" + }, + "#types": { + "types": "./src/types/index.ts", + "default": "./dist/src/types/index.js" + }, + "#types/analysis": { + "types": "./src/types/analysis/index.ts", + "default": "./dist/src/types/analysis/index.js" + }, + "#types/spec": { + "types": "./src/types/spec.ts", + "default": "./dist/src/types/spec.js" + }, "#test/*": "./test/*.ts" }, "scripts": { @@ -75,7 +189,7 @@ "test:watch": "vitest", "test:coverage": "vitest run --coverage", "lint": "eslint src bin --ext .ts", - "typecheck": "tsc --noEmit", + "typecheck": "tsc -p tsconfig.typecheck.json", "format": "prettier --write \"src/**/*.ts\"", "format:check": "prettier --check \"src/**/*.ts\"", "prepare": "yarn build" diff --git a/packages/bugc/tsconfig.typecheck.json b/packages/bugc/tsconfig.typecheck.json new file mode 100644 index 0000000000..ef688383cb --- /dev/null +++ b/packages/bugc/tsconfig.typecheck.json @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": true, + "composite": false, + "incremental": false, + "rootDir": "../..", + "paths": { + "@ethdebug/evm": ["../evm/src/index.ts"], + "@ethdebug/format": ["../format/src/index.ts"], + "@ethdebug/pointers": ["../pointers/src/index.ts"] + } + } +} diff --git a/packages/conformance/package.json b/packages/conformance/package.json index e2e3156260..288ef3f053 100644 --- a/packages/conformance/package.json +++ b/packages/conformance/package.json @@ -40,6 +40,7 @@ "scripts": { "prepare": "tsc", "build": "tsc", + "typecheck": "tsc -p tsconfig.typecheck.json", "test": "vitest run", "test:external": "vitest run --no-file-parallelism --maxWorkers=1" }, diff --git a/packages/conformance/tsconfig.typecheck.json b/packages/conformance/tsconfig.typecheck.json new file mode 100644 index 0000000000..3d9d538686 --- /dev/null +++ b/packages/conformance/tsconfig.typecheck.json @@ -0,0 +1,15 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": true, + "composite": false, + "incremental": false, + "rootDir": "../..", + "paths": { + "@ethdebug/bugc": ["../bugc/src/index.ts"], + "@ethdebug/evm": ["../evm/src/index.ts"], + "@ethdebug/format": ["../format/src/index.ts"], + "@ethdebug/pointers": ["../pointers/src/index.ts"] + } + } +} diff --git a/packages/evm/package.json b/packages/evm/package.json index 0392246a3b..540777384a 100644 --- a/packages/evm/package.json +++ b/packages/evm/package.json @@ -35,6 +35,7 @@ "scripts": { "build": "rm -rf dist && tsc --build tsconfig.build.json", "prepare": "yarn build", + "typecheck": "tsc -p tsconfig.typecheck.json", "watch": "tsc --watch --preserveWatchOutput", "test": "vitest run" }, diff --git a/packages/evm/tsconfig.typecheck.json b/packages/evm/tsconfig.typecheck.json new file mode 100644 index 0000000000..6e118cf769 --- /dev/null +++ b/packages/evm/tsconfig.typecheck.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": true, + "composite": false, + "incremental": false, + "rootDir": "../..", + "paths": { + "@ethdebug/format": ["../format/src/index.ts"], + "@ethdebug/pointers": ["../pointers/src/index.ts"] + } + } +} diff --git a/packages/format/package.json b/packages/format/package.json index 488429ff5a..3867b22324 100644 --- a/packages/format/package.json +++ b/packages/format/package.json @@ -57,6 +57,7 @@ "build": "yarn prepare:yamls && rm -rf dist && tsc --build tsconfig.build.json", "prepare": "yarn build", "clean": "rm -rf dist && rm src/schemas/yamls.ts", + "typecheck": "tsc -p tsconfig.typecheck.json", "test": "vitest", "watch:typescript": "tsc --watch", "watch:schemas": "nodemon --watch ../../schemas -e 'yaml' --exec 'yarn prepare:yamls'", diff --git a/packages/format/tsconfig.typecheck.json b/packages/format/tsconfig.typecheck.json new file mode 100644 index 0000000000..ee7871ef08 --- /dev/null +++ b/packages/format/tsconfig.typecheck.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": true, + "composite": false, + "incremental": false + } +} diff --git a/packages/pointers-react/package.json b/packages/pointers-react/package.json index 472790f6a3..e60fd1bfa7 100644 --- a/packages/pointers-react/package.json +++ b/packages/pointers-react/package.json @@ -35,6 +35,7 @@ "scripts": { "build": "rm -rf dist && tsc --build tsconfig.build.json && copyfiles -u 1 \"src/**/*.css\" dist/src", "prepare": "yarn build", + "typecheck": "tsc -p tsconfig.typecheck.json", "watch": "tsc --watch --preserveWatchOutput", "test": "vitest run" }, diff --git a/packages/pointers-react/tsconfig.typecheck.json b/packages/pointers-react/tsconfig.typecheck.json new file mode 100644 index 0000000000..6e118cf769 --- /dev/null +++ b/packages/pointers-react/tsconfig.typecheck.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": true, + "composite": false, + "incremental": false, + "rootDir": "../..", + "paths": { + "@ethdebug/format": ["../format/src/index.ts"], + "@ethdebug/pointers": ["../pointers/src/index.ts"] + } + } +} diff --git a/packages/pointers/package.json b/packages/pointers/package.json index cc56ec946f..8cebbbf4df 100644 --- a/packages/pointers/package.json +++ b/packages/pointers/package.json @@ -51,6 +51,7 @@ "scripts": { "build": "rm -rf dist && tsc --build tsconfig.build.json", "prepare": "yarn build", + "typecheck": "tsc -p tsconfig.typecheck.json", "run-example": "tsx bin/run-example.ts", "watch": "tsc --build --watch", "test": "vitest" diff --git a/packages/pointers/tsconfig.json b/packages/pointers/tsconfig.json index 5621f6e66d..367a372642 100644 --- a/packages/pointers/tsconfig.json +++ b/packages/pointers/tsconfig.json @@ -15,5 +15,6 @@ "#test/*": ["./test/*"] } }, + "exclude": ["node_modules", "dist"], "references": [{ "path": "../format" }] } diff --git a/packages/pointers/tsconfig.typecheck.json b/packages/pointers/tsconfig.typecheck.json new file mode 100644 index 0000000000..afe77567d1 --- /dev/null +++ b/packages/pointers/tsconfig.typecheck.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": true, + "composite": false, + "incremental": false, + "rootDir": "../..", + "paths": { + "@ethdebug/format": ["../format/src/index.ts"] + } + } +} diff --git a/packages/programs-react/package.json b/packages/programs-react/package.json index e33c874fb9..b7d96a4064 100644 --- a/packages/programs-react/package.json +++ b/packages/programs-react/package.json @@ -20,21 +20,31 @@ }, "imports": { "#components/*": { - "types": "./src/components/*.tsx", + "types": [ + "./src/components/*.tsx", + "./src/components/*.ts" + ], "default": "./dist/src/components/*.js" }, "#shiki/*": { - "types": "./src/shiki/*.ts", + "types": [ + "./src/shiki/*.ts", + "./src/shiki/*.tsx" + ], "default": "./dist/src/shiki/*.js" }, "#utils/*": { - "types": "./src/utils/*.ts", + "types": [ + "./src/utils/*.ts", + "./src/utils/*.tsx" + ], "default": "./dist/src/utils/*.js" } }, "scripts": { "build": "rm -rf dist && tsc --build tsconfig.build.json && copyfiles -u 1 \"src/**/*.css\" dist/src", "prepare": "yarn build", + "typecheck": "tsc -p tsconfig.typecheck.json", "watch": "tsc --watch --preserveWatchOutput", "test": "vitest run" }, diff --git a/packages/programs-react/tsconfig.typecheck.json b/packages/programs-react/tsconfig.typecheck.json new file mode 100644 index 0000000000..6e118cf769 --- /dev/null +++ b/packages/programs-react/tsconfig.typecheck.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": true, + "composite": false, + "incremental": false, + "rootDir": "../..", + "paths": { + "@ethdebug/format": ["../format/src/index.ts"], + "@ethdebug/pointers": ["../pointers/src/index.ts"] + } + } +} diff --git a/tsconfig.base.json b/tsconfig.base.json index f702e09583..27a9e8d03e 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1,3 +1,17 @@ +/* + * Shared compiler options for every package. + * + * Each package's tsconfig.typecheck.json maps its @ethdebug/* + * dependencies to sibling source, so `yarn typecheck` compiles a + * dependency's source under the DEPENDENT's compilerOptions. Keep + * per-package type-checking strictness uniform, or confine a stricter + * setting to a package nothing else depends on: a package that relaxes + * an option its dependents set would report errors in its own source + * only when a dependent checks it. Today only format adds + * exactOptionalPropertyTypes; turning that option on can only add + * errors, so a dependent, which leaves it off, simply checks format's + * source less strictly than format itself does. + */ { "compilerOptions": { /* Visit https://aka.ms/tsconfig to read more about this file */ From c1fbc1512a8194c10ecbfb8d85ebb2bb618f5dd3 Mon Sep 17 00:00:00 2001 From: "g. nicholas d'andrea" Date: Wed, 16 Sep 2026 19:06:01 -0400 Subject: [PATCH 2/4] build: run conformance's build from root 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. --- package.json | 2 +- packages/conformance/package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index e307da343a..ca4eb2efe6 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "packages/*" ], "scripts": { - "build": "yarn lerna run build --no-private", + "build": "yarn lerna run build --ignore @ethdebug/format-web --ignore @ethdebug/bug-playground", "bundle": "tsx ./bin/bundle-schema.ts", "typecheck": "yarn lerna run typecheck --ignore @ethdebug/format-web --ignore @ethdebug/bug-playground", "test": "vitest run", diff --git a/packages/conformance/package.json b/packages/conformance/package.json index 288ef3f053..3eb70388e8 100644 --- a/packages/conformance/package.json +++ b/packages/conformance/package.json @@ -38,8 +38,8 @@ } }, "scripts": { - "prepare": "tsc", - "build": "tsc", + "prepare": "yarn build", + "build": "rm -rf dist && tsc", "typecheck": "tsc -p tsconfig.typecheck.json", "test": "vitest run", "test:external": "vitest run --no-file-parallelism --maxWorkers=1" From 2e3ad9ec87c2a87f583e8b2c687c50fccdf83ca0 Mon Sep 17 00:00:00 2001 From: "g. nicholas d'andrea" Date: Wed, 16 Sep 2026 19:06:34 -0400 Subject: [PATCH 3/4] ci: build the playground 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. --- .github/workflows/ci.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 445f63e05e..41325bdf23 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -72,3 +72,24 @@ jobs: - name: Build website run: yarn build working-directory: ./packages/web + + build-playground: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: yarn + cache-dependency-path: yarn.lock + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Build all packages + run: yarn build + + - name: Build playground + run: yarn build + working-directory: ./packages/playground From 5b1e974758df0deb221196962cace90446a2d04a Mon Sep 17 00:00:00 2001 From: "g. nicholas d'andrea" Date: Wed, 16 Sep 2026 19:08:35 -0400 Subject: [PATCH 4/4] build: watch the React packages from bin/start 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. --- bin/start | 7 +++++-- packages/bugc-react/package.json | 4 +++- packages/pointers-react/package.json | 4 +++- packages/programs-react/package.json | 4 +++- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/bin/start b/bin/start index ffd64a77b7..05b20cc07e 100755 --- a/bin/start +++ b/bin/start @@ -1,4 +1,4 @@ -#!/usr/bin/env sh +#!/usr/bin/env bash # Check if the --no-open flag is provided if [[ " $* " == *" --no-open "* ]]; then @@ -10,11 +10,14 @@ else fi # Run the commands with concurrently -concurrently --names=format,pointers,evm,bugc,programs-react,playground,web,tests \ +concurrently \ + --names=format,pointers,evm,bugc,bugc-react,pointers-react,programs-react,playground,web,tests \ "cd ./packages/format && yarn watch" \ "cd ./packages/pointers && yarn watch" \ "cd ./packages/evm && yarn watch" \ "cd ./packages/bugc && yarn watch" \ + "cd ./packages/bugc-react && yarn watch" \ + "cd ./packages/pointers-react && yarn watch" \ "cd ./packages/programs-react && yarn watch" \ "cd ./packages/playground && yarn watch" \ "cd ./packages/web && yarn start $DOCUSAURUS_NO_OPEN" \ diff --git a/packages/bugc-react/package.json b/packages/bugc-react/package.json index 094f5cda2a..35c5225f1b 100644 --- a/packages/bugc-react/package.json +++ b/packages/bugc-react/package.json @@ -47,7 +47,7 @@ "build": "rm -rf dist && tsc --build tsconfig.build.json && copyfiles -u 1 \"src/**/*.css\" dist/src", "prepare": "yarn build", "typecheck": "tsc -p tsconfig.typecheck.json", - "watch": "tsc --watch --preserveWatchOutput", + "watch": "copyfiles -u 1 \"src/**/*.css\" dist/src && concurrently --names=tsc,css \"tsc --watch --preserveWatchOutput\" \"nodemon --watch src -e css --exec 'copyfiles -u 1 \\\"src/**/*.css\\\" dist/src'\"", "test": "vitest run" }, "dependencies": { @@ -59,7 +59,9 @@ "@types/dagre": "^0.7.52", "@types/react": "^18.2.43", "@types/react-dom": "^18.2.17", + "concurrently": "^8.2.2", "jsdom": "^26.0.0", + "nodemon": "^3.1.11", "react": "^18.2.0", "react-dom": "^18.2.0", "typescript": "^5.0.0", diff --git a/packages/pointers-react/package.json b/packages/pointers-react/package.json index e60fd1bfa7..0bbfde8909 100644 --- a/packages/pointers-react/package.json +++ b/packages/pointers-react/package.json @@ -36,7 +36,7 @@ "build": "rm -rf dist && tsc --build tsconfig.build.json && copyfiles -u 1 \"src/**/*.css\" dist/src", "prepare": "yarn build", "typecheck": "tsc -p tsconfig.typecheck.json", - "watch": "tsc --watch --preserveWatchOutput", + "watch": "copyfiles -u 1 \"src/**/*.css\" dist/src && concurrently --names=tsc,css \"tsc --watch --preserveWatchOutput\" \"nodemon --watch src -e css --exec 'copyfiles -u 1 \\\"src/**/*.css\\\" dist/src'\"", "test": "vitest run" }, "dependencies": { @@ -48,7 +48,9 @@ "@testing-library/react": "^16.0.0", "@types/react": "^18.2.43", "@types/react-dom": "^18.2.17", + "concurrently": "^8.2.2", "jsdom": "^26.0.0", + "nodemon": "^3.1.11", "react": "^18.2.0", "react-dom": "^18.2.0", "typescript": "^5.0.0", diff --git a/packages/programs-react/package.json b/packages/programs-react/package.json index b7d96a4064..aa2e0b14df 100644 --- a/packages/programs-react/package.json +++ b/packages/programs-react/package.json @@ -45,7 +45,7 @@ "build": "rm -rf dist && tsc --build tsconfig.build.json && copyfiles -u 1 \"src/**/*.css\" dist/src", "prepare": "yarn build", "typecheck": "tsc -p tsconfig.typecheck.json", - "watch": "tsc --watch --preserveWatchOutput", + "watch": "copyfiles -u 1 \"src/**/*.css\" dist/src && concurrently --names=tsc,css \"tsc --watch --preserveWatchOutput\" \"nodemon --watch src -e css --exec 'copyfiles -u 1 \\\"src/**/*.css\\\" dist/src'\"", "test": "vitest run" }, "dependencies": { @@ -60,7 +60,9 @@ "@testing-library/react": "^16.0.0", "@types/react": "^18.2.43", "@types/react-dom": "^18.2.17", + "concurrently": "^8.2.2", "jsdom": "^26.0.0", + "nodemon": "^3.1.11", "react": "^18.2.0", "react-dom": "^18.2.0", "typescript": "^5.0.0",