lintDefinitions
uses node:crypto
Lint stored definitions, as tcm view shows them (current names, imports, export), cached by hash and the
linter's version and configuration. fresh lints again regardless.
import type { Codebase } from "#codebase/tcmts/cli/codebase"; import { apartFromItsCycle, configFor, lintTexts } from "#codebase/tcmts/cli/lint"; import type { DefinitionLint, LintIssue, LintTraits } from "#codebase/tcmts/cli/lint"; import { isTestPath } from "#codebase/tcmts/cli/testing"; import { render } from "#codebase/tcmts/loader"; import { createHash } from "node:crypto"; export function lintDefinitions( cb: Codebase, targets: { hash: string; path: string }[], fresh = false, ): DefinitionLint[] { const src = cb.source(); const out: DefinitionLint[] = []; const pending = new Map< string, { hash: string; path: string; text: string; ext: string; traits: LintTraits; key: string }[] >(); for (const t of targets) { const rec = src.get(t.hash); if (!rec || rec.kind === "type") continue; const text = render([rec], src, cb.lay, { style: "scratch", exportDeclarations: true }).text; const traits: LintTraits = { jsx: !!rec.jsx, tests: isTestPath(t.path), node: rec.spans.some((s) => s.ext?.module.startsWith("node:")), }; // findings depend on the text as well as the code: names (an unused `_x`) and comments (`eslint-disable`), which // a hash doesn't cover const key = `${configFor(cb, traits).key} ${createHash("sha256").update(text).digest("hex").slice(0, 16)}`; const hit = fresh ? undefined : cb.store.lintResult(t.hash, key); if (hit !== undefined) { out.push({ ...t, text, issues: JSON.parse(hit) as LintIssue[], cached: true }); continue; } const group = JSON.stringify(traits); pending.set(group, [ ...(pending.get(group) ?? []), { ...t, text, ext: rec.jsx ? ".tsx" : ".ts", traits, key }, ]); } for (const items of pending.values()) { const results = lintTexts(cb, items, items[0]!.traits); items.forEach((item, i) => { // (what only comes of linting it apart from the definitions it's one module with isn't kept) const rec = src.get(item.hash)!; const mates = new Set( cb.store .componentMembers(rec.componentHash) .filter((m) => m.hash !== item.hash) .map((m) => (src.nameOf(m.hash) ?? m.nameHint).split(".").pop()!), ); const issues = results[i]!.filter((issue) => !apartFromItsCycle(issue, item.text, mates)); cb.store.putLintResult(item.hash, item.key, JSON.stringify(issues)); out.push({ hash: item.hash, path: item.path, text: item.text, issues, cached: false }); }); } return out.sort((a, b) => (a.path < b.path ? -1 : 1)); }
uses
- tcmts.cli.codebase.Codebase
- tcmts.cli.lint.DefinitionLint
- tcmts.cli.lint.LintIssue
- tcmts.cli.lint.LintTraits
- tcmts.cli.lint.apartFromItsCycle
- tcmts.cli.lint.configFor
- tcmts.cli.lint.lintTexts
- tcmts.cli.testing.isTestPath
- tcmts.loader.render