/** * Reconciliation source for the icon/colour coverage gate (Task 1965). * * The colour/icon registries in ../index.ts are hand-maintained. This module * assembles the set of labels that can actually appear as a graph node from the * three authoritative sources, so icons.test.ts can reconcile the registries * against the ontology instead of against themselves: * * 1. The `Neo4j Label` column of every node-type table in the vertical schema * docs (plugins/memory/references/schema-*.md). * 2. Every sourceLabel / targetLabel in the typed-edge registry * (plugins/memory/mcp/src/lib/typed-edge-schema.ts). * 3. CODE_EMITTED_NODE_LABELS — labels written by code with no schema-table * row and no typed-edge declaration (e.g. FileArtifact). * * Test-only: it reads source files with node:fs, so it must never be imported * from the browser bundle. It lives under __tests__ for that reason. */ import { readdirSync, readFileSync } from 'node:fs' import { dirname, join } from 'node:path' import { fileURLToPath } from 'node:url' import { CODE_EMITTED_NODE_LABELS } from '../index.js' const HERE = dirname(fileURLToPath(import.meta.url)) // __tests__ -> src -> graph-style -> lib -> platform const PLATFORM = join(HERE, '..', '..', '..', '..') const SCHEMA_DIR = join(PLATFORM, 'plugins', 'memory', 'references') const TYPED_EDGE_FILE = join( PLATFORM, 'plugins', 'memory', 'mcp', 'src', 'lib', 'typed-edge-schema.ts', ) /** 2nd backticked column of a markdown node-type table row: `| Concept | `Label` | ...`. */ const SCHEMA_LABEL_RE = /^\|[^|]*\|\s*`([A-Z][A-Za-z]+)`\s*\|/gm /** sourceLabel: "Label" / targetLabel: "Label" in the typed-edge registry. */ const TYPED_EDGE_LABEL_RE = /(?:sourceLabel|targetLabel): "([A-Z][A-Za-z]+)"/g function schemaLabels(): Set { const out = new Set() for (const file of readdirSync(SCHEMA_DIR)) { if (!/^schema-.*\.md$/.test(file)) continue const text = readFileSync(join(SCHEMA_DIR, file), 'utf8') for (const m of text.matchAll(SCHEMA_LABEL_RE)) out.add(m[1]) } return out } function typedEdgeLabels(): Set { const text = readFileSync(TYPED_EDGE_FILE, 'utf8') const out = new Set() for (const m of text.matchAll(TYPED_EDGE_LABEL_RE)) out.add(m[1]) return out } /** * The union of every label that can appear as a standalone graph node. Callers * subtract ADDITIONAL_BASE_LABELS (labels that only ever stack on a base node) * before asserting colour/icon coverage. */ export function assembleNodeLabelUniverse(): Set { const out = new Set() for (const l of schemaLabels()) out.add(l) for (const l of typedEdgeLabels()) out.add(l) for (const l of CODE_EMITTED_NODE_LABELS) out.add(l) return out }