@milehimikey/em 1.9.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/event-modeling/SKILL.md +1 -1
- package/.claude/skills/event-modeling-conform/SKILL.md +1 -1
- package/.claude/skills/event-modeling-conform/reference/conform.md +1 -1
- package/.claude/skills/event-modeling-design/SKILL.md +3 -3
- package/.claude/skills/event-modeling-discover/SKILL.md +1 -1
- package/.claude/skills/event-modeling-implement/SKILL.md +1 -1
- package/.claude/skills/event-modeling-review/SKILL.md +1 -1
- package/.claude/skills/event-modeling-shared/reference/em-dsl.md +47 -2
- package/.claude/skills/event-modeling-shared/reference/operating-principles.md +4 -1
- package/.claude/skills/event-modeling-shared/reference/slice-doc-schema.md +381 -0
- package/.claude/skills/event-modeling-shared/templates/slice.md +7 -7
- package/README.md +8 -1
- package/dist/cli/ciInit.d.ts +10 -3
- package/dist/cli/ciInit.js +22 -14
- package/dist/cli/ciInit.js.map +1 -1
- package/dist/cli/systemInputs.d.ts +34 -0
- package/dist/cli/systemInputs.js +129 -0
- package/dist/cli/systemInputs.js.map +1 -0
- package/dist/cli.js +222 -7
- package/dist/cli.js.map +1 -1
- package/dist/emit/json.d.ts +16 -1
- package/dist/emit/json.js +36 -1
- package/dist/emit/json.js.map +1 -1
- package/dist/emit/queryJson.d.ts +6 -0
- package/dist/emit/queryJson.js +29 -0
- package/dist/emit/queryJson.js.map +1 -0
- package/dist/emit/systemJson.d.ts +8 -0
- package/dist/emit/systemJson.js +38 -0
- package/dist/emit/systemJson.js.map +1 -0
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.js +185 -6
- package/dist/mcp/server.js.map +1 -1
- package/dist/model/edges.d.ts +13 -1
- package/dist/model/edges.js +43 -15
- package/dist/model/edges.js.map +1 -1
- package/dist/model/model.d.ts +2 -0
- package/dist/model/model.js +1 -0
- package/dist/model/model.js.map +1 -1
- package/dist/model/qualifiedRef.d.ts +47 -0
- package/dist/model/qualifiedRef.js +100 -0
- package/dist/model/qualifiedRef.js.map +1 -0
- package/dist/model/queryIndex.d.ts +50 -0
- package/dist/model/queryIndex.js +111 -0
- package/dist/model/queryIndex.js.map +1 -0
- package/dist/model/rules.d.ts +69 -0
- package/dist/model/rules.js +82 -0
- package/dist/model/rules.js.map +1 -1
- package/dist/model/sliceDocIndex.d.ts +30 -0
- package/dist/model/sliceDocIndex.js +110 -0
- package/dist/model/sliceDocIndex.js.map +1 -0
- package/dist/model/validate.js +4 -11
- package/dist/model/validate.js.map +1 -1
- package/dist/parser/ast.d.ts +4 -0
- package/dist/parser/parser.d.ts +2 -0
- package/dist/parser/parser.js +8 -2
- package/dist/parser/parser.js.map +1 -1
- package/dist/query/format.d.ts +8 -0
- package/dist/query/format.js +80 -0
- package/dist/query/format.js.map +1 -0
- package/dist/query/pipeline.d.ts +17 -0
- package/dist/query/pipeline.js +38 -0
- package/dist/query/pipeline.js.map +1 -0
- package/dist/query/system.d.ts +60 -0
- package/dist/query/system.js +87 -0
- package/dist/query/system.js.map +1 -0
- package/dist/query/verbs.d.ts +100 -0
- package/dist/query/verbs.js +306 -0
- package/dist/query/verbs.js.map +1 -0
- package/dist/render/drawEdges.js +8 -4
- package/dist/render/drawEdges.js.map +1 -1
- package/dist/render/sliceDiagram.js +1 -0
- package/dist/render/sliceDiagram.js.map +1 -1
- package/dist/system/manifest.d.ts +45 -0
- package/dist/system/manifest.js +178 -0
- package/dist/system/manifest.js.map +1 -0
- package/dist/system/verify.d.ts +88 -0
- package/dist/system/verify.js +263 -0
- package/dist/system/verify.js.map +1 -0
- package/dist/util/slug.js +16 -10
- package/dist/util/slug.js.map +1 -1
- package/package.json +10 -1
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ConsumerEntry, ProducerEntry, ClosureEntry, SliceQueryEntry, InvariantQueryEntry, FieldQueryEntry, PathQueryEntry } from "./verbs.js";
|
|
2
|
+
export declare function formatConsumers(results: ConsumerEntry[]): string;
|
|
3
|
+
export declare function formatProducers(results: ProducerEntry[]): string;
|
|
4
|
+
export declare function formatClosure(results: ClosureEntry[]): string;
|
|
5
|
+
export declare function formatSlices(results: SliceQueryEntry[]): string;
|
|
6
|
+
export declare function formatInvariant(results: InvariantQueryEntry[]): string;
|
|
7
|
+
export declare function formatField(results: FieldQueryEntry[]): string;
|
|
8
|
+
export declare function formatPath(results: PathQueryEntry[]): string;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Human-text formatting for `em query`'s eight verbs (the default output — `--json` bypasses
|
|
3
|
+
// this entirely and prints `emit/queryJson.ts`'s document instead). An empty `results` array
|
|
4
|
+
// always prints a bare `(none)` line and still exits 0 — a query with a legitimately empty
|
|
5
|
+
// answer (an event nobody consumes, two elements with no path between them) is not an error.
|
|
6
|
+
function tagList(label, items) {
|
|
7
|
+
return items.length > 0 ? ` ${label}=[${items.join(", ")}]` : "";
|
|
8
|
+
}
|
|
9
|
+
export function formatConsumers(results) {
|
|
10
|
+
if (results.length === 0)
|
|
11
|
+
return "(none)";
|
|
12
|
+
return results.map((r) => `${r.ref} (${r.kind}) in slice "${r.sliceName}" [${r.sliceKey}] — via ${r.via}`).join("\n");
|
|
13
|
+
}
|
|
14
|
+
export function formatProducers(results) {
|
|
15
|
+
if (results.length === 0)
|
|
16
|
+
return "(none)";
|
|
17
|
+
const lines = [];
|
|
18
|
+
for (const r of results) {
|
|
19
|
+
lines.push(`${r.ref} (${r.kind}) in slice "${r.sliceName}" [${r.sliceKey}] — via ${r.via}`);
|
|
20
|
+
for (const t of r.uiTriggers)
|
|
21
|
+
lines.push(` triggered by ui: ${t.ref} "${t.name}"`);
|
|
22
|
+
}
|
|
23
|
+
return lines.join("\n");
|
|
24
|
+
}
|
|
25
|
+
export function formatClosure(results) {
|
|
26
|
+
if (results.length === 0)
|
|
27
|
+
return "(none)";
|
|
28
|
+
return results.map((r) => `depth ${r.depth} ${r.ref} (${r.kind}) via ${r.via} — slice "${r.sliceName}" [${r.sliceKey}]`).join("\n");
|
|
29
|
+
}
|
|
30
|
+
export function formatSlices(results) {
|
|
31
|
+
if (results.length === 0)
|
|
32
|
+
return "(none)";
|
|
33
|
+
return results
|
|
34
|
+
.map((r) => `${r.ref} "${r.name}" pattern=${r.pattern} status=${r.status ?? "no-doc"}` +
|
|
35
|
+
tagList("personas", r.personas) +
|
|
36
|
+
tagList("contexts", r.contexts) +
|
|
37
|
+
tagList("tags", r.tags))
|
|
38
|
+
.join("\n");
|
|
39
|
+
}
|
|
40
|
+
export function formatInvariant(results) {
|
|
41
|
+
if (results.length === 0)
|
|
42
|
+
return "(none)";
|
|
43
|
+
const r = results[0];
|
|
44
|
+
const lines = [
|
|
45
|
+
`${r.id} declared in slice "${r.sliceName}" [${r.sliceRef}]`,
|
|
46
|
+
` doc: ${r.docPath ?? "(no doc)"} status: ${r.status ?? "(none)"}`,
|
|
47
|
+
];
|
|
48
|
+
if (r.citations !== null) {
|
|
49
|
+
if (r.citations.length === 0)
|
|
50
|
+
lines.push(" citations: (none)");
|
|
51
|
+
else {
|
|
52
|
+
lines.push(" citations:");
|
|
53
|
+
for (const c of r.citations)
|
|
54
|
+
lines.push(` ${c.file}:${c.line}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return lines.join("\n");
|
|
58
|
+
}
|
|
59
|
+
export function formatField(results) {
|
|
60
|
+
if (results.length === 0)
|
|
61
|
+
return "(none)";
|
|
62
|
+
const r = results[0];
|
|
63
|
+
const renamed = tagList("renamedFrom", r.renamedFrom ?? []);
|
|
64
|
+
const elementRenamed = tagList("elementRenamedFrom", r.elementRenamedFrom ?? []);
|
|
65
|
+
return `${r.elementRef}.${r.name}: ${r.type ?? "(untyped)"} tag=${r.tag} assigned=${r.assigned}${renamed}${elementRenamed}`;
|
|
66
|
+
}
|
|
67
|
+
export function formatPath(results) {
|
|
68
|
+
if (results.length === 0)
|
|
69
|
+
return "(none)";
|
|
70
|
+
const r = results[0];
|
|
71
|
+
if (r.length === 0)
|
|
72
|
+
return r.refs[0];
|
|
73
|
+
const parts = [r.refs[0]];
|
|
74
|
+
for (let i = 0; i < r.edgeKinds.length; i++) {
|
|
75
|
+
parts.push(`--[${r.edgeKinds[i]}]-->`);
|
|
76
|
+
parts.push(r.refs[i + 1]);
|
|
77
|
+
}
|
|
78
|
+
return parts.join(" ");
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/query/format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { NormalizedModel } from "../model/model.js";
|
|
2
|
+
import { RefsResult } from "../model/refs.js";
|
|
3
|
+
import { Diagnostic } from "../model/validate.js";
|
|
4
|
+
import { ModelIndex } from "../model/queryIndex.js";
|
|
5
|
+
export interface QueryCompileResult {
|
|
6
|
+
model: NormalizedModel;
|
|
7
|
+
refs: RefsResult;
|
|
8
|
+
diagnostics: Diagnostic[];
|
|
9
|
+
index: ModelIndex;
|
|
10
|
+
}
|
|
11
|
+
/** Compile one `.em` source for query use: parse + normalize + refs + validate (grid-free, see
|
|
12
|
+
* header) + the ModelIndex every verb queries. `baseDir` is the `.em` file's own directory —
|
|
13
|
+
* same doc-resolution convention every other command uses (passed straight through to
|
|
14
|
+
* `buildModelIndex`'s slice-doc join). Throws `ParseError` on a syntax error, same as
|
|
15
|
+
* `pipeline.ts`'s `compile()` — callers (cli.ts's compileFile-style wrapper, the MCP tool)
|
|
16
|
+
* catch it the same way. */
|
|
17
|
+
export declare function compileForQuery(source: string, baseDir: string): QueryCompileResult;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// `em query`'s sub-pipeline (MIL-168): `parse -> normalize -> computeRefs -> buildIndex`,
|
|
3
|
+
// skipping `pipeline.ts`'s own `layout()` (the dense per-cell Grid allocation — rows x slice
|
|
4
|
+
// columns) and `emitDot()` entirely. Neither is query work: nothing here renders, and
|
|
5
|
+
// `layout()`'s only diagnostic contribution `validate()` reads is `grid.collisions` (row/col
|
|
6
|
+
// placement clashes — a rendering-only concern, `src/model/validate.ts` greps clean for any
|
|
7
|
+
// other `grid.` use). `EMPTY_GRID` below hands `validate()` a real, empty `Grid` shape instead
|
|
8
|
+
// of computing one, so query pays zero layout cost while every OTHER validate.ts diagnostic
|
|
9
|
+
// (unresolved refs, dangling views, tag/field completeness, ...) still runs at full strength.
|
|
10
|
+
//
|
|
11
|
+
// validate() itself is deliberately still called, one explicit deviation from this ticket's
|
|
12
|
+
// design note (which named it alongside layout/DOT as work to skip): the CLI/MCP contract
|
|
13
|
+
// this ticket also specifies is "refuse (exit 1) if a model has compile errors," the same
|
|
14
|
+
// `hasErrors(diagnostics)` gate `em export`/`em status`/every other JSON surface uses — dropping
|
|
15
|
+
// validate() would mean `em query` silently traverses a model with unresolved references
|
|
16
|
+
// instead of refusing, a behavior change from every sibling command with no upside once
|
|
17
|
+
// layout's own cost is already zero. See this ticket's report for the full tradeoff.
|
|
18
|
+
import { parse } from "../parser/parser.js";
|
|
19
|
+
import { normalize } from "../model/model.js";
|
|
20
|
+
import { computeRefs } from "../model/refs.js";
|
|
21
|
+
import { validate } from "../model/validate.js";
|
|
22
|
+
import { buildModelIndex } from "../model/queryIndex.js";
|
|
23
|
+
const EMPTY_GRID = { rows: [], cols: 0, sliceNames: [], cells: [], rowIndexByKey: new Map(), collisions: [] };
|
|
24
|
+
/** Compile one `.em` source for query use: parse + normalize + refs + validate (grid-free, see
|
|
25
|
+
* header) + the ModelIndex every verb queries. `baseDir` is the `.em` file's own directory —
|
|
26
|
+
* same doc-resolution convention every other command uses (passed straight through to
|
|
27
|
+
* `buildModelIndex`'s slice-doc join). Throws `ParseError` on a syntax error, same as
|
|
28
|
+
* `pipeline.ts`'s `compile()` — callers (cli.ts's compileFile-style wrapper, the MCP tool)
|
|
29
|
+
* catch it the same way. */
|
|
30
|
+
export function compileForQuery(source, baseDir) {
|
|
31
|
+
const ast = parse(source);
|
|
32
|
+
const model = normalize(ast);
|
|
33
|
+
const refs = computeRefs(model);
|
|
34
|
+
const diagnostics = [...validate(model, EMPTY_GRID, refs), ...refs.diagnostics];
|
|
35
|
+
const index = buildModelIndex(model, refs, baseDir);
|
|
36
|
+
return { model, refs, diagnostics, index };
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=pipeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/query/pipeline.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,0FAA0F;AAC1F,6FAA6F;AAC7F,sFAAsF;AACtF,6FAA6F;AAC7F,4FAA4F;AAC5F,+FAA+F;AAC/F,4FAA4F;AAC5F,8FAA8F;AAC9F,EAAE;AACF,4FAA4F;AAC5F,0FAA0F;AAC1F,0FAA0F;AAC1F,iGAAiG;AACjG,yFAAyF;AACzF,wFAAwF;AACxF,qFAAqF;AAErF,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAmB,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAc,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAc,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAc,MAAM,wBAAwB,CAAC;AAGrE,MAAM,UAAU,GAAS,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,aAAa,EAAE,IAAI,GAAG,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;AASpH;;;;;6BAK6B;AAC7B,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,OAAe;IAC7D,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1B,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IAChC,MAAM,WAAW,GAAG,CAAC,GAAG,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC;IAChF,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACpD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { NormalizedModel } from "../model/model.js";
|
|
2
|
+
import { RefsResult } from "../model/refs.js";
|
|
3
|
+
import { ModelIndex } from "../model/queryIndex.js";
|
|
4
|
+
import type { Diagnostic } from "../model/validate.js";
|
|
5
|
+
export interface QueryModelEntry {
|
|
6
|
+
file: string;
|
|
7
|
+
modelKey: string;
|
|
8
|
+
model: NormalizedModel;
|
|
9
|
+
refs: RefsResult;
|
|
10
|
+
index: ModelIndex;
|
|
11
|
+
}
|
|
12
|
+
export interface QuerySystem {
|
|
13
|
+
entries: QueryModelEntry[];
|
|
14
|
+
/** True once more than one file was given — the CLI/MCP layer's signal to qualify every ref
|
|
15
|
+
* in its output (`qualifyRef` below), and the signal `resolveElement`'s ambiguity rule uses
|
|
16
|
+
* ("unqualified + multi-model + ambiguous" -> list qualified candidates, per this ticket's
|
|
17
|
+
* design note). */
|
|
18
|
+
multiModel: boolean;
|
|
19
|
+
/** `duplicate-model-key` warnings from keying the entries (MIL-193, `computeModelKeys()`):
|
|
20
|
+
* two input models deriving the same key, the later one suffixed `~2`/`~3`, … in file-list
|
|
21
|
+
* order. Empty for a single-model system. The CLI prints these to stderr like any other
|
|
22
|
+
* compile warning; the JSON document is unaffected (MCP parity holds). */
|
|
23
|
+
diagnostics: Diagnostic[];
|
|
24
|
+
}
|
|
25
|
+
export declare function buildQuerySystem(entries: Array<{
|
|
26
|
+
file: string;
|
|
27
|
+
model: NormalizedModel;
|
|
28
|
+
refs: RefsResult;
|
|
29
|
+
index: ModelIndex;
|
|
30
|
+
}>): QuerySystem;
|
|
31
|
+
/** `<modelKey>:<ref>` when the system spans more than one model, else the bare ref — the one
|
|
32
|
+
* place every query verb decides whether to qualify a ref for output, so the WHEN can't drift
|
|
33
|
+
* between verbs (the HOW is `formatQualifiedRef()`'s). */
|
|
34
|
+
export declare function qualifyRef(system: QuerySystem, modelKey: string, ref: string): string;
|
|
35
|
+
export interface ResolvedElement {
|
|
36
|
+
modelKey: string;
|
|
37
|
+
file: string;
|
|
38
|
+
entry: QueryModelEntry;
|
|
39
|
+
ref: string;
|
|
40
|
+
qualifiedRef: string;
|
|
41
|
+
elementKind: string;
|
|
42
|
+
elementName: string;
|
|
43
|
+
}
|
|
44
|
+
export type ResolveResult = {
|
|
45
|
+
ok: true;
|
|
46
|
+
match: ResolvedElement;
|
|
47
|
+
} | {
|
|
48
|
+
ok: false;
|
|
49
|
+
error: string;
|
|
50
|
+
};
|
|
51
|
+
/** Resolve one user-supplied element reference — a stable ref, a `<modelKey>:`-qualified ref, or
|
|
52
|
+
* a bare display name — against every model in `system` (or just the named model, when
|
|
53
|
+
* qualified). A bare name/ref matching more than one element across the searched model(s) is
|
|
54
|
+
* always an error listing every candidate as a fully-qualified ref (`<modelKey>:<ref>`, even
|
|
55
|
+
* when `system` is single-model — a candidate list must be unambiguous on its own) — resolution
|
|
56
|
+
* never guesses. "Resolution is per-model" (MIL-168's spec): a bare name is looked up in each
|
|
57
|
+
* candidate model's OWN `byName` index, never merged across models before matching. A repeated
|
|
58
|
+
* read model's later instances (`view X again`) don't count as separate name matches — see
|
|
59
|
+
* the bare-name branch below. */
|
|
60
|
+
export declare function resolveElement(system: QuerySystem, raw: string): ResolveResult;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// `em query`'s multi-model addressing (MIL-168): a `QuerySystem` is one or more compiled
|
|
3
|
+
// models, each keyed by a short, stable `modelKey`. Refs (`<sliceKey>/<kind>.<slug>`) are, and
|
|
4
|
+
// remain, model-UNQUALIFIED — `computeRefs()`'s contract is untouched. For a query answer that
|
|
5
|
+
// spans more than one input file, that's ambiguous on its own (two models can easily mint the
|
|
6
|
+
// same slice/element ref independently), so `em query` addresses cross-model results with the
|
|
7
|
+
// qualified form `<modelKey>:<sliceKey>/<kind>.<slug>` — accepted on input alongside a bare
|
|
8
|
+
// ref/display name, and used to disambiguate/print results whenever more than one file was given.
|
|
9
|
+
//
|
|
10
|
+
// Query was the first surface to need this (MIL-168) and originally derived `modelKey` from the
|
|
11
|
+
// input filename. Since MIL-193 the key, the grammar, and the parse/format live in
|
|
12
|
+
// model/qualifiedRef.ts — the ONE cross-model addressing scheme every em surface shares
|
|
13
|
+
// (`em export`'s `model.key`, MIL-194's seam manifest, em-portal deep links): the key is the
|
|
14
|
+
// kebab-slug of the declared `model "Name"` (basename fallback when none is declared), so a
|
|
15
|
+
// query result's qualified ref is the same string an export consumer would mint for the same
|
|
16
|
+
// element. This module only decides WHEN to qualify (more than one file given) and how a
|
|
17
|
+
// user-supplied ref resolves; it never spells the grammar itself.
|
|
18
|
+
import { normalizeName } from "../model/model.js";
|
|
19
|
+
import { computeModelKeys, formatQualifiedRef, parseQualifiedRef } from "../model/qualifiedRef.js";
|
|
20
|
+
export function buildQuerySystem(entries) {
|
|
21
|
+
const { keys, diagnostics } = computeModelKeys(entries);
|
|
22
|
+
return {
|
|
23
|
+
entries: entries.map((e, i) => ({ file: e.file, modelKey: keys[i], model: e.model, refs: e.refs, index: e.index })),
|
|
24
|
+
multiModel: entries.length > 1,
|
|
25
|
+
diagnostics,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/** `<modelKey>:<ref>` when the system spans more than one model, else the bare ref — the one
|
|
29
|
+
* place every query verb decides whether to qualify a ref for output, so the WHEN can't drift
|
|
30
|
+
* between verbs (the HOW is `formatQualifiedRef()`'s). */
|
|
31
|
+
export function qualifyRef(system, modelKey, ref) {
|
|
32
|
+
return system.multiModel ? formatQualifiedRef(modelKey, ref) : ref;
|
|
33
|
+
}
|
|
34
|
+
const REF_SHAPE_RE = /\//;
|
|
35
|
+
/** Resolve one user-supplied element reference — a stable ref, a `<modelKey>:`-qualified ref, or
|
|
36
|
+
* a bare display name — against every model in `system` (or just the named model, when
|
|
37
|
+
* qualified). A bare name/ref matching more than one element across the searched model(s) is
|
|
38
|
+
* always an error listing every candidate as a fully-qualified ref (`<modelKey>:<ref>`, even
|
|
39
|
+
* when `system` is single-model — a candidate list must be unambiguous on its own) — resolution
|
|
40
|
+
* never guesses. "Resolution is per-model" (MIL-168's spec): a bare name is looked up in each
|
|
41
|
+
* candidate model's OWN `byName` index, never merged across models before matching. A repeated
|
|
42
|
+
* read model's later instances (`view X again`) don't count as separate name matches — see
|
|
43
|
+
* the bare-name branch below. */
|
|
44
|
+
export function resolveElement(system, raw) {
|
|
45
|
+
// `parseQualifiedRef` only splits when the prefix has the model-key SHAPE; a prefix that
|
|
46
|
+
// isn't one of THIS system's keys is then left in place — a display name may legitimately
|
|
47
|
+
// contain a colon — so the search runs over every model; if nothing matches, the miss names
|
|
48
|
+
// the unrecognised prefix (a typo'd qualifier is the likely cause).
|
|
49
|
+
const parsed = parseQualifiedRef(raw);
|
|
50
|
+
const known = parsed.modelKey !== null && system.entries.some((e) => e.modelKey === parsed.modelKey);
|
|
51
|
+
const modelKey = known ? parsed.modelKey : undefined;
|
|
52
|
+
const rest = known ? parsed.ref : raw;
|
|
53
|
+
const candidates = modelKey ? system.entries.filter((e) => e.modelKey === modelKey) : system.entries;
|
|
54
|
+
const matches = [];
|
|
55
|
+
for (const entry of candidates) {
|
|
56
|
+
// A slash makes the input look like a ref; when no ref matches, fall through to the
|
|
57
|
+
// display-name lookup — a name may itself contain a slash ("Approve/Reject Screen").
|
|
58
|
+
const byRef = REF_SHAPE_RE.test(rest) ? entry.index.byRef.get(rest) : undefined;
|
|
59
|
+
if (byRef) {
|
|
60
|
+
const ref = entry.refs.refById.get(byRef.id);
|
|
61
|
+
matches.push({ modelKey: entry.modelKey, file: entry.file, entry, ref, qualifiedRef: formatQualifiedRef(entry.modelKey, ref), elementKind: byRef.kind, elementName: byRef.name });
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// A repeated read model (`view X again`) has one name and several instances; the bare
|
|
65
|
+
// name means the read model, which resolves to its FIRST instance (`logicalId`) — every
|
|
66
|
+
// closure/path verb then follows the instance chain from there (verbs.ts's header). A
|
|
67
|
+
// later instance stays addressable by its own ref.
|
|
68
|
+
const bucket = (entry.model.byName.get(normalizeName(rest)) ?? []).filter((el) => el.logicalId === el.id);
|
|
69
|
+
for (const el of bucket) {
|
|
70
|
+
const ref = entry.refs.refById.get(el.id);
|
|
71
|
+
matches.push({ modelKey: entry.modelKey, file: entry.file, entry, ref, qualifiedRef: formatQualifiedRef(entry.modelKey, ref), elementKind: el.kind, elementName: el.name });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (matches.length === 0) {
|
|
76
|
+
const hint = parsed.modelKey !== null && !known
|
|
77
|
+
? ` ("${parsed.modelKey}" is not a model key — input models are: ${system.entries.map((e) => e.modelKey).join(", ")})`
|
|
78
|
+
: "";
|
|
79
|
+
return { ok: false, error: `em query: no element matches "${raw}"${hint}` };
|
|
80
|
+
}
|
|
81
|
+
if (matches.length > 1) {
|
|
82
|
+
const candidateRefs = matches.map((m) => m.qualifiedRef).join(", ");
|
|
83
|
+
return { ok: false, error: `em query: "${raw}" is ambiguous — matches ${matches.length} elements: ${candidateRefs}` };
|
|
84
|
+
}
|
|
85
|
+
return { ok: true, match: matches[0] };
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=system.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system.js","sourceRoot":"","sources":["../../src/query/system.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { QuerySystem } from "./system.js";
|
|
2
|
+
import { Citation } from "../cli/coverage.js";
|
|
3
|
+
export interface ElementSummary {
|
|
4
|
+
ref: string;
|
|
5
|
+
kind: string;
|
|
6
|
+
name: string;
|
|
7
|
+
sliceKey: string;
|
|
8
|
+
sliceName: string;
|
|
9
|
+
}
|
|
10
|
+
export type VerbResult<T> = {
|
|
11
|
+
ok: true;
|
|
12
|
+
results: T[];
|
|
13
|
+
} | {
|
|
14
|
+
ok: false;
|
|
15
|
+
error: string;
|
|
16
|
+
};
|
|
17
|
+
export interface ConsumerEntry extends ElementSummary {
|
|
18
|
+
via: string;
|
|
19
|
+
}
|
|
20
|
+
/** Views/reactions (and anything wired by an explicit `arrow`) consuming the named event — its
|
|
21
|
+
* direct out-neighbors in the legal-connection graph, each with the slice it lives in. */
|
|
22
|
+
export declare function queryConsumers(system: QuerySystem, eventRef: string): VerbResult<ConsumerEntry>;
|
|
23
|
+
export interface ProducerEntry extends ElementSummary {
|
|
24
|
+
via: string;
|
|
25
|
+
uiTriggers: ElementSummary[];
|
|
26
|
+
}
|
|
27
|
+
/** Commands producing the named event, each with its own slice and (MIL-168 spec: "+ slices, ui
|
|
28
|
+
* triggers") the `ui` elements that trigger that command in turn. */
|
|
29
|
+
export declare function queryProducers(system: QuerySystem, eventRef: string): VerbResult<ProducerEntry>;
|
|
30
|
+
export interface ClosureEntry extends ElementSummary {
|
|
31
|
+
depth: number;
|
|
32
|
+
via: string;
|
|
33
|
+
}
|
|
34
|
+
/** Transitive closure along legal edges (direction: element -> whatever it feeds) — impact
|
|
35
|
+
* analysis: "what breaks if this changes." */
|
|
36
|
+
export declare function queryDownstream(system: QuerySystem, ofRef: string, depth?: number): VerbResult<ClosureEntry>;
|
|
37
|
+
/** Transitive closure against legal-edge direction — "what feeds this." */
|
|
38
|
+
export declare function queryUpstream(system: QuerySystem, ofRef: string, depth?: number): VerbResult<ClosureEntry>;
|
|
39
|
+
export interface SliceQueryEntry {
|
|
40
|
+
ref: string;
|
|
41
|
+
name: string;
|
|
42
|
+
index: number;
|
|
43
|
+
pattern: string;
|
|
44
|
+
status: string | null;
|
|
45
|
+
personas: string[];
|
|
46
|
+
contexts: string[];
|
|
47
|
+
tags: string[];
|
|
48
|
+
}
|
|
49
|
+
export interface SliceFilters {
|
|
50
|
+
pattern?: string;
|
|
51
|
+
status?: string;
|
|
52
|
+
context?: string;
|
|
53
|
+
persona?: string;
|
|
54
|
+
tag?: string;
|
|
55
|
+
}
|
|
56
|
+
/** The filtered slice list — every filter AND-combines. `pattern`/`status` match the slice's
|
|
57
|
+
* own single value exactly (case-insensitive); `context`/`persona`/`tag` match when ANY
|
|
58
|
+
* element in the slice carries that context/persona/tag key. */
|
|
59
|
+
export declare function querySlices(system: QuerySystem, filters: SliceFilters): VerbResult<SliceQueryEntry>;
|
|
60
|
+
export interface InvariantQueryEntry {
|
|
61
|
+
id: string;
|
|
62
|
+
sliceRef: string;
|
|
63
|
+
sliceName: string;
|
|
64
|
+
docPath: string | null;
|
|
65
|
+
status: string | null;
|
|
66
|
+
citations: Citation[] | null;
|
|
67
|
+
}
|
|
68
|
+
/** The declaring slice + doc facts for one `INV-*` id, and (with `testsDir`) every test file
|
|
69
|
+
* citing it — a single-ID `scanTestCitations()` call, the same word-boundary citation scan
|
|
70
|
+
* `em coverage` uses for every ID in the model, reused rather than reimplemented. An id
|
|
71
|
+
* matching more than one input model is the same "unqualified + multi-model + ambiguous" case
|
|
72
|
+
* every other verb refuses on, listing qualified candidates. */
|
|
73
|
+
export declare function queryInvariant(system: QuerySystem, id: string, testsDir?: string): VerbResult<InvariantQueryEntry>;
|
|
74
|
+
export interface FieldQueryEntry {
|
|
75
|
+
elementRef: string;
|
|
76
|
+
name: string;
|
|
77
|
+
type: string | null;
|
|
78
|
+
tag: boolean;
|
|
79
|
+
assigned: boolean;
|
|
80
|
+
renamedFrom: string[] | null;
|
|
81
|
+
/** The owning element's own `renamed from` chain (event/command only, MIL-68) — provenance
|
|
82
|
+
* has two axes: the field's prior names, and the prior names of the element it lives on. */
|
|
83
|
+
elementRenamedFrom: string[] | null;
|
|
84
|
+
}
|
|
85
|
+
/** One field's facts on the named element — type, identity-tag/system-assigned markers, its
|
|
86
|
+
* `renamed from` chain, and the owning element's. An element that resolves but carries no
|
|
87
|
+
* field of that name is a legitimate empty result (`results: []`), not an error — same "none,
|
|
88
|
+
* exit 0" contract as every other verb's empty answer. */
|
|
89
|
+
export declare function queryField(system: QuerySystem, ofRef: string, name: string): VerbResult<FieldQueryEntry>;
|
|
90
|
+
export interface PathQueryEntry {
|
|
91
|
+
refs: string[];
|
|
92
|
+
edgeKinds: string[];
|
|
93
|
+
length: number;
|
|
94
|
+
}
|
|
95
|
+
/** Shortest directed path from `fromRef` to `toRef` through the legal-connection graph (BFS,
|
|
96
|
+
* unweighted — first-found is shortest by construction; a `view-instance` hop costs nothing
|
|
97
|
+
* and isn't counted in `length`). Endpoints resolving to different models is a legitimate
|
|
98
|
+
* empty result (edges never cross model files — see system.ts's header) rather than an
|
|
99
|
+
* error. */
|
|
100
|
+
export declare function queryPath(system: QuerySystem, fromRef: string, toRef: string): VerbResult<PathQueryEntry>;
|