testImportModuleAugmentation
A module augmentation (declare module "./schema" { namespace Annotations … }) is a definition of its own
(<file>.augments) that every check includes: code passing what it adds typechecks without importing it, its
module is written to merge with the definition wherever that's rendered, and it's edited from a scratch file
naming the definition's namespace (declare module "#codebase/lib/schema").
import { okIn, tempDir } from "#codebase/tcmts/cli/test/e2e/harness"; import assert from "node:assert/strict"; import fs from "node:fs"; import path from "node:path"; export const testImportModuleAugmentation = () => { const dir = tempDir("augment module"); const lib = tempDir("augment module lib"); const tcm = (...args: string[]) => okIn(dir, ...args); tcm("init"); const write = (file: string, text: string) => { fs.mkdirSync(path.dirname(path.join(lib, file)), { recursive: true }); fs.writeFileSync(path.join(lib, file), text); }; write( "tsconfig.json", JSON.stringify({ compilerOptions: { strict: true, lib: ["ESNext"], target: "ES2022" } }), ); write( "src/schema.ts", `export declare namespace Annotations { interface Augment { readonly title?: string; } } export const annotate = (a: Annotations.Augment): Annotations.Augment => a; `, ); write( "src/http.ts", `import type { Annotations } from "./schema"; declare module "./schema" { namespace Annotations { interface Augment { readonly status?: number; } } } export const statusOf = (a: Annotations.Augment): number => a.status ?? 200; `, ); // passes what the augmentation adds without importing the file it's in write( "src/errors.ts", `import { annotate } from "./schema";\nexport const notFound = annotate({ title: "Not Found", status: 404 });\n`, ); tcm("import", path.join(lib, "src"), "--into", "lib"); assert.match( tcm("view", "lib.http.augments"), /declare module "#codebase\/lib\/schema" \{\n\s+namespace Annotations \{/, ); assert.match(tcm("verify"), /verified \d+ definitions/); const scratch = path.join(dir, "scratch.ts"); fs.writeFileSync( scratch, `// tcm: namespace app import { notFound } from "#codebase/lib/errors"; import { statusOf } from "#codebase/lib/http"; export function main() { console.log("status", statusOf(notFound), notFound.title); } `, ); tcm("add"); assert.match(tcm("run", "app.main"), /status 404 Not Found/); // edited from a scratch file, checked without the stored version, and what it adds reaches every check tcm("edit", "lib.http.augments"); fs.writeFileSync( scratch, fs .readFileSync(scratch, "utf8") .replace( "readonly status?: number;", "readonly status?: number;\n readonly retryAfter?: number;", ), ); tcm("update"); fs.writeFileSync( scratch, `// tcm: namespace app\nimport { annotate } from "#codebase/lib/schema";\nexport const busy = () => annotate({ status: 503, retryAfter: 30 }).retryAfter;\n`, ); tcm("add"); assert.match(tcm("run", "app.busy"), /30/); }