testSignaturesFollowRenames

tcmts.cli.test.e2e.find.testSignaturesFollowRenames · #4w2izx2t · term

Signatures name types as they're named now: after tcm mv of a type, view, find, ls and what saving says show its new name, even in a signature that names it only because it's inferred, and in a class's.

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 testSignaturesFollowRenames = () => {
  const dir = tempDir("signatures");
  const ok = (...args: string[]) => okIn(dir, ...args);
  ok("init");
  fs.writeFileSync(
    path.join(dir, "scratch.ts"),
    `// tcm: namespace lib
export interface User { name: string; age: number }
export const nameOf = (u: User): string => u.name;
export const make = (name: string): User => ({ name, age: 0 });
export const guest = () => make("guest");
export const byName = (users: User[]): { User: User | undefined } => ({ User: users[0] });
export class Registry {
  users: User[] = [];
}
`,
  );
  ok("add");
  assert.match(ok("view", "lib.nameOf"), /: \(u: User\) => string/);

  ok("mv", "lib.User", "lib.Person");
  ok("mv", "lib.Registry", "lib.People");
  assert.match(ok("view", "lib.nameOf"), /: \(u: Person\) => string/);
  assert.match(ok("view", "lib.guest"), /: \(\) => Person/, "inferred, not in its code");
  // a property's name isn't a type's
  assert.match(
    ok("view", "lib.byName"),
    /: \(users: Person\[\]\) => \{ User: Person \| undefined; \}/,
  );
  assert.match(ok("view", "lib.People"), /typeof People/);
  const found = ok("find", "lib.");
  assert.match(found, /lib\.make .*\(name: string\) => Person/);
  assert.doesNotMatch(found, /=> User/);
  // find searches the signatures shown
  assert.match(ok("find", "=> Person"), /lib\.make/);
  assert.match(ok("find", ":(name: string) => Person"), /lib\.make .*\(name: string\) => Person/);
  assert.match(ok("ls", "lib"), /lib\.nameOf .*\(u: Person\) => string/);

  // changed after the rename, it's saved naming the type as it now is
  fs.writeFileSync(
    path.join(dir, "scratch.ts"),
    `// tcm: namespace lib
import type { Person } from "#codebase/lib";
export const nameOf = (u: Person): string => u.name.trim();
`,
  );
  ok("update");
  assert.match(ok("view", "lib.nameOf"), /: \(u: Person\) => string/);
  // saved beside the type as it's called now (so the checker prints that name), then renamed again
  fs.writeFileSync(
    path.join(dir, "scratch.ts"),
    `// tcm: namespace lib
export interface Person { name: string; age: number }
export const greet = (p: Person): string => "hi " + p.name;
`,
  );
  assert.match(ok("update"), /lib\.greet : \(p: Person\) => string/);
  ok("mv", "lib.Person", "lib.Human");
  assert.match(ok("view", "lib.greet"), /: \(p: Human\) => string/);
  assert.match(ok("view", "lib.nameOf"), /: \(u: Human\) => string/);
}

uses