testStackTracesPointAtDefinitions

tcmts.cli.test.e2e.debug.testStackTracesPointAtDefinitions · #oeyqilvr · term

Stack traces point at definitions: their files in .tcm/src, or the scratch file.

import { tcmIn, 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 testStackTracesPointAtDefinitions = () => {
  const dir = tempDir("debug");
  const run = (...args: string[]) => tcmIn(dir, ...args).out;
  const write = (file: string, text: string) => fs.writeFileSync(path.join(dir, file), text);
  const src = (file: string) => path.join(dir, ".tcm", "src", file);
  run("init");
  fs.rmSync(path.join(dir, "scratch.ts"));
  write("lib.ts", `// tcm: namespace lib\n/** Halves. */\nexport function half(n: number): number {\n  if (n < 0) {\n    throw new Error("negative");\n  }\n  return n / 2;\n}\nexport const main = () => half(-1);\n`);
  run("add", "lib.ts");
  // each definition is a file, exactly as the editor shows it
  const view = fs.readFileSync(src("lib/half.ts"), "utf8");
  assert.match(view, /^\/\/ lib\.half #\w+\n\/\*\*\n \* Halves\.\n \*\/\nexport function half\(n: number\): number \{/);

  const out = run("run", "lib.main");
  assert.ok(out.includes(`at half (${src("lib/half.ts")}:7:11)`), out);
  assert.ok(out.includes(`at main (${src("lib/main.ts")}:4:27)`), "past the `export ` the view adds");

  // code tcm compiles itself (JSX) keeps its map through the compilation
  write("ui.tsx", `// tcm: namespace ui\nexport function Card({ n }: { n: number }) {\n  if (n < 0) {\n    throw new Error("bad card");\n  }\n  return <p>{n}</p>;\n}\nexport const show = () => Card({ n: -1 });\n`);
  run("add", "ui.tsx");
  assert.ok(run("run", "ui.show").includes(`at Card (${src("ui/Card.tsx")}:4:11)`));

  // code not saved yet points at its scratch file
  write("scratch.ts", `import { half } from "#codebase/lib";\n\nexport const quarter = (n: number): number => {\n  return half(half(n));\n};\n\nquarter(-4);\n`);
  const checked = run("check", "--fresh");
  assert.ok(checked.includes(`at quarter (${path.join(dir, "scratch.ts")}:4:10)`), checked);

  // the files follow names
  run("mv", "lib.half", "lib.halve");
  assert.ok(fs.existsSync(src("lib/halve.ts")) && !fs.existsSync(src("lib/half.ts")));
  assert.ok(run("run", "lib.main").includes(`at half (${src("lib/halve.ts")}:7:11)`), "a renamed definition's file, its runtime name unchanged");
}

uses