testTypesDontPlaceCode

tcmts.cli.placement.testTypesDontPlaceCode · #uhj4phgi · term

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",
  });
}

uses