feat(ci): type-check embedded TS templates#93
Merged
PAMulligan merged 7 commits intoMay 14, 2026
Conversation
Captures the design decisions (snippets as source of truth, setup-project.sh cp's them at runtime, dedicated CI job typechecks against current dep versions) and breaks implementation into eight task-scoped commits. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Lifts the 12 .ts heredoc bodies from setup-project.sh into real files
under templates/snippets/{shared,cloudflare,node}/. Content is verbatim
from the heredocs — no rewrites, no behavior change. setup-project.sh
still uses heredocs; the next commit wires it to copy these files.
Layout:
templates/snippets/
├── shared/
│ ├── src/db/{schema,client,seed}.ts
│ └── tests/setup.ts
├── cloudflare/
│ ├── src/index.ts
│ ├── src/db/ping.ts
│ ├── src/routes/health.ts
│ └── tests/unit/health.test.ts
└── node/
├── src/index.ts
├── src/db/ping.ts
├── src/routes/health.ts
└── tests/unit/health.test.ts
First step toward type-checking embedded templates in CI (#57).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds package.json + two tsconfigs at templates/snippets/ so the snippet
files can be type-checked against the deps the generated projects ship
with. Co-located with the snippets so node_modules sits where tsc's
upward-walk module resolution can find it.
Each tsconfig uses TypeScript's `rootDirs` to merge `shared/src` and the
respective platform's `src` into one virtual root — that's what lets
`node/src/db/ping.ts`'s `import { client } from './client.js'` resolve
to `shared/src/db/client.ts` (in a generated project those files are
siblings; in the snippet layout they live in different platform dirs).
Both tsconfigs declare `["@cloudflare/workers-types", "node"]` types
(Cloudflare) or `["node"]` (Node). Cloudflare needs Node types too
because the shared seed.ts runs under tsx — `process.env`, `process.exit`
are reachable even on Workers projects via the seed CLI.
Local results: `pnpm run typecheck` exits 0 against both tsconfigs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ippets/ Replaces 12 write_file ... << 'EOF' blocks in scripts/setup-project.sh with copy_file calls pointing at the real .ts files extracted to templates/snippets/ in the previous commit. Net delta: 446 lines removed from the shell script. Generation output is byte-identical to the heredoc version. Verified by generating both Node and Cloudflare projects from the refactored script: each produces 7/7 passing health tests on the generated tree. drizzle.config.ts stays as a heredoc — it's tiny, has no app-code imports, and its only failure mode would be a drizzle-kit defineConfig signature change (caught downstream by drizzle-kit's own typecheck if it ever happens). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a typecheck-templates job that installs the snippet typecheck scaffold (templates/snippets/package.json) with --frozen-lockfile and runs tsc --noEmit against both tsconfig.cloudflare.json and tsconfig.node.json. This catches type drift between setup-project.sh's templates and the Drizzle/Hono/postgres APIs the generated projects will actually install — without needing to run the full setup-project.sh + pnpm install + pnpm typecheck on a freshly-generated project. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds NOTE comments near setup-project.sh's pnpm add lines pointing at templates/snippets/package.json. Bumping a dep on one side without the other is exactly what the typecheck-templates CI job is meant to catch, but a comment helps future maintainers update both proactively. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Documents the new template authoring model: - TS templates live in templates/snippets/, not in setup-project.sh heredocs - shared/cloudflare/node split matches generation logic - Bumping deps requires updating templates/snippets/package.json too - typecheck-templates CI job catches drift; local equivalent is `cd templates/snippets && pnpm run typecheck` Helps future contributors land template changes without surprising CI failures (#57). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4 tasks
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
Catches Drizzle / Hono / postgres API regressions in
setup-project.shtemplates during development rather than after users run the script. Closes #57.What changed:
setup-project.shto real files undertemplates/snippets/{shared,cloudflare,node}/. Setup script now usescopy_filecalls (-446 lines).templates/snippets/(package.json,tsconfig.cloudflare.json,tsconfig.node.json) with deps pinned to match what generated projects install.tsc --noEmitagainst both tsconfigs on every push.setup-project.shand a newCONTRIBUTING.mdsection so future contributors keeppnpm addlines andtemplates/snippets/package.jsonin sync.Notable design choices (full rationale in
docs/plans/2026-05-14-typecheck-embedded-templates.md):setup-project.shcps them at runtime; editors give LSP, autocomplete, and formatting for free.templates/snippets/nottests/typecheck-templates/). Required fortsc's upward-walk module resolution to findnode_modules/.rootDirsin each tsconfig mergesshared/srcand the respective platform'ssrcinto one virtual root. That's what letsnode/src/db/ping.ts'simport { client } from './client.js'resolve toshared/src/db/client.ts(in a generated project those files are siblings; in the snippet layout they live in different dirs).@cloudflare/workers-typesandnode—shared/seed.tsusesprocess.envand runs undertsx(Node), even on Cloudflare-target projects.vitesttypes + globals; their runtime correctness is already verified by running them on generated projects.Test Plan
pnpm install --frozen-lockfile && pnpm run typecheckintemplates/snippets/exits 0bash scripts/setup-project.sh /tmp/x --node→ 7/7 health tests pass on the generated projectbash scripts/setup-project.sh /tmp/x --cloudflare→ 7/7 health tests pass on the generated projectbash -n scripts/setup-project.shcleanOut of scope (follow-ups)
templates/snippets/**/tests/) — needsvitesttypes andvitest/globalsconfigured.templates/shared/tsconfig.jsondoesn't declare["types"]andsetup-project.shdoesn't install@cloudflare/workers-typesfor Workers projects. Generated projects still test fine (vitest doesn't typecheck by default), butpnpm typecheckon a freshly-generated project will fail until those are fixed. Separate issue.🤖 Generated with Claude Code