appParts
uses tcmts.cli.data_pages.dataTables, which uses tcmts.cli.data_pages.withStore, which uses node:path
What an app is made of, as tcm build plans it (and the editor's Apps view shows it): its code that runs in the
browser, the server functions the browser calls, the tables that server code reaches (each with its rows here), and,
in its namespace, its recurring jobs and its tests; what's wrong with its plan, if anything is.
import type { Codebase } from "#codebase/tcmts/cli/codebase"; import { dataTables } from "#codebase/tcmts/cli/data_pages"; import { isSchedule } from "#codebase/tcmts/cli/pages"; import type { Placement } from "#codebase/tcmts/cli/placement"; import { codebaseRoles } from "#codebase/tcmts/cli/roles"; import { isTestPath } from "#codebase/tcmts/cli/testing"; export function appParts( cb: Codebase, placement: Placement, hash: string, path: string, ): { browser: { path: string; place: string }[]; endpoints: { path: string; signature: string }[]; tables: { path: string; table: string; rows: number }[]; schedules: { path: string; spec: string }[]; tests: string[]; errors: string[]; } { const plan = placement.planApp(hash); const named = (hs: Iterable<string>) => [...hs] .flatMap((h) => (cb.store.pathsOf(h)[0] ? [{ h, path: cb.store.pathsOf(h)[0]! }] : [])) .sort((a, b) => a.path.localeCompare(b.path)); // the tables the server functions' code reaches const tables = new Map<string, string>(); const seen = new Set<string>(); const queue = [...plan.endpoints]; while (queue.length) { const h = queue.pop()!; if (seen.has(h)) continue; seen.add(h); const rec = cb.store.getDef(h); if (!rec) continue; if (rec.table && cb.store.pathsOf(h).length) tables.set(h, rec.table.name ?? cb.store.pathsOf(h)[0]!); for (const d of rec.deps) if (d.ref.startsWith("#")) queue.push(d.ref.slice(1)); } const rows = new Map(dataTables(cb).map((t) => [t.table, t.rows])); const ns = path.includes(".") ? path.slice(0, path.lastIndexOf(".") + 1) : ""; const inNs = cb.store .names() .filter((n) => n.path.startsWith(ns) && !n.path.slice(ns.length).includes(".")); const roles = codebaseRoles(cb); return { browser: named(plan.browser).map((x) => ({ path: x.path, place: placement.placeOf(x.h).place, })), endpoints: named(plan.endpoints).map((x) => { const rec = cb.store.getDef(x.h); return { path: x.path, signature: rec ? cb.store.shownSignature(rec) : "" }; }), tables: named(tables.keys()).map((x) => ({ path: x.path, table: tables.get(x.h)!, rows: rows.get(tables.get(x.h)!) ?? 0, })), schedules: inNs .filter( (n) => n.kind === "term" && roles.get(n.hash) !== "every" && !isTestPath(n.path) && isSchedule(cb.store.getDef(n.hash)!, roles), ) .map((n) => ({ path: n.path, spec: /every\(\s*(["'`])(.*?)\1/.exec(cb.store.getDef(n.hash)!.sourceText)?.[2] ?? "", })), tests: inNs .filter((n) => n.kind !== "type" && isTestPath(n.path)) .map((n) => n.path) .sort(), errors: plan.errors, }; }
uses
- tcmts.cli.codebase.Codebase
- tcmts.cli.data_pages.dataTables
- tcmts.cli.pages.isSchedule
- tcmts.cli.placement.Placement
- tcmts.cli.roles.codebaseRoles
- tcmts.cli.testing.isTestPath