Selaa lähdekoodia

docs: add ADR TSC-first Build and One TSConfig

imccyu 3 kuukautta sitten
vanhempi
sitoutus
20773e12bd
2 muutettua tiedostoa jossa 68 lisäystä ja 0 poistoa
  1. 1 0
      docs/rfc/README.md
  2. 67 0
      docs/rfc/implemented/2026-06-20-ts-build-config.md

+ 1 - 0
docs/rfc/README.md

@@ -60,6 +60,7 @@ Do NOT write one for a mechanical or local choice (a variable name, a one-file r
 | [Rich ACP bash rendering — the terminal card (`_meta`) and command classification](implemented/2026-06-18-acp-terminal-and-tool-rendering.md) | 2026-06-18 |
 | [ACP snapshot tests — record-once / replay-deterministic](implemented/2026-06-19-acp-snapshot-tests.md) | 2026-06-19 |
 | [Real-API e2e in CI against the external DeepSeek API](implemented/2026-06-19-real-api-e2e-ci.md) | 2026-06-19 |
+| [TSC-first build and one tsconfig](implemented/2026-06-20-ts-build-config.md) | 2026-06-20 |
 
 ## Rejected
 

+ 67 - 0
docs/rfc/implemented/2026-06-20-ts-build-config.md

@@ -0,0 +1,67 @@
+# RFC: TSC-first build and one tsconfig
+
+Status: implemented (accepted 2026-06-20)
+
+<!-- XXX: legacy ADR/RFC body format, not yet normalized to a unified RFC template. -->
+
+## Context
+
+The current TypeScript build and typecheck setup had these issues:
+
+- `build` used `tsc` to transform `.ts` to `.d.ts` files for `packages/*` and `vendor/*`, and then used `tsdown` to transform `.ts` to bundled `.js` files. This made two tools do TypeScript transform.
+- `typecheck` tended to validate packages, vendor source, examples, tests, and scripts through one root typecheck config.
+
+The goal is to make build and typecheck use matching tsconfig boundaries and TypeScript resolution/transform behavior. Build should generate `.js`, `.d.ts`, `.js.map`, and `.d.ts.map` through one compiler and config, so publish output and type validation stay consistent.
+
+Validation found several concrete technical issues and possible routes:
+
+- `tsdown` uses `oxc` to transform TypeScript, which is not the same behavior as `tsc`.
+    - Bundled `.d.ts` emitted by `tsdown` conflicts with Cordis' internal relative module augmentation shape.
+    - The tsc output is affected by `allowImportingTsExtensions`, so we need to ensure that generated `.js` files do not import `.ts` files and generated `.d.ts` files do not import `.js` files. Therefore, we need to adjust the import specifiers to extensionless in the TypeScript source.
+    - Bundled `.js` emitted by `tsdown` is not the same behavior as per-file `.js` emitted by `tsc -b`, such as decorator transform behavior.
+- `vendor/*/src`, examples, tests, and scripts cannot all be plain-included in one root strict program.
+    - Directly typechecking `vendor/*/src` under the root strict config triggers many type errors outside this project's ownership.
+    - `package/*` dependencies on `vendor` are resolved to the `vendor/*/lib` for different tsconfig strictness.
+
+
+## Decision
+
+In-package relative imports are extensionless.
+
+`pnpm run build` is a two-stage build:
+
+- Stage 1: `tsc -b tsconfig.build.json` emits publishable per-module `.js`, declarations `.d.ts`, JS sourcemaps `.js.map`, and declaration sourcemaps `.d.ts.map` into each package's `lib/typings`. This is the authoritative TypeScript compilation result. For publish we should keep `.d.ts` and ignore `.js` / `.js.map` / `.d.ts.map`
+    - The build project uses the project-reference graph that `tsc -b` compiles. For example, root `tsconfig.build.json` references package and vendor tsconfigs. It validates and emits package/vendor build results.
+- Stage 2: a bundler reads the emitted JS under `lib/typings` and writes the bundled runtime entry as `lib/index.js` or `lib/index.mjs` (follow current behavior). This stage is bundling only. It must not read TypeScript source or emit declarations.
+
+`tsdown` is no longer the owner of TypeScript compilation or declaration output.
+
+`pnpm run typecheck` runs build mode over the root `tsconfig.json`.
+- The root `tsconfig.json` is the single development/typecheck project. It has `noEmit` for demos, examples, tests, and scripts, and validates package/vendor source through references.
+- Referenced package/vendor projects keep the same emit behavior as build, so typecheck can refresh their `lib/typings` outputs instead of using a separate no-emit graph. Project-specific strictness changes live in the owning `packages/*/tsconfig.json` or `vendor/*/tsconfig.json`.
+
+The command orchestration shape is:
+
+```sh
+pnpm run build:
+tsc -b tsconfig.build.json
+tsdown
+
+pnpm run typecheck:
+tsc -b tsconfig.json
+```
+
+`pnpm run demo:*` still runs `src` directly through tsx and root paths, without a compile step.
+
+## Consequences
+
+Build responsibilities are clearer:
+
+- Each module under `packages/*` and `vendor/*` has one local tsconfig for build, typecheck, and tools that run source directly, such as `tsx` and `vitest`.
+- The `build` command uses `tsconfig.build.json`. `tsc -b` owns the publishable per-module `.js` and `.d.ts` output, and the bundler owns only `lib/index.*`.
+    - `lib/typings/*.d.ts` is the publish declaration output.
+    - `lib/typings/*.js` is only a bundler input and must not be used as a runtime entry or public import target.
+    - `lib/index.*` is the publish runtime output and is generated by the bundler, currently `tsdown`.
+- The `typecheck` command uses `tsconfig.json`. Examples, tests, and scripts are checked by the root no-emit project, while packages and vendor modules keep the same emit behavior as `build`. Package and vendor source stays behind project-reference boundaries.
+
+The Cordis vendor copy now has one more type-structure divergence from upstream. During upstream sync, that divergence must be reapplied or explicitly retired.