matchLibraries

tcmts.hub.matchLibraries · #q3w2m2br · term · runs on the server

uses tcmts.cli.search.searchByType, which uses node:path

What matches q in each of shown (libraries mirrored in s's codebase): by name, words in docs, or a type, as tcm find does, but each name as its library shows it (geo.area, not where the hub mounts it). by says which (name: names, then docs where no name matches; docs: docs alone; type); without it, a type if q looks like one, names otherwise. Its own definitions only: not what it holds, nor its tests. Each library with what matches in it, best match first; the libraries by their best match, then most used. A type's near matches (more general, or more specific) are close; a definition whose code, or what it uses, reaches outside the codebase (or that uses a package that does) reaches.

import { reaches } from "#codebase/tcmts/cli/effects";
import { docSummary, looksLikeType, nameScore } from "#codebase/tcmts/cli/pages";
import { searchByType } from "#codebase/tcmts/cli/search";
import { isTestPath } from "#codebase/tcmts/cli/testing";
import type { Library, LibraryHits } from "#codebase/tcmts/hub";
import { codeHref } from "#codebase/tcmts/share";
import type { Share } from "#codebase/tcmts/share";

export function matchLibraries(
  s: Pick<Share, "cb" | "cache">,
  shown: Library[],
  q: string,
  by?: string,
): LibraryHits[] {
  const query = q.trim();
  if (!query) return [];
  const cb = s.cb;
  const placement = s.cache.placement(cb);
  // (a library's own name for it, or nothing: what it holds, its record, its tests and their helpers aren't searched)
  const ownName = (l: Library, path: string) => {
    const mount = l.latest.mount!;
    if (!path.startsWith(`${mount}.`)) return undefined;
    const rel = path.slice(mount.length + 1);
    if (rel.startsWith("lib.") || rel === "libraries") return undefined;
    if (isTestPath(rel) || rel.split(".").includes("test")) return undefined;
    return rel;
  };
  type Scored = {
    l: Library;
    rel: string;
    path: string;
    hash: string;
    score: number;
    detail?: string;
    close?: boolean;
  };
  const scored: Scored[] = [];
  const mode =
    by === "name" || by === "docs" || by === "type" ? by : looksLikeType(query) ? "type" : "name";
  if (mode === "type") {
    let hits: ReturnType<typeof searchByType>["hits"] = [];
    try {
      hits = searchByType(cb, query.replace(/^:/, "")).hits;
    } catch {
      return [];
    }
    for (const h of hits)
      for (const l of shown) {
        const rel = ownName(l, h.path);
        if (rel !== undefined)
          scored.push({
            l,
            rel,
            path: h.path,
            hash: h.hash,
            score: -h.cost,
            detail: h.notes.join(", ") || "same type",
            ...(h.notes.length ? { close: true } : {}),
          });
      }
  } else {
    const lower = query.toLowerCase();
    for (const l of shown)
      for (const row of cb.store.namespaceRows(l.latest.namespace)) {
        const path = `${l.latest.mount}.${row.path}`;
        const rel = ownName(l, path);
        if (rel === undefined) continue;
        const name = mode === "docs" ? 0 : nameScore(lower, `${l.package}.${rel}`);
        const doc = name
          ? 0
          : cb.store.getDef(row.hash)?.doc?.toLowerCase().includes(lower)
            ? 20
            : 0;
        if (name || doc) scored.push({ l, rel, path, hash: row.hash, score: Math.max(name, doc) });
      }
  }
  const groups = new Map<Library, Scored[]>();
  for (const x of scored) groups.set(x.l, [...(groups.get(x.l) ?? []), x]);
  const best = (xs: Scored[]) => Math.max(...xs.map((x) => x.score));
  return [...groups]
    .sort(
      ([a, xs], [b, ys]) =>
        best(ys) - best(xs) || b.dependents - a.dependents || a.package.localeCompare(b.package),
    )
    .map(([l, xs]) => ({
      l,
      hits: xs
        .sort((a, b) => b.score - a.score || (a.rel < b.rel ? -1 : 1))
        .map((x) => {
          const rec = cb.store.getDef(x.hash)!;
          const place = rec.kind === "term" ? placement.placeOf(x.hash).place : undefined;
          // (its code and what it uses, by hash; and a package's, as the library's facts say)
          const out =
            rec.kind === "term" &&
            ((reaches(cb, [x.hash]).get(x.hash)?.length ?? 0) > 0 ||
              Object.values(l.latest.facts?.effects ?? {}).some((names) =>
                names?.some((n) => n.startsWith(`${x.rel} (`)),
              ));
          return {
            name: `${l.package}.${x.rel}`,
            path: x.path,
            href: codeHref(x.path),
            signature:
              rec.kind === "file"
                ? "file"
                : rec.kind === "type"
                  ? "type"
                  : cb.store.shownSignature(rec),
            detail: x.detail ?? docSummary(rec) ?? "",
            ...(place ? { place } : {}),
            ...(x.close ? { close: true } : {}),
            ...(out ? { reaches: true } : {}),
          };
        }),
    }));
}

uses

used by