testPackagesInEditor

tcmts.cli.test.e2e.lsp.testPackagesInEditor · #dtnjsspt · term

packages in the editor: the lock, what uses each package, a page with its README and API, upgrading

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 testPackagesInEditor = () => withChildren(async (keep) => {
  const dir5 = tempDir("lsp packages");
  const tcm = (...args: string[]) => spawnSync(process.execPath, [tcmBin(), ...args], { cwd: dir5, env: plainEnv(), encoding: "utf8" });
  tcm("init");
  // nothing installed: tcm provides ms
  fs.writeFileSync(path.join(dir5, "scratch.ts"), `// tcm: namespace time\nimport ms from "ms";\nexport const short = (n: number): string => ms(n);\n`);
  assert.equal(tcm("add").status, 0);
  spawnSync("sqlite3", [path.join(dir5, ".tcm", "codebase.sqlite"), "update packages set version = '2.1.1', integrity = null where name = 'ms'"]);

  const c = client(keep);
  await c.request("initialize", { processId: null, rootUri: pathToFileURL(dir5).href, capabilities: {}, clientInfo: { name: "Visual Studio Code" } });
  c.notify("initialized", {});
  const list = await c.request("tcm/packages", {});
  const ms = list.find((p: { name: string }) => p.name === "ms");
  assert.deepEqual(ms.ranges.map((r: { range: string; version: string; users: number; types?: string }) => [r.range, r.version, r.users, !!r.types]), [["2", "2.1.1", 1, true]]);
  assert.deepEqual((await c.request("tcm/packageUsers", { name: "ms", range: "2" })).map((u: { path: string }) => u.path), ["time.short"]);

  const page = await c.request("tcm/packagePage", { name: "ms", range: "2" });
  assert.equal(page.version, "2.1.1");
  assert.match(page.readme, /^# ms/m, "the package's README");
  assert.ok(page.api.some((a: { name: string; kind: string }) => a.name === "default" && a.kind === "function"), "its API, from its types");
  // signatures come highlighted, as a definition page's code does
  assert.ok(page.api.some((a: { html: string }) => /<span class="k">/.test(a.html)), "its API's signatures, highlighted");
  assert.equal(page.users[0].uri, pathToFileURL(path.join(dir5, ".tcm", "src", "time", "short.ts")).href);

  // oxlint's findings are diagnostics in scratch files, beside tcm's own
  const lintFile = path.join(dir5, "lint.ts");
  const lintText = `export const f = (n: number): number => {\n  debugger;\n  return n;\n};\n`;
  fs.writeFileSync(lintFile, lintText);
  c.notify("textDocument/didOpen", { textDocument: { uri: pathToFileURL(lintFile).href, languageId: "typescript", version: 1, text: lintText } });
  const linted = await c.waitFor(() =>
    c.notes.find((n) => n.method === "textDocument/publishDiagnostics" && n.params.uri === pathToFileURL(lintFile).href && n.params.diagnostics.some((d: { source: string }) => d.source === "oxlint")),
  );
  const d = linted.params.diagnostics.find((x: { source: string }) => x.source === "oxlint");
  assert.equal(d.code, "eslint(no-debugger)");
  assert.deepEqual(d.range.start, { line: 1, character: 2 });
  assert.match(d.codeDescription.href, /oxc\.rs/);

  // oxfmt: formatting a scratch file as it's saved, and Format Document
  const messy = `export const g=(n:number)=>{return n}\n`;
  c.notify("textDocument/didChange", { textDocument: { uri: pathToFileURL(lintFile).href, version: 2 }, contentChanges: [{ text: messy }] });
  const onSave = await c.request("textDocument/willSaveWaitUntil", { textDocument: { uri: pathToFileURL(lintFile).href }, reason: 1 });
  assert.equal(onSave[0].newText, "export const g = (n: number) => {\n  return n;\n};\n");
  assert.deepEqual(await c.request("textDocument/formatting", { textDocument: { uri: pathToFileURL(lintFile).href }, options: { tabSize: 2, insertSpaces: true } }), onSave);

  const upgraded = await c.request("workspace/executeCommand", { command: "tcm.upgrade", arguments: ["ms"] });
  assert.equal(upgraded, true);
  assert.notEqual((await c.request("tcm/packages", {})).find((p: { name: string }) => p.name === "ms").ranges[0].version, "2.1.1");
  c.child.kill();
})

uses