testPages

tcmts.cli.test.e2e.lsp.testPages · #id7vybbb · term

pages: a definition's rendered doc and linked source, a namespace's README, and the finder

import { plainEnv, tcmBin, tempDir, withChildren } from "#codebase/tcmts/cli/test/e2e/harness";
import { client } from "#codebase/tcmts/cli/test/e2e/lsp";
import assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
import { pathToFileURL } from "node:url";

export const testPages = () => withChildren(async (keep) => {
  const dir4 = tempDir("lsp4");
  const tcm = (...args: string[]) => spawnSync(process.execPath, [tcmBin(), ...args], { cwd: dir4, env: plainEnv(), encoding: "utf8" });
  tcm("init");
  fs.writeFileSync(
    path.join(dir4, "scratch.ts"),
    `// tcm: namespace geo
/** A point on the plane. */
export type Point = { x: number; y: number };
/**
 * Distance between two {@link Point}s.
 *
 * \`\`\`ts
 * dist({ x: 0, y: 0 }, { x: 3, y: 4 })
 * \`\`\`
 */
export const dist = (a: Point, b: Point): number => Math.hypot(a.x - b.x, a.y - b.y);
/** Around the outside: the sum of each side's {@link dist}. */
export const perimeter = (ps: Point[]): number => ps.reduce((n, p, i) => n + dist(p, ps[(i + 1) % ps.length]!), 0);
/**
 * # Geometry
 *
 * Points and distances. Start with {@link dist}.
 */
export type README = never;
`,
  );
  assert.equal(tcm("add").status, 0);
  // and a page, kept as written, linking to code
  fs.writeFileSync(path.join(dir4, "guide.md"), "<!-- tcm: namespace geo -->\n# Guide\n\nMeasure with {@link dist}.\n");
  assert.equal(tcm("add", "guide.md").status, 0);
  const dist = spawnSync("sqlite3", [path.join(dir4, ".tcm", "codebase.sqlite"), "select hash from names where path = 'geo.dist'"], { encoding: "utf8" }).stdout.trim();
  const pointHash = spawnSync("sqlite3", [path.join(dir4, ".tcm", "codebase.sqlite"), "select hash from names where path = 'geo.Point'"], { encoding: "utf8" }).stdout.trim();

  const c = client(keep);
  await c.request("initialize", { processId: null, rootUri: pathToFileURL(dir4).href, capabilities: {}, clientInfo: { name: "Visual Studio Code" } });
  c.notify("initialized", {});

  // a definition's page: rendered doc (links by hash, the example evaluated), source with references as links
  const page = await c.request("tcm/page", { path: "geo.dist" });
  assert.equal(page.hash, dist);
  assert.deepEqual(page.names, ["geo.dist"]);
  assert.match(page.docMarkdown, new RegExp(`Distance between two \\[\`Point\`\\]\\(tcm-page:${pointHash}\\)s\\.`));
  assert.match(page.docMarkdown, /```text\n⧩ 5\n```/);
  assert.match(page.sourceHtml, new RegExp(`<a class="ref t" data-hash="${pointHash}">Point</a>`));
  assert.match(page.sourceHtml, /<span class="k">const<\/span>/);
  // its imports link too: what each brings in, and the namespace it's from
  assert.match(page.sourceHtml, /<a class="ref s" data-namespace="geo">&quot;#codebase\/geo&quot;<\/a>/);
  assert.equal(page.sourceHtml.split(`data-hash="${pointHash}">Point</a>`).length - 1, 3, "Point in the import, and in both parameters");
  assert.deepEqual(page.uses.map((u: any) => u.name), ["geo.Point"]);
  // (the page linking to it uses it too)
  assert.deepEqual(page.usedBy.map((u: any) => u.name), ["geo.guide", "geo.perimeter"]);

  // files are in the tree, with pages of their own: Markdown rendered, its links to code opening their pages
  const tree = await c.request("tcm/tree", { namespace: "geo" });
  assert.ok(tree.definitions.some((d: any) => d.name === "guide" && d.kind === "file" && d.role === "file"), JSON.stringify(tree.definitions));
  const guide = await c.request("tcm/page", { path: "geo.guide" });
  assert.equal(guide.kind, "file");
  assert.equal(guide.format, "md");
  assert.match(guide.docMarkdown, new RegExp(`Measure with \\[\`geo\\.dist\`\\]\\(tcm-page:${dist}\\)`));

  // a namespace's page: its README rendered, then what's in it by role
  const ns = await c.request("tcm/namespace", { namespace: "geo" });
  assert.match(ns.readme, /^# Geometry\n\nPoints and distances\. Start with \[`dist`\]\(tcm-page:/);
  assert.deepEqual(ns.definitions.map((d: any) => [d.name, d.role]), [["Point", "type"], ["dist", "shared"], ["guide", "file"], ["perimeter", "shared"]]);
  assert.equal(ns.definitions[0].summary, "A point on the plane.");

  // the finder: names (best first), words in docs, and types
  const byName = await c.request("tcm/find", { query: "dist" });
  assert.equal(byName[0].path, "geo.dist");
  const byDoc = await c.request("tcm/find", { query: "outside" });
  assert.deepEqual(byDoc.map((i: any) => [i.path, i.match]), [["geo.perimeter", "doc"]]);
  const byType = await c.request("tcm/find", { query: "(a: Point, b: Point) => number" });
  assert.deepEqual(byType.map((i: any) => [i.path, i.match]), [["geo.dist", "type"]]);
})

uses