searchByType

tcmts.cli.search.searchByType · #6swb6qwz · term · runs on the server

uses node:path

Terms whose type has the query's shape. Codebase types in the query are found by name; names that aren't types become type variables. Exact matches (up to renaming) come first, then ones with arguments reordered, a Promise result, or a more general or more specific type.

import type { Codebase } from "#codebase/tcmts/cli/codebase";
import { MAX_MATCH_COST } from "#codebase/tcmts/cli/search";
import type { TypeHit } from "#codebase/tcmts/cli/search";
import { matchShapes, queryShape } from "#codebase/tcmts/core/shape";
import path_1 from "node:path";

export function searchByType(cb: Codebase, text: string): { variables: string[]; hits: TypeHit[] } {
  if (!text.trim()) throw new Error("find :<type>, e.g. tcm find ':(xs: T[]) => T'");
  const names = cb.store.names();
  const types = names.filter((n) => n.kind !== "term");
  const resolve = (name: string) => {
    const hits = types.filter((n) => n.path === name || n.path.endsWith(`.${name}`));
    const exact = hits.filter((n) => n.path === name);
    const paths = [...new Set((exact.length ? exact : hits).map((n) => n.path))];
    if (paths.length > 1)
      throw new Error(
        `'${name}' in the query could be ${paths.join(", ")}; write the one you mean`,
      );
    if (!paths.length) return undefined;
    const segs = paths[0]!.split(".");
    return { module: ["#codebase", ...segs.slice(0, -1)].join("/"), export: segs.at(-1)! };
  };
  cb.refreshShim();
  const q = queryShape(text, path_1.join(cb.lay.tcmDir, "query.ts"), cb.compilerOptions(), resolve);
  const terms = names.filter((n) => n.kind === "term");
  // (received code comes without shapes: worked out the first time a search needs them)
  cb.fillShapes(terms.map((n) => n.hash));
  const hits = terms
    .map((n) => {
      const def = cb.store.getDef(n.hash)!;
      const m = def.shape ? matchShapes(q.shape, def.shape) : undefined;
      return m && m.cost <= MAX_MATCH_COST
        ? {
            path: n.path,
            hash: n.hash,
            signature: cb.store.shownSignature(def),
            cost: m.cost,
            notes: m.notes,
          }
        : undefined;
    })
    .filter((h): h is TypeHit => !!h)
    .sort((a, b) => a.cost - b.cost || (a.path < b.path ? -1 : 1));
  return { variables: q.variables, hits };
}

uses

used by