testTypesDontPlaceCode
Types are erased: a global named only in them (a parameter's type, as HTMLElement, a variable's type, a type
argument, typeof window in a type, a type or interface declared inside the code) doesn't run, so it doesn't place
the code in the browser or on the server, or give it effects. Used as a value (read, called, new, instanceof,
typeof x as an expression), it still does.
import { reaches } from "#codebase/tcmts/cli/effects"; import { Placement } from "#codebase/tcmts/cli/placement"; import { codebaseOf } from "#codebase/tcmts/cli/test/shapes"; import { analyzeFile } from "#codebase/tcmts/core/analyze"; import { compilerOptions } from "#codebase/tcmts/core/program"; import assert from "node:assert/strict"; import fs from "node:fs"; import os from "node:os"; import path from "node:path"; export const testTypesDontPlaceCode = () => { const dir = fs.mkdtempSync(path.join(os.tmpdir(), "tcm types ")); fs.writeFileSync(path.join(dir, "package.json"), JSON.stringify({ type: "module" })); const file = path.join(dir, "types.ts"); fs.writeFileSync( file, `import type { Stats } from "node:fs"; export const measure = (el: Element) => el.getBoundingClientRect().width; export const cast = (x: unknown) => (x as HTMLElement).id; export function count() { let n: Node | undefined; return n ? 1 : 0; } export const listOf = () => new Array<HTMLDivElement>().length; export const windowed = (w: { win?: typeof window }) => !!w.win; export const local = () => { type E = Element; interface I { e?: HTMLElement; f?: E } const x: I = {}; return x.e ? 1 : 0; }; export const bytes = (b: Buffer) => b.length; export const proc = (p: typeof process) => p.pid; export const statted = (s: Stats) => s.size; export const when = (d: Date) => d.getTime(); export const body = () => document.body; export const observe = () => new IntersectionObserver(() => {}); export const isElement = (x: unknown) => x instanceof HTMLElement; export const hasWindow = () => typeof window !== "undefined"; export const buffered = () => Buffer.from("x"); export const now = () => new Date(); `, ); const analyzed = analyzeFile(file, { cacheDir: path.join(dir, ".tcm", "cache"), resolveName: (name) => { throw new Error(`unknown ${name}`); }, compilerOptions: { ...compilerOptions(), lib: ["lib.esnext.d.ts", "lib.dom.d.ts"] }, }); assert.deepEqual([...analyzed.errors, ...analyzed.diagnostics.map((d) => d.message)], []); const cb = codebaseOf(analyzed.defs); const hash = new Map(analyzed.defs.map((d) => [d.nameHint, d.hash])); const names = [...hash.keys()].sort(); const placement = new Placement(cb); const effects = reaches(cb, [...hash.values()]); const seen = Object.fromEntries( names.map((n) => [ n, `${placement.placeOf(hash.get(n)!).place} ${effects.get(hash.get(n)!)!.join(",")}`.trim(), ]), ); assert.deepEqual(seen, { body: "browser environment", buffered: "server", bytes: "anywhere", cast: "anywhere", count: "anywhere", hasWindow: "browser environment", isElement: "browser", listOf: "anywhere", local: "anywhere", measure: "anywhere", now: "anywhere clock", observe: "browser", proc: "anywhere", statted: "anywhere", when: "anywhere", windowed: "anywhere", }); }