Files
Aura/crates/aura-cli/tests/viewer_name_prefix.mjs
Brummel 0ae8320d14 feat(aura): surface explicit node instance name in the graph viewer
A leaf primitive built with `.named("fast")` now renders its `aura graph` viewer
box head as `fast: SMA[length]` — the instance name as a `:` declaration prefix.
An unnamed leaf keeps the bare `SMA[length]`.

Engine half: a new raw `PrimitiveBuilder::instance_name() -> Option<&str>` (the
explicit name, default not resolved) feeds a conditional leading `"name"` field
in prim_record, present only for an explicitly-named node; both golden twins
(inline model_golden + sample-model.json) re-captured. Viewer half: adaptNodes
carries `name`, the genDot leaf-emit forwards it, and cellLabel prepends the
`name: ` prefix when present (composites stay bare). `named()`'s non-empty
debug_assert is unchanged, its doc re-grounded to the now load-bearing Some/None
invariant (knob-address segment + prefix switch).

The name is a render/model-only debug symbol — dropped at lowering (C23), and the
model stays deterministic (C14). Parameter ganging (one knob, several nodes) was
considered and spun off as an explicit composite-shared-param idea (#61), not via
name collision (param_space is injective, C12/C19).

closes #58
2026-06-13 19:02:16 +02:00

63 lines
2.7 KiB
JavaScript

// Headless render guard for the `aura graph` viewer (graph-viewer.js).
//
// Property protected: a leaf primitive built with an explicit instance name
// renders a `name: ` declaration prefix immediately ahead of the bold type head
// (`fast: SMA…`); an UNNAMED leaf renders the bare type head, no prefix.
//
// It loads the *real* viewer module (so a fix or a regression there is observed
// here) and drives the exported pure `genDot` over a minimal root model with one
// named leaf (SMA, name "fast") and one unnamed leaf (Sub) — exercising the
// genDot leaf-emit + cellLabel prefix path directly, no composite expand needed.
import { createRequire } from "node:module";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
const require = createRequire(import.meta.url);
const here = dirname(fileURLToPath(import.meta.url));
const model = {
root: {
nodes: {
"0": { prim: { name: "fast", type: "SMA", role: "node", params: [["length", "i64"]], ins: [["f64", "any", "series"]], outs: [["value", "f64"]] } },
"1": { prim: { type: "Sub", role: "node", params: [], ins: [["f64", "any", "lhs"], ["f64", "any", "rhs"]], outs: [["value", "f64"]] } },
},
edges: [["0.o0", "1.i0"]],
},
composites: {},
};
// genDot closes over module-scoped ROOT/COMP derived from window.AURA_MODEL at
// load. Stub the global BEFORE requiring the viewer (mirrors the browser).
global.window = { AURA_MODEL: model };
const { normalizeModel, genDot } = require(join(here, "..", "assets", "graph-viewer.js"));
const ROOT = normalizeModel(model).root;
const { dot } = genDot(ROOT, "root", new Set(), false);
// The named leaf renders `fast: ` (colon + one trailing space, no leading space)
// contiguously ahead of the bold SMA type head.
const NAMED = '<font color="#cdd6f4">fast</font><font color="#9399b2">: </font><font color="#f5f5f5"><b>SMA</b></font>';
if (!dot.includes(NAMED)) {
console.error(
"named leaf missing the `fast: ` prefix before the SMA head.\n--- dot ---\n" + dot
);
process.exit(1);
}
// Exactly ONE name prefix in the whole graph: the named SMA leg. The `: `
// separator font (#9399b2 colon-space) is unique to the prefix at showTypes=false
// (sig uses `[`/`]`/`, `, never `: `), so it appears once — the unnamed Sub has
// no prefix.
const SEP = '<font color="#9399b2">: </font>';
const sepCount = dot.split(SEP).length - 1;
if (sepCount !== 1) {
console.error(
`expected exactly 1 name prefix (the named leaf), found ${sepCount} — ` +
"an unnamed leaf must render no prefix.\n--- dot ---\n" + dot
);
process.exit(1);
}
console.log("OK — named leaf renders `fast: ` prefix; unnamed leaf stays bare.");
process.exit(0);