@milehimikey/em 1.17.0 → 1.18.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 +46 -5
- package/.claude/skills/event-modeling-discover/SKILL.md +43 -8
- package/.claude/skills/event-modeling-discover/reference/extract.md +6 -1
- package/.claude/skills/event-modeling-discover/reference/prd-rubric.md +102 -0
- package/.claude/skills/event-modeling-discover/reference/prd-spec-path.md +171 -0
- package/.claude/skills/event-modeling-engagement/SKILL.md +8 -3
- package/.claude/skills/event-modeling-implement/SKILL.md +1 -1
- package/.claude/skills/event-modeling-implement/reference/implement.md +8 -0
- package/.claude/skills/event-modeling-review/SKILL.md +1 -1
- package/.claude/skills/event-modeling-shared/reference/em-dsl.md +90 -5
- package/.claude/skills/event-modeling-shared/reference/methodology.md +268 -0
- package/.claude/skills/event-modeling-shared/reference/slice-doc-schema.md +96 -2
- package/.claude/skills/event-modeling-shared/templates/slice.md +11 -3
- package/.claude-plugin/marketplace.json +2 -2
- package/dist/catalog/docModelConsistencyValidate.js +160 -0
- package/dist/catalog/docModelConsistencyValidate.js.map +1 -1
- package/dist/catalog/invariantsValidate.d.ts +2 -0
- package/dist/catalog/invariantsValidate.js +67 -1
- package/dist/catalog/invariantsValidate.js.map +1 -1
- package/dist/catalog/scenarioQualityValidate.d.ts +4 -0
- package/dist/catalog/scenarioQualityValidate.js +148 -0
- package/dist/catalog/scenarioQualityValidate.js.map +1 -0
- package/dist/catalog/scenarios.d.ts +5 -0
- package/dist/catalog/scenarios.js +80 -0
- package/dist/catalog/scenarios.js.map +1 -1
- package/dist/catalog/sliceReadyValidate.d.ts +8 -0
- package/dist/catalog/sliceReadyValidate.js +35 -3
- package/dist/catalog/sliceReadyValidate.js.map +1 -1
- package/dist/catalog/sliceSections.d.ts +3 -2
- package/dist/catalog/sliceSections.js +99 -9
- package/dist/catalog/sliceSections.js.map +1 -1
- package/dist/cli/ciInit.d.ts +4 -11
- package/dist/cli/ciInit.js +24 -6
- package/dist/cli/ciInit.js.map +1 -1
- package/dist/cli/coverage.d.ts +9 -0
- package/dist/cli/coverage.js +18 -0
- package/dist/cli/coverage.js.map +1 -1
- package/dist/cli/defer.d.ts +28 -0
- package/dist/cli/defer.js +87 -4
- package/dist/cli/defer.js.map +1 -1
- package/dist/cli/engagement.d.ts +2 -2
- package/dist/cli/engagement.js +24 -1
- package/dist/cli/engagement.js.map +1 -1
- package/dist/cli/markImplemented.d.ts +14 -10
- package/dist/cli/markImplemented.js +49 -1
- package/dist/cli/markImplemented.js.map +1 -1
- package/dist/cli/prdTriage.d.ts +109 -0
- package/dist/cli/prdTriage.js +378 -0
- package/dist/cli/prdTriage.js.map +1 -0
- package/dist/cli/render-inputs.d.ts +2 -0
- package/dist/cli/render-inputs.js +4 -0
- package/dist/cli/render-inputs.js.map +1 -1
- package/dist/cli/revise.d.ts +2 -0
- package/dist/cli/revise.js +7 -2
- package/dist/cli/revise.js.map +1 -1
- package/dist/cli/shape.d.ts +27 -0
- package/dist/cli/shape.js +77 -0
- package/dist/cli/shape.js.map +1 -0
- package/dist/cli/sliceIndex.d.ts +6 -1
- package/dist/cli/sliceIndex.js +28 -13
- package/dist/cli/sliceIndex.js.map +1 -1
- package/dist/cli/sliceNew.d.ts +4 -1
- package/dist/cli/sliceNew.js +26 -9
- package/dist/cli/sliceNew.js.map +1 -1
- package/dist/cli/status.d.ts +21 -1
- package/dist/cli/status.js +25 -3
- package/dist/cli/status.js.map +1 -1
- package/dist/cli/storylineSuggest.d.ts +26 -0
- package/dist/cli/storylineSuggest.js +252 -0
- package/dist/cli/storylineSuggest.js.map +1 -0
- package/dist/cli/upgrade.d.ts +15 -3
- package/dist/cli/upgrade.js +426 -7
- package/dist/cli/upgrade.js.map +1 -1
- package/dist/cli/upgradeReshape.d.ts +60 -0
- package/dist/cli/upgradeReshape.js +425 -0
- package/dist/cli/upgradeReshape.js.map +1 -0
- package/dist/cli.js +286 -29
- package/dist/cli.js.map +1 -1
- package/dist/emit/dot.d.ts +2 -0
- package/dist/emit/dot.js +44 -8
- package/dist/emit/dot.js.map +1 -1
- package/dist/emit/engagementJson.d.ts +1 -1
- package/dist/emit/engagementJson.js +3 -1
- package/dist/emit/engagementJson.js.map +1 -1
- package/dist/emit/json.d.ts +21 -1
- package/dist/emit/json.js +26 -2
- package/dist/emit/json.js.map +1 -1
- package/dist/emit/queryJson.d.ts +1 -1
- package/dist/emit/queryJson.js +3 -1
- package/dist/emit/queryJson.js.map +1 -1
- package/dist/emit/statusJson.d.ts +1 -1
- package/dist/emit/statusJson.js +6 -1
- package/dist/emit/statusJson.js.map +1 -1
- package/dist/emit/theme.d.ts +1 -0
- package/dist/emit/theme.js +13 -0
- package/dist/emit/theme.js.map +1 -1
- package/dist/emit/validateJson.d.ts +5 -2
- package/dist/emit/validateJson.js +36 -2
- package/dist/emit/validateJson.js.map +1 -1
- package/dist/layout/grid.d.ts +5 -1
- package/dist/layout/grid.js +93 -2
- package/dist/layout/grid.js.map +1 -1
- package/dist/mcp/server.js +46 -11
- package/dist/mcp/server.js.map +1 -1
- package/dist/model/edges.d.ts +7 -0
- package/dist/model/edges.js +33 -16
- package/dist/model/edges.js.map +1 -1
- package/dist/model/model.d.ts +33 -0
- package/dist/model/model.js +87 -3
- package/dist/model/model.js.map +1 -1
- package/dist/model/queryIndex.js +2 -2
- package/dist/model/queryIndex.js.map +1 -1
- package/dist/model/refs.js +8 -5
- package/dist/model/refs.js.map +1 -1
- package/dist/model/rules.d.ts +149 -0
- package/dist/model/rules.js +144 -0
- package/dist/model/rules.js.map +1 -1
- package/dist/model/shapeLint.d.ts +12 -0
- package/dist/model/shapeLint.js +170 -0
- package/dist/model/shapeLint.js.map +1 -0
- package/dist/model/storylines.d.ts +51 -0
- package/dist/model/storylines.js +188 -0
- package/dist/model/storylines.js.map +1 -0
- package/dist/model/validate.d.ts +6 -1
- package/dist/model/validate.js +317 -14
- package/dist/model/validate.js.map +1 -1
- package/dist/parser/againSugar.d.ts +30 -0
- package/dist/parser/againSugar.js +105 -0
- package/dist/parser/againSugar.js.map +1 -0
- package/dist/parser/ast.d.ts +33 -0
- package/dist/parser/lexer.d.ts +2 -0
- package/dist/parser/lexer.js +4 -0
- package/dist/parser/lexer.js.map +1 -1
- package/dist/parser/parser.js +284 -4
- package/dist/parser/parser.js.map +1 -1
- package/dist/query/format.js +1 -0
- package/dist/query/format.js.map +1 -1
- package/dist/query/verbs.d.ts +4 -0
- package/dist/query/verbs.js +30 -3
- package/dist/query/verbs.js.map +1 -1
- package/dist/render/drawEdges.js +100 -4
- package/dist/render/drawEdges.js.map +1 -1
- package/dist/render/render.js +20 -2
- package/dist/render/render.js.map +1 -1
- package/dist/render/sliceDiagram.js +5 -5
- package/dist/render/sliceDiagram.js.map +1 -1
- package/dist/render/storylineBands.d.ts +11 -0
- package/dist/render/storylineBands.js +80 -0
- package/dist/render/storylineBands.js.map +1 -0
- package/dist/render/storylineDiagram.d.ts +14 -0
- package/dist/render/storylineDiagram.js +142 -0
- package/dist/render/storylineDiagram.js.map +1 -0
- package/dist/roster/check.d.ts +32 -0
- package/dist/roster/check.js +92 -0
- package/dist/roster/check.js.map +1 -0
- package/dist/roster/context.d.ts +3 -0
- package/dist/roster/context.js +23 -0
- package/dist/roster/context.js.map +1 -0
- package/dist/roster/init.d.ts +15 -0
- package/dist/roster/init.js +52 -0
- package/dist/roster/init.js.map +1 -0
- package/dist/roster/roster.d.ts +79 -0
- package/dist/roster/roster.js +298 -0
- package/dist/roster/roster.js.map +1 -0
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +2 -2
- package/plugin/shared/reference/em-dsl.md +90 -5
- package/plugin/shared/reference/methodology.md +268 -0
- package/plugin/shared/reference/slice-doc-schema.md +96 -2
- package/plugin/shared/templates/slice.md +11 -3
- package/plugin/skills/conform/SKILL.md +1 -1
- package/plugin/skills/design/SKILL.md +46 -5
- package/plugin/skills/discover/SKILL.md +43 -8
- package/plugin/skills/discover/reference/extract.md +6 -1
- package/plugin/skills/discover/reference/prd-rubric.md +103 -0
- package/plugin/skills/discover/reference/prd-spec-path.md +172 -0
- package/plugin/skills/engagement/SKILL.md +8 -3
- package/plugin/skills/event-modeling/SKILL.md +1 -1
- package/plugin/skills/implement/SKILL.md +1 -1
- package/plugin/skills/implement/reference/implement.md +8 -0
- package/plugin/skills/review/SKILL.md +1 -1
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Scenario-quality advisories (GH #293, was MIL-244): three deterministic warnings over a bound
|
|
3
|
+
// slice doc's authored `### Scenario:` blocks (catalog/scenarios.ts), checked against the `.em`
|
|
4
|
+
// model. Called from validateDocModelConsistency's per-doc loop, so a MIL-121 cross-covered doc is
|
|
5
|
+
// checked once against the UNION of its covered slices. Canon: Dymitruk, "each specification is
|
|
6
|
+
// tied to exactly one command or view"; Dilger's GWT shape (Given events / When command / Then
|
|
7
|
+
// events or error).
|
|
8
|
+
//
|
|
9
|
+
// scenario-when-not-command a scenario's When names none of the slice's commands (for a
|
|
10
|
+
// reaction slice: the triggered command — it is the slice's command).
|
|
11
|
+
// scenario-then-not-outcome Then names neither one of the slice's events (any alternative or
|
|
12
|
+
// shared event counts) nor a rejection/error phrase.
|
|
13
|
+
// invariant-without-scenario an INV-* declared for the slice (model `invariant` line or the
|
|
14
|
+
// doc's Invariants section) is cited by no scenario. Convention:
|
|
15
|
+
// a scenario cites the INV ids it exercises, anywhere in its block.
|
|
16
|
+
//
|
|
17
|
+
// Silent by construction on a doc with no `### Scenario:` blocks (every 1.13 free-prose doc) and,
|
|
18
|
+
// for the first two, on a slice with no command (a State View slice has no When). Names compare
|
|
19
|
+
// with case, spacing and punctuation stripped, so `OrderPlaced` matches the event "Order Placed".
|
|
20
|
+
import { readFileSync } from "node:fs";
|
|
21
|
+
import { join } from "node:path";
|
|
22
|
+
import { collectModelInvariants } from "../model/model.js";
|
|
23
|
+
import { pushDiag } from "../model/rules.js";
|
|
24
|
+
import { INV_TOKEN_RE } from "../cli/coverage.js";
|
|
25
|
+
import { parseScenariosLenient } from "./scenarios.js";
|
|
26
|
+
import { AUTOMATION_KINDS } from "../parser/ast.js";
|
|
27
|
+
// A stated outcome that is not an event: a rejection/error, or a deliberate no-op (an automation
|
|
28
|
+
// or translation that correctly does nothing: "nothing is dispatched", "no second event", "no
|
|
29
|
+
// command is issued", "success; no second event").
|
|
30
|
+
const REJECTION_RE = /\b(reject\w*|refus\w*|den(?:y|ies|ied)|errors?|fail(?:s|ed|ure)?|invalid|not allowed|forbidden|exceptions?|unauthori[sz]ed|violat\w*|nothing|no[- ]op|no second|not (?:re-?)?(?:dispatched|issued|emitted|recorded|sent|raised)|no\b[^.;]{0,40}\b(?:events?|commands?)\b)/i;
|
|
31
|
+
const squash = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, "");
|
|
32
|
+
function names(els) {
|
|
33
|
+
return els.map((e) => squash(e.name)).filter((n) => n !== "");
|
|
34
|
+
}
|
|
35
|
+
function mentionsAny(text, squashedNames) {
|
|
36
|
+
const t = squash(text);
|
|
37
|
+
return squashedNames.some((n) => t.includes(n));
|
|
38
|
+
}
|
|
39
|
+
/** Ids this slice DECLARES, from a doc body: the first INV token of each top-level line of the
|
|
40
|
+
* Invariants section (later tokens on the line cite other rules, often another slice's), and the
|
|
41
|
+
* stable id on each `#### Requirement:` / MODIFIED line under Delta's Added/Modified (never
|
|
42
|
+
* Removed or Renamed - those retire ids). */
|
|
43
|
+
function declaredInDoc(body) {
|
|
44
|
+
const ids = [];
|
|
45
|
+
const add = (line) => {
|
|
46
|
+
const m = line.match(INV_TOKEN_RE);
|
|
47
|
+
if (m && !ids.includes(m[0]))
|
|
48
|
+
ids.push(m[0]);
|
|
49
|
+
};
|
|
50
|
+
let section = null;
|
|
51
|
+
let sub = null;
|
|
52
|
+
for (const line of body.split(/\r?\n/)) {
|
|
53
|
+
if (/^#{1,2}\s/.test(line)) {
|
|
54
|
+
section = /^##\s+Invariants\b/i.test(line) ? "inv" : /^##\s+Delta\s*$/i.test(line) ? "delta" : null;
|
|
55
|
+
sub = null;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (section === "inv" && /^[-*]\s/.test(line))
|
|
59
|
+
add(line);
|
|
60
|
+
if (section === "delta") {
|
|
61
|
+
const h = /^###\s+(Added|Modified|Removed|Renamed)\b/.exec(line);
|
|
62
|
+
if (h)
|
|
63
|
+
sub = h[1];
|
|
64
|
+
else if ((sub === "Added" || sub === "Modified") && /^(?:#{4,6}\s|[-*]\s)/.test(line))
|
|
65
|
+
add(line);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return ids;
|
|
69
|
+
}
|
|
70
|
+
export function checkScenarioQuality(diags, body, docPath, sliceIndices, ownerKey, model, refs, baseDir) {
|
|
71
|
+
let text = body;
|
|
72
|
+
let located = false;
|
|
73
|
+
try {
|
|
74
|
+
text = readFileSync(join(baseDir, docPath), "utf8"); // full file, so scenario lines are doc-file lines
|
|
75
|
+
located = true;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// unreadable: parse the body, lines unknown
|
|
79
|
+
}
|
|
80
|
+
const scenarios = parseScenariosLenient(text);
|
|
81
|
+
if (scenarios.length === 0)
|
|
82
|
+
return;
|
|
83
|
+
const els = [];
|
|
84
|
+
for (const i of sliceIndices)
|
|
85
|
+
els.push(...model.slices[i].elements);
|
|
86
|
+
const commands = els.filter((e) => e.kind === "command");
|
|
87
|
+
const events = els.filter((e) => e.kind === "event");
|
|
88
|
+
const cmdNames = names(commands);
|
|
89
|
+
const evtNames = names(events);
|
|
90
|
+
// A reaction slice's When may name the reaction itself or the view it reads, not only the command.
|
|
91
|
+
const reactions = els.filter((e) => AUTOMATION_KINDS.has(e.kind));
|
|
92
|
+
const whenNames = reactions.length > 0 ? [...cmdNames, ...names(reactions), ...names(els.filter((e) => e.kind === "view"))] : cmdNames;
|
|
93
|
+
const at = (s) => `${docPath}${located ? `:${s.line}` : ""} scenario "${s.title}"`;
|
|
94
|
+
if (commands.length > 0) {
|
|
95
|
+
const anchor = commands[0];
|
|
96
|
+
const modelRefs = [refs.sliceKeys[anchor.sliceIndex], refs.refById.get(anchor.id)];
|
|
97
|
+
const accepted = [...commands, ...(reactions.length > 0 ? [...reactions, ...els.filter((e) => e.kind === "view")] : [])];
|
|
98
|
+
const cmdList = accepted.map((c) => `${c.kind} "${c.name}"`).join(", ");
|
|
99
|
+
for (const s of scenarios) {
|
|
100
|
+
if (!s.when.some((w) => mentionsAny(w, whenNames))) {
|
|
101
|
+
pushDiag(diags, "scenario-when-not-command", {
|
|
102
|
+
message: `${at(s)}: When does not name the slice's command${reactions.length > 0 ? ", reaction or the view it reads" : ""} (accepted: ${cmdList}) — a scenario is tied to exactly one command`,
|
|
103
|
+
line: anchor.line,
|
|
104
|
+
refs: modelRefs,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
if (!s.then.some((t) => mentionsAny(t, evtNames) || REJECTION_RE.test(t))) {
|
|
108
|
+
const evtList = events.length > 0 ? events.map((e) => `"${e.name}"`).join(", ") : "none declared";
|
|
109
|
+
pushDiag(diags, "scenario-then-not-outcome", {
|
|
110
|
+
message: `${at(s)}: Then names none of the slice's events (${evtList}) and no rejection/error — state the event(s) recorded, or the rejection`,
|
|
111
|
+
line: anchor.line,
|
|
112
|
+
refs: modelRefs,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Declared for the slice: model `invariant` lines on its elements, plus the doc's own section.
|
|
118
|
+
const cited = new Set();
|
|
119
|
+
for (const s of scenarios) {
|
|
120
|
+
for (const text of [s.title, ...s.given, ...s.when, ...s.then])
|
|
121
|
+
for (const m of text.matchAll(INV_TOKEN_RE))
|
|
122
|
+
cited.add(m[0]);
|
|
123
|
+
}
|
|
124
|
+
const reported = new Set();
|
|
125
|
+
const elIds = new Set(els.map((e) => e.id));
|
|
126
|
+
for (const inv of collectModelInvariants(model)) {
|
|
127
|
+
if (!elIds.has(inv.element.id) || cited.has(inv.id) || reported.has(inv.id))
|
|
128
|
+
continue;
|
|
129
|
+
reported.add(inv.id);
|
|
130
|
+
pushDiag(diags, "invariant-without-scenario", {
|
|
131
|
+
message: `invariant ${inv.id} (${inv.element.kind} "${inv.element.name}") is cited by no scenario in ${docPath} — cite the INV id in the scenario that exercises it`,
|
|
132
|
+
line: inv.line,
|
|
133
|
+
refs: [refs.sliceKeys[inv.element.sliceIndex], refs.refById.get(inv.element.id)],
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
const ownerSlice = model.slices[sliceIndices.find((i) => refs.sliceKeys[i] === ownerKey) ?? sliceIndices[0]];
|
|
137
|
+
for (const id of declaredInDoc(body)) {
|
|
138
|
+
if (cited.has(id) || reported.has(id))
|
|
139
|
+
continue;
|
|
140
|
+
reported.add(id);
|
|
141
|
+
pushDiag(diags, "invariant-without-scenario", {
|
|
142
|
+
message: `invariant ${id} (declared in ${docPath}) is cited by no scenario — cite the INV id in the scenario that exercises it`,
|
|
143
|
+
line: ownerSlice.line,
|
|
144
|
+
refs: [ownerKey],
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=scenarioQualityValidate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scenarioQualityValidate.js","sourceRoot":"","sources":["../../src/catalog/scenarioQualityValidate.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,3 +13,8 @@ export interface ScenarioParseResult {
|
|
|
13
13
|
/** Parse every `### Scenario:` block of a slice doc's body (or whole text — the frontmatter
|
|
14
14
|
* never holds a `## Scenarios` heading). */
|
|
15
15
|
export declare function parseScenarios(body: string): ScenarioParseResult;
|
|
16
|
+
export interface LenientScenario extends Scenario {
|
|
17
|
+
/** 1-based line of the block's heading / title bullet within the text that was parsed. */
|
|
18
|
+
line: number;
|
|
19
|
+
}
|
|
20
|
+
export declare function parseScenariosLenient(text: string): LenientScenario[];
|
|
@@ -94,4 +94,84 @@ export function parseScenarios(body) {
|
|
|
94
94
|
}
|
|
95
95
|
return { scenarios, problems };
|
|
96
96
|
}
|
|
97
|
+
const ANY_SCENARIO_HEADING_RE = /^#{3,6}\s+Scenario:\s*(.*?)\s*$/;
|
|
98
|
+
const TITLE_BULLET_RE = /^[-*]\s+\*\*([^*]+?)\*\*\s*$/;
|
|
99
|
+
const ANY_LABEL_RE = /^(\s*)[-*]\s+\*\*(Given|When|Then):\*\*\s*(.*?)\s*$/;
|
|
100
|
+
const ANY_BULLET_RE = /^(\s*)[-*]\s+(.*?)\s*$/;
|
|
101
|
+
export function parseScenariosLenient(text) {
|
|
102
|
+
const lines = text.split(/\r?\n/);
|
|
103
|
+
const out = [];
|
|
104
|
+
let section = null;
|
|
105
|
+
let cur = null;
|
|
106
|
+
let beat = null;
|
|
107
|
+
let labelIndent = 0;
|
|
108
|
+
let lastItem = null;
|
|
109
|
+
const flush = () => {
|
|
110
|
+
if (cur && (cur.beats.given.length || cur.beats.when.length || cur.beats.then.length)) {
|
|
111
|
+
out.push({ title: cur.title, line: cur.line, given: cur.beats.given, when: cur.beats.when, then: cur.beats.then });
|
|
112
|
+
}
|
|
113
|
+
cur = null;
|
|
114
|
+
beat = null;
|
|
115
|
+
lastItem = null;
|
|
116
|
+
};
|
|
117
|
+
const start = (title, line) => {
|
|
118
|
+
flush();
|
|
119
|
+
cur = { title, line, beats: { given: [], when: [], then: [] } };
|
|
120
|
+
};
|
|
121
|
+
const push = (b, t) => {
|
|
122
|
+
if (!cur || t === "")
|
|
123
|
+
return;
|
|
124
|
+
cur.beats[b].push(t);
|
|
125
|
+
lastItem = { arr: cur.beats[b], idx: cur.beats[b].length - 1 };
|
|
126
|
+
};
|
|
127
|
+
lines.forEach((line, i) => {
|
|
128
|
+
if (/^#{1,2}\s/.test(line)) {
|
|
129
|
+
flush();
|
|
130
|
+
section = /^##\s+Scenarios\b/.test(line) ? "scenarios" : /^##\s+Delta\b/.test(line) ? "delta" : null;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (!section)
|
|
134
|
+
return;
|
|
135
|
+
const heading = ANY_SCENARIO_HEADING_RE.exec(line);
|
|
136
|
+
if (heading) {
|
|
137
|
+
start(heading[1], i + 1);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (/^#{3,6}\s/.test(line)) {
|
|
141
|
+
flush();
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const label = ANY_LABEL_RE.exec(line);
|
|
145
|
+
if (label && cur) {
|
|
146
|
+
beat = label[2].toLowerCase();
|
|
147
|
+
labelIndent = label[1].length;
|
|
148
|
+
push(beat, label[3]);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (section === "scenarios" && !/^\s/.test(line)) {
|
|
152
|
+
const t = TITLE_BULLET_RE.exec(line);
|
|
153
|
+
if (t) {
|
|
154
|
+
start(t[1], i + 1);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (!cur)
|
|
159
|
+
return;
|
|
160
|
+
const bullet = ANY_BULLET_RE.exec(line);
|
|
161
|
+
if (bullet && beat && bullet[1].length > labelIndent) {
|
|
162
|
+
push(beat, bullet[2]);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (line.trim() === "")
|
|
166
|
+
return;
|
|
167
|
+
if (/^\s/.test(line) && lastItem && !bullet) {
|
|
168
|
+
lastItem.arr[lastItem.idx] += ` ${line.trim()}`; // wrapped continuation of the previous item
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
if (!/^\s/.test(line))
|
|
172
|
+
beat = null; // any other column-0 line ends the current beat
|
|
173
|
+
});
|
|
174
|
+
flush();
|
|
175
|
+
return out;
|
|
176
|
+
}
|
|
97
177
|
//# sourceMappingURL=scenarios.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scenarios.js","sourceRoot":"","sources":["../../src/catalog/scenarios.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"scenarios.js","sourceRoot":"","sources":["../../src/catalog/scenarios.ts"],"names":[],"mappings":"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"}
|
|
@@ -22,6 +22,10 @@ export interface SliceReadyOptions {
|
|
|
22
22
|
* fakes `ratifiedBy`/`ratifiedOn` without a hash passes readiness with no integrity check
|
|
23
23
|
* otherwise, which is the hole this closes. */
|
|
24
24
|
requireRatifiedHash?: boolean;
|
|
25
|
+
/** `--strict` (GH #293): advisory-rule diagnostics (RuleDef.advisory) are promoted to errors and gate. */
|
|
26
|
+
strict?: boolean;
|
|
27
|
+
/** GH #259: explicit roster path (`--roster`); omitted = the nearest `ratifiers.yaml` above the model. */
|
|
28
|
+
rosterPath?: string;
|
|
25
29
|
}
|
|
26
30
|
export declare function validateSliceReady(model: NormalizedModel, refs: RefsResult, baseDir: string, sliceKey: string, contract: ContractCheckInput, options?: SliceReadyOptions): Diagnostic[];
|
|
27
31
|
/** The named gate conditions `em validate --slice-ready <key> --json` reports individually
|
|
@@ -73,7 +77,11 @@ export declare function computeSliceReadyGates(model: NormalizedModel, refs: Ref
|
|
|
73
77
|
* "no scoped diagnostics". `result` is `computeSliceReadyGates`' named gates (null for an
|
|
74
78
|
* unknown key). */
|
|
75
79
|
export interface SliceReadiness {
|
|
80
|
+
/** Blocking diagnostics concerning this slice — what `ready` is derived from. */
|
|
76
81
|
scoped: Diagnostic[];
|
|
82
|
+
/** GH #293: advisory-rule diagnostics concerning this slice (listed, never gating). Empty under
|
|
83
|
+
* `strict`, which promotes them into `scoped` as errors. */
|
|
84
|
+
advisories: Diagnostic[];
|
|
77
85
|
ready: boolean;
|
|
78
86
|
result: SliceReadyResult | null;
|
|
79
87
|
}
|
|
@@ -25,12 +25,15 @@
|
|
|
25
25
|
// with `refs: [sliceKey]`, so the `--slice-ready` branch filters the full combined diagnostic
|
|
26
26
|
// set by that ref instead of this module re-deriving classifyImplementationDrift.
|
|
27
27
|
import { resolveSliceKey } from "../model/resolveSlice.js";
|
|
28
|
-
import { makeDiag, pushDiag } from "../model/rules.js";
|
|
28
|
+
import { makeDiag, pushDiag, RULES } from "../model/rules.js";
|
|
29
29
|
import { resolveSliceDocJoin } from "./docJoin.js";
|
|
30
30
|
import { readSliceDoc } from "./readSliceDoc.js";
|
|
31
31
|
import { ratifiedHashScope } from "./sliceDoc.js";
|
|
32
32
|
import { findStructuredSectionProblems } from "./sliceSections.js";
|
|
33
33
|
import { contractStatus, slicePublicTouching } from "./apiFirst.js";
|
|
34
|
+
import { isGrandfatheredSignoff, loadRoster, rosterRefusal, sliceContexts } from "../roster/roster.js";
|
|
35
|
+
import { rosterContextFor } from "../roster/context.js";
|
|
36
|
+
import { computeModelKey } from "../model/qualifiedRef.js";
|
|
34
37
|
/** MIL-238 (briefing R10): the API-first gate's diagnostic for one slice, or null when the slice
|
|
35
38
|
* touches no public element or its model's contract is current. Independent of the slice doc —
|
|
36
39
|
* the contract belongs to the model — so it is appended on every path past the unknown-key check. */
|
|
@@ -123,6 +126,29 @@ export function validateSliceReady(model, refs, baseDir, sliceKey, contract, opt
|
|
|
123
126
|
refs: [sliceKey],
|
|
124
127
|
});
|
|
125
128
|
}
|
|
129
|
+
// GH #259: with a ratifier roster present, a `ratifiedBy` it does not permit for this slice's
|
|
130
|
+
// context — the hand-edited-frontmatter case `em slice ratify`'s own refusal cannot see.
|
|
131
|
+
// `grandfathered ...` is em's own migration marker, not a signer, so it is exempt (it stays a
|
|
132
|
+
// finding of --require-ratified-hash and a human re-ratify item). Only `ready-to-implement`
|
|
133
|
+
// docs are checked here; `em roster check` also covers shipped docs.
|
|
134
|
+
if (doc.status === "ready-to-implement" && doc.ratifiedBy && !isGrandfatheredSignoff(doc.ratifiedBy, doc.ratifiedHash)) {
|
|
135
|
+
const roster = loadRoster(baseDir, options.rosterPath, rosterContextFor(model, contract.file));
|
|
136
|
+
if (roster.state === "invalid") {
|
|
137
|
+
for (const d of roster.diagnostics) {
|
|
138
|
+
pushDiag(diags, "roster-invalid", { message: `${roster.path}: ${d.message}`, line: slice.line, refs: [sliceKey] });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
else if (roster.state === "present") {
|
|
142
|
+
const why = rosterRefusal(roster.roster, "ratifiers", doc.ratifiedBy, sliceContexts(model, sliceIndex), computeModelKey(model, contract.file));
|
|
143
|
+
if (why !== null) {
|
|
144
|
+
pushDiag(diags, "ratified-by-not-in-roster", {
|
|
145
|
+
message: `slice "${sliceKey}": ratifiedBy ${why} (${roster.path}) — re-ratify with a permitted name, or update the roster`,
|
|
146
|
+
line: slice.line,
|
|
147
|
+
refs: [sliceKey],
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
126
152
|
// GH #256: strict mode — the body-changed check above can only run when a hash exists, so
|
|
127
153
|
// without this a `ready-to-implement` doc whose frontmatter was hand-edited to carry
|
|
128
154
|
// `ratifiedBy`/`ratifiedOn` and no `ratifiedHash` passes with no integrity check at all.
|
|
@@ -178,8 +204,14 @@ export function computeSliceReadyGates(model, refs, baseDir, sliceKey, contract)
|
|
|
178
204
|
export function computeSliceReadiness(model, refs, baseDir, sliceKey, contract, allDiagnostics, options = {}) {
|
|
179
205
|
const readyDiagnostics = validateSliceReady(model, refs, baseDir, sliceKey, contract, options);
|
|
180
206
|
const combined = [...allDiagnostics, ...readyDiagnostics];
|
|
181
|
-
const
|
|
207
|
+
const concerning = combined.filter((d) => d.refs?.some((r) => r === sliceKey || r.startsWith(`${sliceKey}/`)));
|
|
208
|
+
const isAdvisory = (d) => RULES[d.code]?.advisory === true;
|
|
209
|
+
const strict = options.strict === true;
|
|
210
|
+
const scoped = concerning
|
|
211
|
+
.filter((d) => strict || !isAdvisory(d))
|
|
212
|
+
.map((d) => (strict && isAdvisory(d) ? { ...d, severity: "error" } : d));
|
|
213
|
+
const advisories = strict ? [] : concerning.filter(isAdvisory);
|
|
182
214
|
const result = computeSliceReadyGates(model, refs, baseDir, sliceKey, contract);
|
|
183
|
-
return { scoped, ready: scoped.length === 0, result };
|
|
215
|
+
return { scoped, advisories, ready: scoped.length === 0, result };
|
|
184
216
|
}
|
|
185
217
|
//# sourceMappingURL=sliceReadyValidate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sliceReadyValidate.js","sourceRoot":"","sources":["../../src/catalog/sliceReadyValidate.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,4FAA4F;AAC5F,2FAA2F;AAC3F,0FAA0F;AAC1F,6FAA6F;AAC7F,qBAAqB;AACrB,EAAE;AACF,qFAAqF;AACrF,uFAAuF;AACvF,4FAA4F;AAC5F,8FAA8F;AAC9F,+FAA+F;AAC/F,4FAA4F;AAC5F,8DAA8D;AAC9D,EAAE;AACF,gGAAgG;AAChG,uFAAuF;AACvF,6FAA6F;AAC7F,gGAAgG;AAChG,kGAAkG;AAClG,2DAA2D;AAC3D,EAAE;AACF,8FAA8F;AAC9F,6FAA6F;AAC7F,8FAA8F;AAC9F,kFAAkF;AAIlF,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAE3D,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"sliceReadyValidate.js","sourceRoot":"","sources":["../../src/catalog/sliceReadyValidate.ts"],"names":[],"mappings":"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"}
|
|
@@ -22,8 +22,9 @@ export declare function regionKindOf(name: string): RegionKind | null;
|
|
|
22
22
|
* The generated regions a doc bound to `sliceIndices` (one slice, or the union a MIL-121
|
|
23
23
|
* cross-covered doc / a MIL-208 continuation resolves to) should carry, in template order:
|
|
24
24
|
* commands, events, views, invariants. Elements are taken in slice order then declaration
|
|
25
|
-
* order; a repeated view (`again`)
|
|
26
|
-
* kind with the same slug only the
|
|
25
|
+
* order; the first instance of a repeated view (`again`) owns the row (its sources are the
|
|
26
|
+
* union across instances, GH #280), and two elements of one kind with the same slug only the
|
|
27
|
+
* first.
|
|
27
28
|
*/
|
|
28
29
|
export declare function buildSliceRegions(model: NormalizedModel, sliceIndices: number[]): GeneratedRegion[];
|
|
29
30
|
/** The template's placeholder regions — what `em slice new` writes when it has no model to fill
|
|
@@ -23,7 +23,9 @@
|
|
|
23
23
|
//
|
|
24
24
|
// Pure: model in, region bodies (as line arrays, EOL-free) out; doc text in, regions/problems
|
|
25
25
|
// out. The CLI (`em slice new`, cli/sliceSync.ts) owns every read and write.
|
|
26
|
-
import { normalizeName } from "../model/model.js";
|
|
26
|
+
import { normalizeName, resolveTypeRef } from "../model/model.js";
|
|
27
|
+
import { againInstancesOf, viewSourceNames } from "../model/continuation.js";
|
|
28
|
+
import { alternativesOf } from "../layout/grid.js";
|
|
27
29
|
import { kebabSlug } from "../util/slug.js";
|
|
28
30
|
import { parseScenarios } from "./scenarios.js";
|
|
29
31
|
export const SLICE_REGION_PREFIX = "em-slice-";
|
|
@@ -100,9 +102,50 @@ function eventBody(model, el) {
|
|
|
100
102
|
}
|
|
101
103
|
return out;
|
|
102
104
|
}
|
|
105
|
+
const COLLECTION_VERBS = {
|
|
106
|
+
created: "contains", added: "contains", attached: "contains",
|
|
107
|
+
deleted: "omits", removed: "omits", detached: "omits",
|
|
108
|
+
updated: "updates", renamed: "updates", changed: "updates",
|
|
109
|
+
};
|
|
110
|
+
/** The verb a collection event's trailing word implies, or undefined when it is not in the list. */
|
|
111
|
+
function collectionVerb(eventName) {
|
|
112
|
+
const words = eventName.trim().split(/[\s_-]+|(?=[A-Z])/).filter(Boolean);
|
|
113
|
+
return COLLECTION_VERBS[(words[words.length - 1] ?? "").toLowerCase()];
|
|
114
|
+
}
|
|
115
|
+
/** An `event A | B @Ctx` line's event region (GH #278): one "records one of" heading, then each
|
|
116
|
+
* alternative as its own `**Event:**` marker with its own field table. */
|
|
117
|
+
function alternativesBody(model, lead) {
|
|
118
|
+
const out = ["**Records one of:**", ""];
|
|
119
|
+
alternativesOf(model, lead).forEach((alt, i) => {
|
|
120
|
+
if (i > 0)
|
|
121
|
+
out.push("");
|
|
122
|
+
out.push(...eventBody(model, alt));
|
|
123
|
+
});
|
|
124
|
+
return out;
|
|
125
|
+
}
|
|
103
126
|
function viewBody(model, el) {
|
|
104
|
-
|
|
105
|
-
const
|
|
127
|
+
// The union across every `again` instance (GH #280): each instance lists only the NEW events.
|
|
128
|
+
const sources = viewSourceNames(model, el);
|
|
129
|
+
// Each later event is annotated with the slice of the `again` instance that adds it; the
|
|
130
|
+
// originating instance's events carry no annotation.
|
|
131
|
+
const origin = model.byId.get(el.logicalId) ?? el;
|
|
132
|
+
const via = new Map();
|
|
133
|
+
const originNames = new Set((origin.from ?? []).map(normalizeName));
|
|
134
|
+
for (const inst of againInstancesOf(model, origin)) {
|
|
135
|
+
for (const n of inst.from ?? []) {
|
|
136
|
+
const k = normalizeName(n);
|
|
137
|
+
if (!originNames.has(k) && !via.has(k))
|
|
138
|
+
via.set(k, model.slices[inst.sliceIndex].name);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const built = sources.length > 0
|
|
142
|
+
? sources
|
|
143
|
+
.map((s) => {
|
|
144
|
+
const slice = via.get(normalizeName(s));
|
|
145
|
+
return slice === undefined ? `"${s}"` : `"${s}" (via "${slice}")`;
|
|
146
|
+
})
|
|
147
|
+
.join(", ")
|
|
148
|
+
: "—";
|
|
106
149
|
const out = [`- **View:** \`${el.name}\` built from events: ${built}`, ""];
|
|
107
150
|
if (!el.fields || el.fields.length === 0)
|
|
108
151
|
return [...out, NO_FIELDS];
|
|
@@ -113,9 +156,16 @@ function viewBody(model, el) {
|
|
|
113
156
|
if (ev)
|
|
114
157
|
sourceEvents.push(ev);
|
|
115
158
|
}
|
|
159
|
+
const collections = [];
|
|
116
160
|
for (const f of el.fields) {
|
|
117
161
|
let note;
|
|
118
|
-
|
|
162
|
+
const resolved = resolveTypeRef(f.type, model.typesByName);
|
|
163
|
+
if (f.derived === true && resolved?.array === true && f.derivedFrom && f.derivedFrom.length > 0) {
|
|
164
|
+
// Collection of a declared type, fed by child events (GH #288).
|
|
165
|
+
note = `Collection of \`${resolved.typeDecl.name}\`, fed by ${f.derivedFrom.map((n) => `\`${n}\``).join(", ")}`;
|
|
166
|
+
collections.push({ field: f.name, events: f.derivedFrom });
|
|
167
|
+
}
|
|
168
|
+
else if (f.derived === true) {
|
|
119
169
|
note = f.derivedFrom && f.derivedFrom.length > 0 ? `Derived from ${f.derivedFrom.map((n) => `"${n}"`).join(", ")}` : "Derived";
|
|
120
170
|
}
|
|
121
171
|
else {
|
|
@@ -124,6 +174,17 @@ function viewBody(model, el) {
|
|
|
124
174
|
}
|
|
125
175
|
out.push(`| ${cell(f.name)} | ${cell(f.type ?? "—")} | ${cell(note)} |`);
|
|
126
176
|
}
|
|
177
|
+
// Behaviour of a collection lives in scenarios, not the model (GH #288): one NEUTRAL stub per
|
|
178
|
+
// named event (order is not significant). The verb is pre-filled only when the event name ends
|
|
179
|
+
// in a known word; otherwise the placeholder stays. The region is generated and read-only, so
|
|
180
|
+
// the author copies the stubs into `## Scenarios` and completes them there.
|
|
181
|
+
for (const c of collections) {
|
|
182
|
+
out.push("", `Scenario stubs for \`${c.field}\` (copy into \`## Scenarios\` and complete them there):`, "");
|
|
183
|
+
for (const e of c.events) {
|
|
184
|
+
const verb = collectionVerb(e) ?? "{{ contains / omits / updates }}";
|
|
185
|
+
out.push(`### Scenario: ${c.field} after ${e}`, `- **Given:** \`${e}\` {{ }}`, "- **When:** {{ the view is queried }}", `- **Then:** \`${c.field}\` ${verb} {{ }}`, "");
|
|
186
|
+
}
|
|
187
|
+
}
|
|
127
188
|
return out;
|
|
128
189
|
}
|
|
129
190
|
function noneBody(kind) {
|
|
@@ -134,8 +195,9 @@ function noneBody(kind) {
|
|
|
134
195
|
* The generated regions a doc bound to `sliceIndices` (one slice, or the union a MIL-121
|
|
135
196
|
* cross-covered doc / a MIL-208 continuation resolves to) should carry, in template order:
|
|
136
197
|
* commands, events, views, invariants. Elements are taken in slice order then declaration
|
|
137
|
-
* order; a repeated view (`again`)
|
|
138
|
-
* kind with the same slug only the
|
|
198
|
+
* order; the first instance of a repeated view (`again`) owns the row (its sources are the
|
|
199
|
+
* union across instances, GH #280), and two elements of one kind with the same slug only the
|
|
200
|
+
* first.
|
|
139
201
|
*/
|
|
140
202
|
export function buildSliceRegions(model, sliceIndices) {
|
|
141
203
|
const ordered = [...sliceIndices].sort((a, b) => a - b);
|
|
@@ -150,6 +212,9 @@ export function buildSliceRegions(model, sliceIndices) {
|
|
|
150
212
|
for (const el of elements) {
|
|
151
213
|
if (el.kind !== kind)
|
|
152
214
|
continue;
|
|
215
|
+
// A non-first alternative is rendered inside its lead's region (alternativesBody).
|
|
216
|
+
if (el.alternativeGroup !== undefined && el.alternativeGroup !== el.id)
|
|
217
|
+
continue;
|
|
153
218
|
if (seenLogical.has(el.logicalId))
|
|
154
219
|
continue;
|
|
155
220
|
seenLogical.add(el.logicalId);
|
|
@@ -159,7 +224,8 @@ export function buildSliceRegions(model, sliceIndices) {
|
|
|
159
224
|
seenSlug.add(s);
|
|
160
225
|
els.push(el);
|
|
161
226
|
}
|
|
162
|
-
const
|
|
227
|
+
const eventRegion = (m, e) => e.alternativeGroup !== undefined ? alternativesBody(m, e) : eventBody(m, e);
|
|
228
|
+
const build = kind === "command" ? commandBody : kind === "event" ? eventRegion : viewBody;
|
|
163
229
|
if (els.length === 0) {
|
|
164
230
|
regions.push({ name: `${SLICE_REGION_PREFIX}${kind}`, kind, body: noneBody(kind) });
|
|
165
231
|
}
|
|
@@ -171,16 +237,40 @@ export function buildSliceRegions(model, sliceIndices) {
|
|
|
171
237
|
regions.push({ name: `${SLICE_REGION_PREFIX}${kind}-${kebabSlug(el.name)}`, kind, body: build(model, el) });
|
|
172
238
|
}
|
|
173
239
|
}
|
|
174
|
-
const
|
|
240
|
+
const invEntries = [];
|
|
241
|
+
const seenAltInv = new Set();
|
|
175
242
|
for (const el of elements) {
|
|
176
243
|
if (el.kind !== "command" && el.kind !== "event")
|
|
177
244
|
continue;
|
|
178
245
|
for (const inv of el.invariants ?? []) {
|
|
246
|
+
let suffix = "";
|
|
247
|
+
if (el.alternativeGroup !== undefined) {
|
|
248
|
+
// GH #278: a rule every alternative carries is one rule (listed once); one declared inside
|
|
249
|
+
// a `oneof` binds to its own alternative only, and the list says so.
|
|
250
|
+
const alts = elements.filter((e) => e.sliceIndex === el.sliceIndex && e.alternativeGroup === el.alternativeGroup);
|
|
251
|
+
if (alts.every((e) => (e.invariants ?? []).some((i) => i.id === inv.id))) {
|
|
252
|
+
const k = `${el.sliceIndex}|${el.alternativeGroup}|${inv.id}`;
|
|
253
|
+
if (seenAltInv.has(k))
|
|
254
|
+
continue;
|
|
255
|
+
seenAltInv.add(k);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
suffix = ` — binds to \`${el.name}\` only`;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
179
261
|
// `**INV-X**` + an em-dash — deliberately NOT the `**INV-X:**` declaring label
|
|
180
262
|
// (invariants/declared-in-both): the model declares the ID, this list only restates it.
|
|
181
|
-
|
|
263
|
+
invEntries.push({
|
|
264
|
+
slice: el.sliceIndex,
|
|
265
|
+
line: inv.line,
|
|
266
|
+
text: (inv.rule ? `- **${inv.id}** — ${inv.rule}` : `- **${inv.id}**`) + suffix,
|
|
267
|
+
});
|
|
182
268
|
}
|
|
183
269
|
}
|
|
270
|
+
// Source order (the alternatives' shared rules are cloned onto each alternative, so element
|
|
271
|
+
// order alone would put them out of place).
|
|
272
|
+
invEntries.sort((x, y) => x.slice - y.slice || x.line - y.line);
|
|
273
|
+
const invLines = invEntries.map((e) => e.text);
|
|
184
274
|
regions.push({
|
|
185
275
|
name: `${SLICE_REGION_PREFIX}invariants`,
|
|
186
276
|
kind: "invariants",
|