@milehimikey/em 1.9.1 → 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-design/SKILL.md +1 -1
- 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 +46 -1
- 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 +220 -5
- 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
package/dist/model/edges.d.ts
CHANGED
|
@@ -1,9 +1,21 @@
|
|
|
1
|
+
import { ElementKind } from "../parser/ast.js";
|
|
1
2
|
import { Element, NormalizedModel } from "./model.js";
|
|
3
|
+
/** Where an edge came from: inferred from a slice's pattern shape, resolved from an explicit
|
|
4
|
+
* `from "Name"` clause, or declared by an `arrow`. First-wins on a duplicate (from, to) pair
|
|
5
|
+
* in exactly this order — an `arrow` restating an inferred connection is the same line. */
|
|
6
|
+
export type EdgeSource = "pattern" | "from" | "arrow";
|
|
2
7
|
export interface SemanticEdge {
|
|
3
8
|
from: string;
|
|
4
9
|
to: string;
|
|
5
|
-
|
|
10
|
+
source: EdgeSource;
|
|
6
11
|
}
|
|
12
|
+
/** The six legal connection types, named by their endpoint kinds. */
|
|
13
|
+
export type ConnectionKind = "ui->command" | "command->event" | "event->view" | "view->ui" | "view->reaction" | "reaction->command";
|
|
14
|
+
/** The legal connection type for an endpoint-kind pair, or undefined when no such connection
|
|
15
|
+
* is legal — the relationship is a pure function of the two kinds, so edges carry no `kind`
|
|
16
|
+
* of their own (validate.ts's illegal-pair rule and query's edge labels both derive from
|
|
17
|
+
* here). */
|
|
18
|
+
export declare function connectionKind(from: ElementKind, to: ElementKind): ConnectionKind | undefined;
|
|
7
19
|
/** Infer pattern arrows from each slice plus cross-slice `from` sources. */
|
|
8
20
|
export declare function semanticEdges(model: NormalizedModel): SemanticEdge[];
|
|
9
21
|
/**
|
package/dist/model/edges.js
CHANGED
|
@@ -1,22 +1,48 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// The semantic edges of a model: which
|
|
3
|
-
// the single source of truth for the
|
|
4
|
-
//
|
|
2
|
+
// The semantic edges of a model: which connections exist, and where each came from. This is
|
|
3
|
+
// the single source of truth for the graph — the renderer draws exactly these (colouring each
|
|
4
|
+
// by its source element's kind at the call site, render/drawEdges.ts), `em query`'s ModelIndex
|
|
5
|
+
// traverses exactly these (model/queryIndex.ts), and `em export` serializes exactly these as
|
|
6
|
+
// `model.edges` (emit/json.ts, schema 1.10 / MIL-191). One derivation, three consumers: the guards below (the misplaced-ui rule, the
|
|
7
|
+
// same-slice-only event->view rule, the pair dedup) are judgment calls invisible in the data,
|
|
8
|
+
// so a second walk re-deriving them would drift — it did once already (the MIL-162 portal
|
|
9
|
+
// spike re-derived independently).
|
|
5
10
|
import { AUTOMATION_KINDS } from "../parser/ast.js";
|
|
6
11
|
import { normalizeName } from "./model.js";
|
|
7
|
-
|
|
12
|
+
/** The legal connection type for an endpoint-kind pair, or undefined when no such connection
|
|
13
|
+
* is legal — the relationship is a pure function of the two kinds, so edges carry no `kind`
|
|
14
|
+
* of their own (validate.ts's illegal-pair rule and query's edge labels both derive from
|
|
15
|
+
* here). */
|
|
16
|
+
export function connectionKind(from, to) {
|
|
17
|
+
if (from === "ui")
|
|
18
|
+
return to === "command" ? "ui->command" : undefined; // State Change
|
|
19
|
+
if (from === "command")
|
|
20
|
+
return to === "event" ? "command->event" : undefined; // State Change
|
|
21
|
+
if (from === "event")
|
|
22
|
+
return to === "view" ? "event->view" : undefined; // State View
|
|
23
|
+
if (from === "view") {
|
|
24
|
+
if (to === "ui")
|
|
25
|
+
return "view->ui"; // State View
|
|
26
|
+
if (AUTOMATION_KINDS.has(to))
|
|
27
|
+
return "view->reaction"; // Automation / Translation
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
if (AUTOMATION_KINDS.has(from))
|
|
31
|
+
return to === "command" ? "reaction->command" : undefined; // reactions always go through a command
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
8
34
|
/** Infer pattern arrows from each slice plus cross-slice `from` sources. */
|
|
9
35
|
export function semanticEdges(model) {
|
|
10
36
|
const edges = [];
|
|
11
37
|
const seen = new Set();
|
|
12
|
-
const add = (from, to,
|
|
38
|
+
const add = (from, to, source) => {
|
|
13
39
|
if (from === to)
|
|
14
40
|
return;
|
|
15
41
|
const key = `${from}>${to}`;
|
|
16
42
|
if (seen.has(key))
|
|
17
43
|
return;
|
|
18
44
|
seen.add(key);
|
|
19
|
-
edges.push({ from, to,
|
|
45
|
+
edges.push({ from, to, source });
|
|
20
46
|
};
|
|
21
47
|
for (const slice of model.slices) {
|
|
22
48
|
const uis = slice.elements.filter((e) => e.kind === "ui");
|
|
@@ -31,25 +57,25 @@ export function semanticEdges(model) {
|
|
|
31
57
|
if (command) {
|
|
32
58
|
if (!auto)
|
|
33
59
|
for (const ui of uis)
|
|
34
|
-
add(ui.id, command.id, "
|
|
60
|
+
add(ui.id, command.id, "pattern");
|
|
35
61
|
for (const ev of events)
|
|
36
|
-
add(command.id, ev.id, "
|
|
62
|
+
add(command.id, ev.id, "pattern");
|
|
37
63
|
}
|
|
38
64
|
// Automation/translation: it triggers the command in this same slice — the
|
|
39
65
|
// reaction is to a command what a `ui` is in the State Change pattern. If it
|
|
40
66
|
// also reads a read model that happens to share this slice, wire that too;
|
|
41
67
|
// the far more common cross-slice case is handled by the `from` loop below.
|
|
42
68
|
if (auto && command)
|
|
43
|
-
add(auto.id, command.id,
|
|
69
|
+
add(auto.id, command.id, "pattern");
|
|
44
70
|
if (auto && view)
|
|
45
|
-
add(view.id, auto.id, "
|
|
71
|
+
add(view.id, auto.id, "pattern");
|
|
46
72
|
// Output pattern: view -> UI (read model feeds the screen)
|
|
47
73
|
if (view) {
|
|
48
74
|
for (const ui of uis)
|
|
49
|
-
add(view.id, ui.id, "
|
|
75
|
+
add(view.id, ui.id, "pattern");
|
|
50
76
|
if ((view.from ?? []).length === 0) {
|
|
51
77
|
for (const ev of events)
|
|
52
|
-
add(ev.id, view.id, "
|
|
78
|
+
add(ev.id, view.id, "pattern");
|
|
53
79
|
}
|
|
54
80
|
}
|
|
55
81
|
}
|
|
@@ -60,7 +86,7 @@ export function semanticEdges(model) {
|
|
|
60
86
|
for (const name of el.from ?? []) {
|
|
61
87
|
const src = resolveFromSource(model, el, name);
|
|
62
88
|
if (src)
|
|
63
|
-
add(src.id, el.id,
|
|
89
|
+
add(src.id, el.id, "from");
|
|
64
90
|
}
|
|
65
91
|
}
|
|
66
92
|
// Note: instances of the same logical read model (`view X again`) are deliberately NOT
|
|
@@ -69,11 +95,13 @@ export function semanticEdges(model) {
|
|
|
69
95
|
// inbound event arrows are what show how the view changes over time. A view->view arrow
|
|
70
96
|
// would be a modelling error — and, since commands and read models share the API lane,
|
|
71
97
|
// it also renders as a flat line through any command box between the two instances,
|
|
72
|
-
// reading as an illegal command->read-model connection.
|
|
98
|
+
// reading as an illegal command->read-model connection. (Traversal that needs to follow a
|
|
99
|
+
// read model across its instances — `em query`'s closures — does so via `logicalId`, as a
|
|
100
|
+
// query-engine rule, not as an edge.)
|
|
73
101
|
// Explicit arrows from the DSL.
|
|
74
102
|
for (const a of model.arrows) {
|
|
75
103
|
if (a.fromId && a.toId)
|
|
76
|
-
add(a.fromId, a.toId,
|
|
104
|
+
add(a.fromId, a.toId, "arrow");
|
|
77
105
|
}
|
|
78
106
|
return edges;
|
|
79
107
|
}
|
package/dist/model/edges.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"edges.js","sourceRoot":"","sources":["../../src/model/edges.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,
|
|
1
|
+
{"version":3,"file":"edges.js","sourceRoot":"","sources":["../../src/model/edges.ts"],"names":[],"mappings":"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"}
|
package/dist/model/model.d.ts
CHANGED
|
@@ -89,6 +89,8 @@ export interface ResolvedArrow {
|
|
|
89
89
|
}
|
|
90
90
|
export interface NormalizedModel {
|
|
91
91
|
name: string;
|
|
92
|
+
/** Whether `name` came from a `model "Name"` declaration (see `ModelNode.nameDeclared`). */
|
|
93
|
+
nameDeclared: boolean;
|
|
92
94
|
personas: string[];
|
|
93
95
|
contexts: string[];
|
|
94
96
|
hasAutomation: boolean;
|
package/dist/model/model.js
CHANGED
package/dist/model/model.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/model/model.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,sEAAsE;AACtE,2EAA2E;AAE3E,OAAO,EAAE,gBAAgB,EAA4C,MAAM,kBAAkB,CAAC;AAC9F,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAkB/C,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC;AACtC,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAC;AAmDxC;;;;;;;;;GASG;AACH,MAAM,UAAU,WAAW,CAAC,OAAgB;IAC1C,MAAM,OAAO,GAAe,EAAE,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;QACrC,IAAI,CAAC,CAAC,GAAG,KAAK,IAAI;YAAE,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3G,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;QACnC,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW;YAAE,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;;YAClH,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,IAAI,EAAE,CAAC,CAAC;IACxG,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/model/model.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { NormalizedModel } from "./model.js";
|
|
2
|
+
import type { Diagnostic } from "./validate.js";
|
|
3
|
+
/** The model-key shape: a kebab slug (`kebabSlug()`'s output) with an optional `~n` collision
|
|
4
|
+
* suffix. Anchored; the single definition `parseQualifiedRef`/`isQualifiedRef` split on. */
|
|
5
|
+
export declare const MODEL_KEY_RE: RegExp;
|
|
6
|
+
/**
|
|
7
|
+
* A model's own key: `kebabSlug(model.name)` when the name was declared (`model "Name"`);
|
|
8
|
+
* otherwise the kebab-slugged basename of `fallbackFile` (extension stripped) when one is
|
|
9
|
+
* given; otherwise the slug of the parser's default title. Never deduped — collisions are a
|
|
10
|
+
* multi-model concern, see `computeModelKeys()`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function computeModelKey(model: NormalizedModel, fallbackFile?: string): string;
|
|
13
|
+
export interface ModelKeysResult {
|
|
14
|
+
/** One key per entry, same order/index as the input. */
|
|
15
|
+
keys: string[];
|
|
16
|
+
/** `duplicate-model-key` warnings, one per entry that had to take a `~n` suffix. */
|
|
17
|
+
diagnostics: Diagnostic[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Keys for every model of one multi-model invocation: `computeModelKey()` each, then dedupe
|
|
21
|
+
* with `~2`, `~3`, … in input order (the first entry to claim a key keeps it bare) and warn
|
|
22
|
+
* on every collision. Order-stable: a consumer that always lists its files the same way gets
|
|
23
|
+
* the same keys back.
|
|
24
|
+
*/
|
|
25
|
+
export declare function computeModelKeys(entries: Array<{
|
|
26
|
+
model: NormalizedModel;
|
|
27
|
+
file: string;
|
|
28
|
+
}>): ModelKeysResult;
|
|
29
|
+
/** `<modelKey>:<ref>` — the one place the qualifier separator is spelled. `ref` is an
|
|
30
|
+
* element ref, a bare slice key, or a type ref, unchanged. */
|
|
31
|
+
export declare function formatQualifiedRef(modelKey: string, ref: string): string;
|
|
32
|
+
export interface ParsedQualifiedRef {
|
|
33
|
+
/** The qualifier, or `null` when `input` carried none (or its prefix isn't a model-key shape). */
|
|
34
|
+
modelKey: string | null;
|
|
35
|
+
/** The model-unqualified remainder — `input` itself when unqualified. */
|
|
36
|
+
ref: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Split `<modelKey>:<ref>` on the FIRST colon, but only when the prefix has the model-key
|
|
40
|
+
* shape (`MODEL_KEY_RE`); anything else is returned intact as an unqualified ref — a display
|
|
41
|
+
* name ("Order: Paid") may legitimately contain a colon, and callers resolving names must not
|
|
42
|
+
* lose it. Shape-only: whether the key names a model this caller actually has is its own
|
|
43
|
+
* question (`em query`'s `resolveElement` checks that and reports an unknown prefix).
|
|
44
|
+
*/
|
|
45
|
+
export declare function parseQualifiedRef(input: string): ParsedQualifiedRef;
|
|
46
|
+
/** True when `parseQualifiedRef(input)` would find a model-key-shaped qualifier. */
|
|
47
|
+
export declare function isQualifiedRef(input: string): boolean;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Model-qualified addressing (MIL-193): the ONE grammar for naming a slice, element, or type
|
|
3
|
+
// that lives in another model. Export refs (`<sliceKey>/<kind>.<slug>`, `computeRefs()`) are
|
|
4
|
+
// deliberately model-unqualified and stay valid everywhere they are today; any artifact that
|
|
5
|
+
// crosses a model boundary — `em query`'s multi-model output, `em export`'s own `model.key`,
|
|
6
|
+
// MIL-194's seam manifest, em-portal deep links, em-tracker-bridge — prefixes them with a
|
|
7
|
+
// `modelKey` using exactly this module, so the "one addressing scheme" constraint (MIL-162)
|
|
8
|
+
// can't die by each consumer inventing its own qualifier.
|
|
9
|
+
//
|
|
10
|
+
// <modelKey>:<sliceKey>/<kind>.<slug> element
|
|
11
|
+
// <modelKey>:<sliceKey> slice
|
|
12
|
+
// <modelKey>:types/<slug> type
|
|
13
|
+
//
|
|
14
|
+
// `modelKey` is the kebab-slug of the DECLARED model name (`model "Name"`) — the same
|
|
15
|
+
// `kebabSlug()` every other export identity derives from — never a path: it survives file
|
|
16
|
+
// moves and renames, and a single-model `em export` can carry it with no system context. A
|
|
17
|
+
// file that declares no name falls back to its kebab-slugged basename (extension stripped);
|
|
18
|
+
// two models in one multi-model invocation that mint the same key are deduped `~2`, `~3`, …
|
|
19
|
+
// in file-list order (first wins the bare key) with a `duplicate-model-key` warning naming
|
|
20
|
+
// both files — the same posture as `computeRefs()`'s `duplicate-slice-name`.
|
|
21
|
+
//
|
|
22
|
+
// Lives in model/ for the same layering reason as refs.ts: a pure function of NormalizedModel
|
|
23
|
+
// (no fs, no JSON shape), consumed by emit/, query/, and — via the package's `./refs` subpath
|
|
24
|
+
// export — by external packages, which must never grow a second parser for this grammar.
|
|
25
|
+
import { pushDiag } from "./rules.js";
|
|
26
|
+
import { dedupe, kebabSlug } from "../util/slug.js";
|
|
27
|
+
/** The model-key shape: a kebab slug (`kebabSlug()`'s output) with an optional `~n` collision
|
|
28
|
+
* suffix. Anchored; the single definition `parseQualifiedRef`/`isQualifiedRef` split on. */
|
|
29
|
+
export const MODEL_KEY_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*(?:~\d+)?$/;
|
|
30
|
+
/** Strip a path to its kebab-slugged basename, extension removed — the no-declared-name
|
|
31
|
+
* fallback. Pure string work (no fs, and both `/` and `\` separators) so the module stays
|
|
32
|
+
* usable from a browser bundle. */
|
|
33
|
+
function fileBasenameKey(file) {
|
|
34
|
+
const base = file.split(/[\\/]/).pop() ?? file;
|
|
35
|
+
const dot = base.lastIndexOf(".");
|
|
36
|
+
return kebabSlug(dot > 0 ? base.slice(0, dot) : base);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A model's own key: `kebabSlug(model.name)` when the name was declared (`model "Name"`);
|
|
40
|
+
* otherwise the kebab-slugged basename of `fallbackFile` (extension stripped) when one is
|
|
41
|
+
* given; otherwise the slug of the parser's default title. Never deduped — collisions are a
|
|
42
|
+
* multi-model concern, see `computeModelKeys()`.
|
|
43
|
+
*/
|
|
44
|
+
export function computeModelKey(model, fallbackFile) {
|
|
45
|
+
if (!model.nameDeclared && fallbackFile)
|
|
46
|
+
return fileBasenameKey(fallbackFile);
|
|
47
|
+
return kebabSlug(model.name);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Keys for every model of one multi-model invocation: `computeModelKey()` each, then dedupe
|
|
51
|
+
* with `~2`, `~3`, … in input order (the first entry to claim a key keeps it bare) and warn
|
|
52
|
+
* on every collision. Order-stable: a consumer that always lists its files the same way gets
|
|
53
|
+
* the same keys back.
|
|
54
|
+
*/
|
|
55
|
+
export function computeModelKeys(entries) {
|
|
56
|
+
const diagnostics = [];
|
|
57
|
+
const used = new Set();
|
|
58
|
+
const firstFileByKey = new Map();
|
|
59
|
+
const keys = entries.map(({ model, file }) => {
|
|
60
|
+
const base = computeModelKey(model, file);
|
|
61
|
+
const key = dedupe(base, used, "~");
|
|
62
|
+
if (key === base) {
|
|
63
|
+
firstFileByKey.set(base, file);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
pushDiag(diagnostics, "duplicate-model-key", {
|
|
67
|
+
message: `duplicate model key "${base}" (${firstFileByKey.get(base)} and ${file} both derive it); give each model a unique \`model "Name"\` so cross-model refs stay stable — ${file} is addressed as "${key}" in this run`,
|
|
68
|
+
refs: [key, base],
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return key;
|
|
72
|
+
});
|
|
73
|
+
return { keys, diagnostics };
|
|
74
|
+
}
|
|
75
|
+
/** `<modelKey>:<ref>` — the one place the qualifier separator is spelled. `ref` is an
|
|
76
|
+
* element ref, a bare slice key, or a type ref, unchanged. */
|
|
77
|
+
export function formatQualifiedRef(modelKey, ref) {
|
|
78
|
+
return `${modelKey}:${ref}`;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Split `<modelKey>:<ref>` on the FIRST colon, but only when the prefix has the model-key
|
|
82
|
+
* shape (`MODEL_KEY_RE`); anything else is returned intact as an unqualified ref — a display
|
|
83
|
+
* name ("Order: Paid") may legitimately contain a colon, and callers resolving names must not
|
|
84
|
+
* lose it. Shape-only: whether the key names a model this caller actually has is its own
|
|
85
|
+
* question (`em query`'s `resolveElement` checks that and reports an unknown prefix).
|
|
86
|
+
*/
|
|
87
|
+
export function parseQualifiedRef(input) {
|
|
88
|
+
const colon = input.indexOf(":");
|
|
89
|
+
if (colon <= 0)
|
|
90
|
+
return { modelKey: null, ref: input };
|
|
91
|
+
const prefix = input.slice(0, colon);
|
|
92
|
+
if (!MODEL_KEY_RE.test(prefix))
|
|
93
|
+
return { modelKey: null, ref: input };
|
|
94
|
+
return { modelKey: prefix, ref: input.slice(colon + 1) };
|
|
95
|
+
}
|
|
96
|
+
/** True when `parseQualifiedRef(input)` would find a model-key-shaped qualifier. */
|
|
97
|
+
export function isQualifiedRef(input) {
|
|
98
|
+
return parseQualifiedRef(input).modelKey !== null;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=qualifiedRef.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qualifiedRef.js","sourceRoot":"","sources":["../../src/model/qualifiedRef.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Element, NormalizedModel } from "./model.js";
|
|
2
|
+
import { RefsResult } from "./refs.js";
|
|
3
|
+
import { ConnectionKind } from "./edges.js";
|
|
4
|
+
import { SliceQueryDoc } from "./sliceDocIndex.js";
|
|
5
|
+
/** What a query result arrived by: one of the six legal connections, `view-instance` (the
|
|
6
|
+
* zero-cost hop between two timeline instances of one read model — not an edge), or `other`
|
|
7
|
+
* for an edge whose endpoint kinds form no legal connection (only reachable through a `from`
|
|
8
|
+
* clause resolving to a non-event; an explicit `arrow` between such a pair is a compile error
|
|
9
|
+
* query refuses on). */
|
|
10
|
+
export type QueryEdgeKind = ConnectionKind | "view-instance" | "other";
|
|
11
|
+
export interface IndexEdge {
|
|
12
|
+
ref: string;
|
|
13
|
+
kind: QueryEdgeKind;
|
|
14
|
+
}
|
|
15
|
+
export interface SliceIndexFact {
|
|
16
|
+
key: string;
|
|
17
|
+
name: string;
|
|
18
|
+
index: number;
|
|
19
|
+
line: number;
|
|
20
|
+
doc: SliceQueryDoc;
|
|
21
|
+
}
|
|
22
|
+
export interface InvariantIndexEntry {
|
|
23
|
+
id: string;
|
|
24
|
+
sliceKey: string;
|
|
25
|
+
}
|
|
26
|
+
export interface ModelIndex {
|
|
27
|
+
model: NormalizedModel;
|
|
28
|
+
refs: RefsResult;
|
|
29
|
+
baseDir: string;
|
|
30
|
+
/** Export ref -> Element, in `model.elements` order (== document order: slice, then
|
|
31
|
+
* within-slice declaration order) — the same order every query verb sorts its results by,
|
|
32
|
+
* for free, via Map iteration order. */
|
|
33
|
+
byRef: Map<string, Element>;
|
|
34
|
+
out: Map<string, IndexEdge[]>;
|
|
35
|
+
in: Map<string, IndexEdge[]>;
|
|
36
|
+
/** Ref of a repeated read model instance -> refs of its OTHER instances (same `logicalId`),
|
|
37
|
+
* in document order. Only populated for views declared more than once; a single-instance
|
|
38
|
+
* element has no entry. */
|
|
39
|
+
instances: Map<string, string[]>;
|
|
40
|
+
/** Slice export key -> its doc-join facts, in `model.slices` order. */
|
|
41
|
+
sliceFacts: Map<string, SliceIndexFact>;
|
|
42
|
+
/** INV-* id -> the slice that declares it. A doc is scanned once per slice it resolves for
|
|
43
|
+
* (its own canonical slice, plus every slice it ratifies via MIL-121 `covers:`), so the
|
|
44
|
+
* CANONICAL binding (`doc.path === slices/<thisSliceKey>.md`) always owns the id, whatever
|
|
45
|
+
* the slices' document order; a cross-bound slice claims an id only when no canonical slice
|
|
46
|
+
* for that doc exists in the model. Two canonical docs declaring the same id is first-wins
|
|
47
|
+
* in slice order — a bug in the model, not something query silently resolves further. */
|
|
48
|
+
invariants: Map<string, InvariantIndexEntry>;
|
|
49
|
+
}
|
|
50
|
+
export declare function buildModelIndex(model: NormalizedModel, refs: RefsResult, baseDir: string): ModelIndex;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// `ModelIndex` (MIL-168): the one graph index `em query`'s verbs all reduce to a map hit or a
|
|
3
|
+
// BFS over — built once per compiled model (see ../query/pipeline.ts's sub-pipeline) and shared
|
|
4
|
+
// by the CLI and the MCP `query` tool (both call `buildModelIndex()`, never a second traversal
|
|
5
|
+
// implementation — MCP parity, docs/mcp.md).
|
|
6
|
+
//
|
|
7
|
+
// - `byRef`: the inverse of `RefsResult.refById` — the compiled model has never had this
|
|
8
|
+
// before (`NormalizedModel.byName` is the only lookup table, keyed by display name, not ref).
|
|
9
|
+
// - `out`/`in`: adjacency over `semanticEdges()` (model/edges.ts — the SAME edge list the
|
|
10
|
+
// renderer draws, so query and diagram can't disagree on what connects), keyed by export ref
|
|
11
|
+
// so query never has to re-resolve an internal Element.id. Each edge is labeled with its
|
|
12
|
+
// connection kind, a pure function of the endpoint kinds (`connectionKind()`).
|
|
13
|
+
// - `instances`: repeated read-model instances (`view X again`) grouped by `logicalId` — never
|
|
14
|
+
// edges (see edges.ts's note on why instances don't connect), but the thing closures/paths
|
|
15
|
+
// follow so "what's downstream of this event" reaches every later timeline instance of a
|
|
16
|
+
// read model it feeds, not just the first (MIL-191's design note: a query-engine rule).
|
|
17
|
+
// - `sliceFacts`: the doc join done once via `sliceDocIndex.ts`'s single `readdirSync`.
|
|
18
|
+
// - `invariants`: INV-* id -> declaring slice, extracted from EVERY found slice doc's body
|
|
19
|
+
// regardless of its status — reuses `cli/coverage.ts`'s extraction (never re-derives the
|
|
20
|
+
// ownership-heading / structural-line rules a second time), but NOT coverage's in-scope
|
|
21
|
+
// status gate: that gate decides which invariants must be cited by tests, whereas a lookup
|
|
22
|
+
// ("which slice declares INV-X?") has to find a draft doc's invariant too, and reports the
|
|
23
|
+
// doc's status alongside it. Test citations are NOT precomputed here (a query run only ever
|
|
24
|
+
// asks about one ID at a time — see `em query invariant`) — the CLI/MCP layer calls
|
|
25
|
+
// `scanTestCitations()` (also coverage.ts) directly when `--tests` is given.
|
|
26
|
+
import { semanticEdges, connectionKind } from "./edges.js";
|
|
27
|
+
import { loadSliceDocsOnce, joinSliceDocFast } from "./sliceDocIndex.js";
|
|
28
|
+
import { extractInvariantIds } from "../cli/coverage.js";
|
|
29
|
+
function pushEdge(map, key, edge) {
|
|
30
|
+
const bucket = map.get(key);
|
|
31
|
+
if (bucket)
|
|
32
|
+
bucket.push(edge);
|
|
33
|
+
else
|
|
34
|
+
map.set(key, [edge]);
|
|
35
|
+
}
|
|
36
|
+
export function buildModelIndex(model, refs, baseDir) {
|
|
37
|
+
const byRef = new Map();
|
|
38
|
+
for (const el of model.elements) {
|
|
39
|
+
const ref = refs.refById.get(el.id);
|
|
40
|
+
if (ref)
|
|
41
|
+
byRef.set(ref, el);
|
|
42
|
+
}
|
|
43
|
+
const out = new Map();
|
|
44
|
+
const inMap = new Map();
|
|
45
|
+
for (const e of semanticEdges(model)) {
|
|
46
|
+
const fromRef = refs.refById.get(e.from);
|
|
47
|
+
const toRef = refs.refById.get(e.to);
|
|
48
|
+
const fromEl = model.byId.get(e.from);
|
|
49
|
+
const toEl = model.byId.get(e.to);
|
|
50
|
+
if (!fromRef || !toRef || !fromEl || !toEl)
|
|
51
|
+
continue;
|
|
52
|
+
const kind = connectionKind(fromEl.kind, toEl.kind) ?? "other";
|
|
53
|
+
pushEdge(out, fromRef, { ref: toRef, kind });
|
|
54
|
+
pushEdge(inMap, toRef, { ref: fromRef, kind });
|
|
55
|
+
}
|
|
56
|
+
const byLogical = new Map();
|
|
57
|
+
for (const el of model.elements) {
|
|
58
|
+
if (el.kind !== "view")
|
|
59
|
+
continue;
|
|
60
|
+
const ref = refs.refById.get(el.id);
|
|
61
|
+
if (!ref)
|
|
62
|
+
continue;
|
|
63
|
+
const bucket = byLogical.get(el.logicalId);
|
|
64
|
+
if (bucket)
|
|
65
|
+
bucket.push(ref);
|
|
66
|
+
else
|
|
67
|
+
byLogical.set(el.logicalId, [ref]);
|
|
68
|
+
}
|
|
69
|
+
const instances = new Map();
|
|
70
|
+
for (const group of byLogical.values()) {
|
|
71
|
+
if (group.length < 2)
|
|
72
|
+
continue;
|
|
73
|
+
for (const ref of group)
|
|
74
|
+
instances.set(ref, group.filter((r) => r !== ref));
|
|
75
|
+
}
|
|
76
|
+
const docsByKey = loadSliceDocsOnce(baseDir);
|
|
77
|
+
const sliceFacts = new Map();
|
|
78
|
+
model.slices.forEach((slice, i) => {
|
|
79
|
+
const key = refs.sliceKeys[i];
|
|
80
|
+
const doc = joinSliceDocFast(slice, key, docsByKey);
|
|
81
|
+
sliceFacts.set(key, { key, name: slice.name, index: i, line: slice.line, doc });
|
|
82
|
+
});
|
|
83
|
+
// Two passes, canonical bindings first, so a doc's own slice owns its invariants no matter
|
|
84
|
+
// where a slice it also `covers:` sits in document order (see the `invariants` field doc).
|
|
85
|
+
// A doc that resolves for several slices (its own plus every one it `covers:`) is scanned
|
|
86
|
+
// once, keyed by path — the ids are a property of the doc, not of the slice asking.
|
|
87
|
+
const invariants = new Map();
|
|
88
|
+
const idsByDocPath = new Map();
|
|
89
|
+
const idsOf = (doc) => {
|
|
90
|
+
let ids = idsByDocPath.get(doc.path);
|
|
91
|
+
if (!ids) {
|
|
92
|
+
ids = extractInvariantIds(doc.body);
|
|
93
|
+
idsByDocPath.set(doc.path, ids);
|
|
94
|
+
}
|
|
95
|
+
return ids;
|
|
96
|
+
};
|
|
97
|
+
const claim = (canonical) => {
|
|
98
|
+
for (const { key, doc } of sliceFacts.values()) {
|
|
99
|
+
if (doc.body === null || (doc.path === `slices/${key}.md`) !== canonical)
|
|
100
|
+
continue;
|
|
101
|
+
for (const id of idsOf(doc)) {
|
|
102
|
+
if (!invariants.has(id))
|
|
103
|
+
invariants.set(id, { id, sliceKey: key });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
claim(true);
|
|
108
|
+
claim(false);
|
|
109
|
+
return { model, refs, baseDir, byRef, out, in: inMap, instances, sliceFacts, invariants };
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=queryIndex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queryIndex.js","sourceRoot":"","sources":["../../src/model/queryIndex.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,8FAA8F;AAC9F,gGAAgG;AAChG,+FAA+F;AAC/F,6CAA6C;AAC7C,EAAE;AACF,0FAA0F;AAC1F,iGAAiG;AACjG,2FAA2F;AAC3F,gGAAgG;AAChG,4FAA4F;AAC5F,kFAAkF;AAClF,gGAAgG;AAChG,8FAA8F;AAC9F,4FAA4F;AAC5F,2FAA2F;AAC3F,yFAAyF;AACzF,4FAA4F;AAC5F,4FAA4F;AAC5F,2FAA2F;AAC3F,8FAA8F;AAC9F,8FAA8F;AAC9F,+FAA+F;AAC/F,uFAAuF;AACvF,gFAAgF;AAIhF,OAAO,EAAE,aAAa,EAAE,cAAc,EAAkB,MAAM,YAAY,CAAC;AAC3E,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAiB,MAAM,oBAAoB,CAAC;AACxF,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAoDzD,SAAS,QAAQ,CAAC,GAA6B,EAAE,GAAW,EAAE,IAAe;IAC3E,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC5B,IAAI,MAAM;QAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;;QACzB,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAsB,EAAE,IAAgB,EAAE,OAAe;IACvF,MAAM,KAAK,GAAG,IAAI,GAAG,EAAmB,CAAC;IACzC,KAAK,MAAM,EAAE,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QAChC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACpC,IAAI,GAAG;YAAE,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC9B,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC3C,MAAM,KAAK,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC7C,KAAK,MAAM,CAAC,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACrC,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAClC,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI;YAAE,SAAS;QACrD,MAAM,IAAI,GAAkB,cAAc,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC;QAC9E,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACjD,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC9C,KAAK,MAAM,EAAE,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QAChC,IAAI,EAAE,CAAC,IAAI,KAAK,MAAM;YAAE,SAAS;QACjC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG;YAAE,SAAS;QACnB,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;QAC3C,IAAI,MAAM;YAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;;YACxB,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1C,CAAC;IACD,MAAM,SAAS,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC9C,KAAK,MAAM,KAAK,IAAI,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC;QACvC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS;QAC/B,KAAK,MAAM,GAAG,IAAI,KAAK;YAAE,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,SAAS,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC7C,MAAM,UAAU,GAAG,IAAI,GAAG,EAA0B,CAAC;IACrD,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QAChC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,GAAG,GAAG,gBAAgB,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;QACpD,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IAClF,CAAC,CAAC,CAAC;IAEH,2FAA2F;IAC3F,2FAA2F;IAC3F,0FAA0F;IAC1F,oFAAoF;IACpF,MAAM,UAAU,GAAG,IAAI,GAAG,EAA+B,CAAC;IAC1D,MAAM,YAAY,GAAG,IAAI,GAAG,EAAoB,CAAC;IACjD,MAAM,KAAK,GAAG,CAAC,GAAkB,EAAY,EAAE;QAC7C,IAAI,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,GAAG,GAAG,mBAAmB,CAAC,GAAG,CAAC,IAAK,CAAC,CAAC;YACrC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAClC,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC,CAAC;IACF,MAAM,KAAK,GAAG,CAAC,SAAkB,EAAE,EAAE;QACnC,KAAK,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC;YAC/C,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,UAAU,GAAG,KAAK,CAAC,KAAK,SAAS;gBAAE,SAAS;YACnF,KAAK,MAAM,EAAE,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC5B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBAAE,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;YACrE,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IACF,KAAK,CAAC,IAAI,CAAC,CAAC;IACZ,KAAK,CAAC,KAAK,CAAC,CAAC;IAEb,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC;AAC5F,CAAC"}
|
package/dist/model/rules.d.ts
CHANGED
|
@@ -323,12 +323,81 @@ export declare const RULES: {
|
|
|
323
323
|
readonly fix: "Rename the type so its export ref is unique.";
|
|
324
324
|
readonly usageCategory: "duplicate type ref";
|
|
325
325
|
};
|
|
326
|
+
readonly "duplicate-model-key": {
|
|
327
|
+
readonly severity: "warning";
|
|
328
|
+
readonly title: "Duplicate model key";
|
|
329
|
+
readonly fix: "Give each model a unique `model \"Name\"` so its key (and every cross-model ref) is stable.";
|
|
330
|
+
readonly usageCategory: "duplicate model key";
|
|
331
|
+
};
|
|
326
332
|
readonly "cross-model-slice-doc-collision": {
|
|
327
333
|
readonly severity: "warning";
|
|
328
334
|
readonly title: "Colliding slice doc path across models";
|
|
329
335
|
readonly fix: "Give each model its own directory (see docs/cli.md, \"Multi-model projects\").";
|
|
330
336
|
readonly usageCategory: "colliding slice doc path across models";
|
|
331
337
|
};
|
|
338
|
+
readonly "system-manifest-invalid": {
|
|
339
|
+
readonly severity: "error";
|
|
340
|
+
readonly title: "Seam manifest invalid";
|
|
341
|
+
readonly fix: "Fix the manifest: required keys, `systemSchemaVersion: \"1.0\"`, a readable `source` per model, and only declared model keys in seam refs.";
|
|
342
|
+
readonly usageCategory: "seam manifest invalid";
|
|
343
|
+
readonly docAnchor: "seam-manifest";
|
|
344
|
+
};
|
|
345
|
+
readonly "system-model-key-mismatch": {
|
|
346
|
+
readonly severity: "error";
|
|
347
|
+
readonly title: "Manifest model key differs from the export's `model.key`";
|
|
348
|
+
readonly fix: "Rename the manifest's `models:` key to the computed key the message prints.";
|
|
349
|
+
readonly usageCategory: "seam manifest model key mismatch";
|
|
350
|
+
readonly docAnchor: "seam-manifest";
|
|
351
|
+
};
|
|
352
|
+
readonly "seam-endpoint-unresolved": {
|
|
353
|
+
readonly severity: "error";
|
|
354
|
+
readonly title: "Seam endpoint does not resolve";
|
|
355
|
+
readonly fix: "Fix the ref to an element the named model actually exports (`em export` lists every ref), or re-declare the seam after a rename.";
|
|
356
|
+
readonly usageCategory: "seam endpoint unresolved";
|
|
357
|
+
readonly docAnchor: "seam-manifest";
|
|
358
|
+
};
|
|
359
|
+
readonly "seam-source-not-public": {
|
|
360
|
+
readonly severity: "error";
|
|
361
|
+
readonly title: "Seam source is not `public`";
|
|
362
|
+
readonly fix: "Mark the event/view `public` in its model, or point the seam at the element that is.";
|
|
363
|
+
readonly usageCategory: "seam source not public";
|
|
364
|
+
readonly docAnchor: "seam-manifest";
|
|
365
|
+
};
|
|
366
|
+
readonly "seam-consumer-not-reaction": {
|
|
367
|
+
readonly severity: "error";
|
|
368
|
+
readonly title: "Seam consumer is not a reaction";
|
|
369
|
+
readonly fix: "Point `to` at a translation/automation element (or a slice containing exactly one).";
|
|
370
|
+
readonly usageCategory: "seam consumer not a reaction";
|
|
371
|
+
readonly docAnchor: "seam-manifest";
|
|
372
|
+
};
|
|
373
|
+
readonly "seam-duplicate": {
|
|
374
|
+
readonly severity: "warning";
|
|
375
|
+
readonly title: "Duplicate seam";
|
|
376
|
+
readonly fix: "Remove the repeated `from`/`to` pair.";
|
|
377
|
+
readonly usageCategory: "duplicate seam";
|
|
378
|
+
readonly docAnchor: "seam-manifest";
|
|
379
|
+
};
|
|
380
|
+
readonly "dangling-public-event": {
|
|
381
|
+
readonly severity: "warning";
|
|
382
|
+
readonly title: "Public event/view no seam consumes";
|
|
383
|
+
readonly fix: "Declare the seam that reads it, or drop `public` if nothing outside the model does.";
|
|
384
|
+
readonly usageCategory: "public event not consumed by any seam";
|
|
385
|
+
readonly docAnchor: "seam-manifest";
|
|
386
|
+
};
|
|
387
|
+
readonly "unbound-translation": {
|
|
388
|
+
readonly severity: "warning";
|
|
389
|
+
readonly title: "Externally-fed reaction no seam feeds";
|
|
390
|
+
readonly fix: "Declare the seam whose `to` is this reaction, or give it an in-model `from`.";
|
|
391
|
+
readonly usageCategory: "externally-fed reaction not bound by any seam";
|
|
392
|
+
readonly docAnchor: "seam-manifest";
|
|
393
|
+
};
|
|
394
|
+
readonly "undeclared-seam-candidate": {
|
|
395
|
+
readonly severity: "warning";
|
|
396
|
+
readonly title: "Looks connected across models, no seam declared";
|
|
397
|
+
readonly fix: "Declare the seam, or rename one side so the name match stops looking like a link.";
|
|
398
|
+
readonly usageCategory: "undeclared seam candidate";
|
|
399
|
+
readonly docAnchor: "seam-manifest";
|
|
400
|
+
};
|
|
332
401
|
readonly "slice-ready-unknown-slice": {
|
|
333
402
|
readonly severity: "error";
|
|
334
403
|
readonly title: "Unknown --slice-ready key";
|