dsh-logicprobe 1.3.0 → 1.4.1
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/README.en-US.md +22 -1
- package/README.md +16 -1
- package/lib/engine.js +320 -25
- package/lib/types/uml.d.ts +293 -293
- package/lib/uml-tool.js +153 -153
- package/lib/uml.js +14 -1
- package/package.json +11 -9
- package/skills/logicprobe/SKILL.md +50 -1
- package/skills/logicprobe/references/dsh-model-schema.md +20 -3
- package/skills/logicprobe-concurrency/SKILL.md +2 -0
- package/skills/logicprobe-datamodel/SKILL.md +2 -0
- package/skills/logicprobe-structure/SKILL.md +2 -0
- package/skills/logicprobe-uml/SKILL.md +2 -0
- package/src/engine.ts +325 -27
- package/src/uml.ts +15 -1
package/lib/types/uml.d.ts
CHANGED
|
@@ -1,293 +1,293 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* UML front end for LogicModelV1 — model a code flow as a UML diagram, then
|
|
3
|
-
* review the modelling itself.
|
|
4
|
-
*
|
|
5
|
-
* Two halves, one data flow:
|
|
6
|
-
*
|
|
7
|
-
* 1. `renderUml` turns a validated LogicModelV1 into Mermaid or PlantUML text
|
|
8
|
-
* (state machine, activity/flow, or sequence trace). The diagram is a
|
|
9
|
-
* *view*: it never invents structure the model does not have, and anything
|
|
10
|
-
* the notation cannot express is reported as a warning instead of being
|
|
11
|
-
* dropped silently.
|
|
12
|
-
* 2. `parseUml` reads that text back into a LogicModelV1, and `reviewUml`
|
|
13
|
-
* compares the two. That comparison is the point of the feature: a UML
|
|
14
|
-
* diagram of a code flow is itself a model, and a model can be wrong —
|
|
15
|
-
* ambiguous branches, dead ends, flows nobody can enter, symbols the
|
|
16
|
-
* source never names. A diagram that does not round-trip to the model it
|
|
17
|
-
* was drawn from is mis-modelled, and the review says so.
|
|
18
|
-
*
|
|
19
|
-
* Why the round trip is the fidelity check: rendering and parsing are inverse
|
|
20
|
-
* only if every construct survives the notation. The generated text carries
|
|
21
|
-
* `logicprobe:` directives (ignored by Mermaid/PlantUML renderers) that pin the
|
|
22
|
-
* initial state, the terminal states and any state id the notation cannot spell
|
|
23
|
-
* verbatim, so an exact comparison is possible rather than a fuzzy one.
|
|
24
|
-
*
|
|
25
|
-
* The review deliberately does NOT replace `logicprobe_verify`: it checks the
|
|
26
|
-
* modelling (structure the diagram claims, documentation coverage, notation
|
|
27
|
-
* fidelity), while S1-S8/A1-A14 check the machine's behaviour (guard
|
|
28
|
-
* exhaustiveness under real valuations, invariant paths, deadlock/liveness in
|
|
29
|
-
* the runtime state space). Findings name the engine check to run next.
|
|
30
|
-
*
|
|
31
|
-
* @module logicprobe-uml
|
|
32
|
-
*/
|
|
33
|
-
import { type HashSpec, type NarrativeCoverage, type ReportSchema, type Verdict } from './engine.js';
|
|
34
|
-
import type { GuardNode, LogicModelV1, UpdateSpec } from './engine.js';
|
|
35
|
-
export type UmlNotation = 'mermaid' | 'plantuml';
|
|
36
|
-
export type UmlDiagram = 'state' | 'activity' | 'sequence';
|
|
37
|
-
export declare const UML_NOTATIONS: readonly UmlNotation[];
|
|
38
|
-
export declare const UML_DIAGRAMS: readonly UmlDiagram[];
|
|
39
|
-
/**
|
|
40
|
-
* What the caller is going to do with the artifact, declared up front.
|
|
41
|
-
*
|
|
42
|
-
* The view follows the question, not the machine, so the tool cannot pick it. What it
|
|
43
|
-
* can do is refuse a pairing that cannot serve the question — before the work, not as
|
|
44
|
-
* a finding after it.
|
|
45
|
-
*/
|
|
46
|
-
export type UmlIntent = 'present' | 'verify' | 'fidelity';
|
|
47
|
-
export declare const UML_INTENTS: readonly UmlIntent[];
|
|
48
|
-
/** The tool actions, for the entry check. `labels` is `action=explain-labels`. */
|
|
49
|
-
export type UmlIntentAction = 'render' | 'parse' | 'review' | 'labels';
|
|
50
|
-
export interface UmlRenderResult {
|
|
51
|
-
notation: UmlNotation;
|
|
52
|
-
diagram: UmlDiagram;
|
|
53
|
-
/** The diagram source; hand this to the user or a renderer as-is. */
|
|
54
|
-
primary: string;
|
|
55
|
-
warnings: string[];
|
|
56
|
-
}
|
|
57
|
-
export interface UmlParseResult {
|
|
58
|
-
notation: UmlNotation;
|
|
59
|
-
diagram: UmlDiagram;
|
|
60
|
-
model: LogicModelV1;
|
|
61
|
-
/**
|
|
62
|
-
* Display labels found in the diagram, keyed by state id. They are how a
|
|
63
|
-
* reader learns what a symbol means; a missing entry is an undocumented
|
|
64
|
-
* symbol, which the review reports.
|
|
65
|
-
*/
|
|
66
|
-
labels: Record<string, string>;
|
|
67
|
-
/**
|
|
68
|
-
* Declarations found in the text that LogicModelV1 cannot represent. A non-empty
|
|
69
|
-
* list means the parsed model is NOT this diagram: the text belongs to another
|
|
70
|
-
* diagram family (component, package, class, deployment, …), so whatever came
|
|
71
|
-
* out is a by-product of reading keywords the parser does not own.
|
|
72
|
-
*/
|
|
73
|
-
discardedConstructs: DiscardedConstruct[];
|
|
74
|
-
/**
|
|
75
|
-
* Arrows whose endpoints were declared by a discarded construct. They survive
|
|
76
|
-
* parsing as state transitions, which is exactly why they are counted out loud.
|
|
77
|
-
*/
|
|
78
|
-
discardedEdges: number;
|
|
79
|
-
warnings: string[];
|
|
80
|
-
}
|
|
81
|
-
/** One declaration the parser could not represent, with the source line that carried it. */
|
|
82
|
-
export interface DiscardedConstruct {
|
|
83
|
-
/** The construct keyword, lower-cased (`component`, `package`, `classDiagram`). */
|
|
84
|
-
construct: string;
|
|
85
|
-
/** 1-based line number in the diagram source. */
|
|
86
|
-
line: number;
|
|
87
|
-
/** The source line, trimmed. */
|
|
88
|
-
text: string;
|
|
89
|
-
}
|
|
90
|
-
export interface UmlFinding {
|
|
91
|
-
code: string;
|
|
92
|
-
severity: 'error' | 'warning' | 'info';
|
|
93
|
-
message: string;
|
|
94
|
-
states?: string[];
|
|
95
|
-
events?: string[];
|
|
96
|
-
transitions?: Array<{
|
|
97
|
-
from: string;
|
|
98
|
-
event: string;
|
|
99
|
-
to: string;
|
|
100
|
-
}>;
|
|
101
|
-
detail?: string;
|
|
102
|
-
/** Machine-readable context for the finding (ids, coverage, rule matches), same shape as the engine's findings. */
|
|
103
|
-
evidence?: Record<string, unknown>;
|
|
104
|
-
}
|
|
105
|
-
export interface UmlRoundTripReport {
|
|
106
|
-
notation: UmlNotation;
|
|
107
|
-
diagram: UmlDiagram;
|
|
108
|
-
ok: boolean;
|
|
109
|
-
/** Which published hash specification the two hashes follow (see references/hash-spec.md). */
|
|
110
|
-
hashSpec: HashSpec;
|
|
111
|
-
modelHash: string;
|
|
112
|
-
parsedHash: string;
|
|
113
|
-
diffs: string[];
|
|
114
|
-
warnings: string[];
|
|
115
|
-
}
|
|
116
|
-
export interface UmlReviewReport {
|
|
117
|
-
/** The review ran and produced this report. It does NOT mean the modelling passed — read `verdict`. */
|
|
118
|
-
ok: boolean;
|
|
119
|
-
ran: boolean;
|
|
120
|
-
verdict: Verdict;
|
|
121
|
-
verdictReason: string;
|
|
122
|
-
/** The versioned report contract this result follows. */
|
|
123
|
-
schema: ReportSchema;
|
|
124
|
-
source: 'model' | 'diagram' | 'model+diagram';
|
|
125
|
-
summary: {
|
|
126
|
-
errors: number;
|
|
127
|
-
warnings: number;
|
|
128
|
-
info: number;
|
|
129
|
-
states: number;
|
|
130
|
-
events: number;
|
|
131
|
-
transitions: number;
|
|
132
|
-
terminalStates: number;
|
|
133
|
-
reachableStates: number;
|
|
134
|
-
documentedStates: number;
|
|
135
|
-
};
|
|
136
|
-
findings: UmlFinding[];
|
|
137
|
-
roundTrip: UmlRoundTripReport | null;
|
|
138
|
-
/** Diagram display labels, when a diagram took part in the review. */
|
|
139
|
-
labels?: Record<string, string>;
|
|
140
|
-
/** Model parsed from the diagram, when a diagram was given (feed it to `logicprobe_verify`). */
|
|
141
|
-
model?: LogicModelV1;
|
|
142
|
-
/** Diagram rendered from the model, when only a model was given. */
|
|
143
|
-
primary?: string;
|
|
144
|
-
/** Paths of the `_`-prefixed metadata keys found in the supplied model, when it carried any. */
|
|
145
|
-
metadataKeys?: string[];
|
|
146
|
-
/** How much of the model the narrative documents; absent when there is no narrative. */
|
|
147
|
-
narrativeCoverage?: NarrativeCoverage;
|
|
148
|
-
/** Hashes of what was reviewed, in one place. */
|
|
149
|
-
hashes: {
|
|
150
|
-
hashSpec: HashSpec;
|
|
151
|
-
modelHash?: string;
|
|
152
|
-
parsedHash?: string;
|
|
153
|
-
};
|
|
154
|
-
/** Declarations the parser could not represent; a non-empty list fails the review. */
|
|
155
|
-
discardedConstructs?: DiscardedConstruct[];
|
|
156
|
-
/** Arrows whose endpoints came from a discarded construct. */
|
|
157
|
-
discardedEdges?: number;
|
|
158
|
-
warnings: string[];
|
|
159
|
-
nextSteps: string[];
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* A UML front-end refusal. `code` lets the tool report *why* it refused instead of
|
|
163
|
-
* collapsing every refusal into a generic input error.
|
|
164
|
-
*/
|
|
165
|
-
export declare class UmlError extends Error {
|
|
166
|
-
readonly code: string;
|
|
167
|
-
constructor(message: string, code?: string);
|
|
168
|
-
}
|
|
169
|
-
/** Canonical guard text. Rendering wraps every composite node in parentheses, and the parser flattens same-operator chains, so render∘parse is the identity. */
|
|
170
|
-
export declare function guardText(node: GuardNode): string;
|
|
171
|
-
/**
|
|
172
|
-
* The `(notation, view)` cells this module can draw.
|
|
173
|
-
*
|
|
174
|
-
* PlantUML activity is the cell that does not exist: its activity syntax is a
|
|
175
|
-
* structured flowchart language, so a graph with merges or cycles needs a while/if
|
|
176
|
-
* reconstruction this module does not perform. Refusing is the honest outcome —
|
|
177
|
-
* quietly emitting a state diagram under an "activity" request would mislabel the
|
|
178
|
-
* model.
|
|
179
|
-
*/
|
|
180
|
-
export declare function assertUmlView(notation: UmlNotation, diagram: UmlDiagram): void;
|
|
181
|
-
/**
|
|
182
|
-
* Refuse, before any work, a request whose declared purpose the view cannot serve.
|
|
183
|
-
*
|
|
184
|
-
* Without an intent this changes nothing: the review still reports `UML019` when the
|
|
185
|
-
* fidelity check does not apply to the view it was given. With one, an impossible
|
|
186
|
-
* pairing is an error carrying a code, instead of a report about the wrong artifact —
|
|
187
|
-
* which is the failure this check exists to prevent.
|
|
188
|
-
*
|
|
189
|
-
* @param intent - the declared purpose, or `undefined` to leave the behaviour unchanged.
|
|
190
|
-
* @param action - which action is about to run.
|
|
191
|
-
* @param view - the requested `(notation, diagram)`, for the actions that have one.
|
|
192
|
-
*/
|
|
193
|
-
export declare function checkUmlIntent(intent: UmlIntent | undefined, action: UmlIntentAction, view?: {
|
|
194
|
-
notation: UmlNotation;
|
|
195
|
-
diagram: UmlDiagram;
|
|
196
|
-
}): void;
|
|
197
|
-
/**
|
|
198
|
-
* Render a LogicModelV1 as UML.
|
|
199
|
-
*
|
|
200
|
-
* Mermaid covers all three views; PlantUML covers state and sequence (see
|
|
201
|
-
* `assertUmlView` for why activity is refused).
|
|
202
|
-
*
|
|
203
|
-
* @param input - candidate LogicModelV1.
|
|
204
|
-
* @param notation - `mermaid` (default) or `plantuml`.
|
|
205
|
-
* @param diagram - `state` (default), `activity`, or `sequence`.
|
|
206
|
-
* @param maxSteps - cap on the sequence trace length.
|
|
207
|
-
* @param intent - what the diagram is for; a view that cannot serve it is refused first.
|
|
208
|
-
*/
|
|
209
|
-
export declare function renderUml(input: unknown, notation?: UmlNotation, diagram?: UmlDiagram, maxSteps?: number, intent?: UmlIntent): UmlRenderResult;
|
|
210
|
-
/** Parse a guard expression such as `(retry < 3 && armed == true)`. */
|
|
211
|
-
export declare function parseGuardText(text: string): GuardNode;
|
|
212
|
-
/** Parse a UML action clause such as `retry := retry + 1, armed := true`. */
|
|
213
|
-
export declare function parseUpdatesText(text: string, warnings: string[]): UpdateSpec[];
|
|
214
|
-
/**
|
|
215
|
-
* Findings a parse result carries on its own. A diagram from another family parses
|
|
216
|
-
* into something; without this finding that something is presented as a model of the
|
|
217
|
-
* file, which is a false guarantee of exactly the kind this plugin exists to prevent.
|
|
218
|
-
*/
|
|
219
|
-
export declare function parseFindings(parsed: UmlParseResult): UmlFinding[];
|
|
220
|
-
/** One accepted way of writing a state's meaning into a diagram label. */
|
|
221
|
-
export interface LabelForm {
|
|
222
|
-
form: string;
|
|
223
|
-
example: string;
|
|
224
|
-
note: string;
|
|
225
|
-
}
|
|
226
|
-
export interface LabelExplanation {
|
|
227
|
-
notation: UmlNotation;
|
|
228
|
-
/** The comment prefix a `logicprobe:` directive uses in this notation. */
|
|
229
|
-
directivePrefix: string;
|
|
230
|
-
directiveLines: Array<{
|
|
231
|
-
example: string;
|
|
232
|
-
meaning: string;
|
|
233
|
-
}>;
|
|
234
|
-
/** Accepted label spellings, in the order `documentedMeaning` accepts them. */
|
|
235
|
-
acceptedLabelForms: LabelForm[];
|
|
236
|
-
/** What the renderer itself writes, so a hand-edited diagram can match it. */
|
|
237
|
-
renderedForm: string;
|
|
238
|
-
ignoredLines: Array<{
|
|
239
|
-
pattern: string;
|
|
240
|
-
behaviour: string;
|
|
241
|
-
}>;
|
|
242
|
-
rules: string[];
|
|
243
|
-
}
|
|
244
|
-
/**
|
|
245
|
-
* What the front end expects of labels and comments, so "why does my hand-drawn diagram
|
|
246
|
-
* report label drift or ignored lines?" has a printed answer instead of a guess.
|
|
247
|
-
* `tests/uml/run.mjs` feeds every claim here back through the parser, so this text cannot
|
|
248
|
-
* drift away from the behaviour it describes.
|
|
249
|
-
*/
|
|
250
|
-
export declare function explainLabels(notation?: UmlNotation): LabelExplanation;
|
|
251
|
-
/**
|
|
252
|
-
* Parse a Mermaid or PlantUML diagram back into a LogicModelV1.
|
|
253
|
-
*
|
|
254
|
-
* State and activity diagrams carry the whole machine, so they parse into a
|
|
255
|
-
* complete model. Sequence diagrams do not: a trace shows the paths that were
|
|
256
|
-
* walked, not the branches that were not, so parsing one would silently prune
|
|
257
|
-
* the machine. That case is refused rather than approximated.
|
|
258
|
-
*
|
|
259
|
-
* @param text - diagram source.
|
|
260
|
-
* @param notation - `auto` (default) detects Mermaid vs PlantUML from the text.
|
|
261
|
-
*/
|
|
262
|
-
export declare function parseUml(text: string, notation?: UmlNotation | 'auto'): UmlParseResult;
|
|
263
|
-
/** Compare two machines by structure — the fidelity measure behind the round-trip check. */
|
|
264
|
-
export declare function diffModels(left: LogicModelV1, right: LogicModelV1): string[];
|
|
265
|
-
export interface UmlReviewOptions {
|
|
266
|
-
/** LogicModelV1 to review. Provide it, `diagram`, or both. */
|
|
267
|
-
model?: unknown;
|
|
268
|
-
/** Diagram text: reviewed on its own, or compared against `model` when both are given. */
|
|
269
|
-
diagram?: string;
|
|
270
|
-
notation?: UmlNotation | 'auto';
|
|
271
|
-
diagramKind?: UmlDiagram;
|
|
272
|
-
/** Render-and-reparse fidelity check (default true; only meaningful with a model). */
|
|
273
|
-
roundTrip?: boolean;
|
|
274
|
-
/** Cap on the sequence trace used for the fidelity check. */
|
|
275
|
-
maxSteps?: number;
|
|
276
|
-
/** What the review is for; a view that cannot serve it is refused before any work. */
|
|
277
|
-
intent?: UmlIntent;
|
|
278
|
-
}
|
|
279
|
-
/**
|
|
280
|
-
* Review a UML model of a code flow.
|
|
281
|
-
*
|
|
282
|
-
* Three inputs are possible and each answers a different question:
|
|
283
|
-
*
|
|
284
|
-
* - `model` only — "is this machine well-modelled?" The review checks the
|
|
285
|
-
* structure the diagram would draw, then renders and re-parses it to prove the
|
|
286
|
-
* diagram carries the machine faithfully (round trip).
|
|
287
|
-
* - `diagram` only — "what does this diagram actually say?" The diagram is parsed
|
|
288
|
-
* into a model, and that model is reviewed; nothing can be said about fidelity
|
|
289
|
-
* to a machine the caller did not provide.
|
|
290
|
-
* - both — "does this diagram match this model?" Any structural difference is a
|
|
291
|
-
* modelling defect and is reported both as round-trip diffs and as a finding.
|
|
292
|
-
*/
|
|
293
|
-
export declare function reviewUml(options: UmlReviewOptions): UmlReviewReport;
|
|
1
|
+
/**
|
|
2
|
+
* UML front end for LogicModelV1 — model a code flow as a UML diagram, then
|
|
3
|
+
* review the modelling itself.
|
|
4
|
+
*
|
|
5
|
+
* Two halves, one data flow:
|
|
6
|
+
*
|
|
7
|
+
* 1. `renderUml` turns a validated LogicModelV1 into Mermaid or PlantUML text
|
|
8
|
+
* (state machine, activity/flow, or sequence trace). The diagram is a
|
|
9
|
+
* *view*: it never invents structure the model does not have, and anything
|
|
10
|
+
* the notation cannot express is reported as a warning instead of being
|
|
11
|
+
* dropped silently.
|
|
12
|
+
* 2. `parseUml` reads that text back into a LogicModelV1, and `reviewUml`
|
|
13
|
+
* compares the two. That comparison is the point of the feature: a UML
|
|
14
|
+
* diagram of a code flow is itself a model, and a model can be wrong —
|
|
15
|
+
* ambiguous branches, dead ends, flows nobody can enter, symbols the
|
|
16
|
+
* source never names. A diagram that does not round-trip to the model it
|
|
17
|
+
* was drawn from is mis-modelled, and the review says so.
|
|
18
|
+
*
|
|
19
|
+
* Why the round trip is the fidelity check: rendering and parsing are inverse
|
|
20
|
+
* only if every construct survives the notation. The generated text carries
|
|
21
|
+
* `logicprobe:` directives (ignored by Mermaid/PlantUML renderers) that pin the
|
|
22
|
+
* initial state, the terminal states and any state id the notation cannot spell
|
|
23
|
+
* verbatim, so an exact comparison is possible rather than a fuzzy one.
|
|
24
|
+
*
|
|
25
|
+
* The review deliberately does NOT replace `logicprobe_verify`: it checks the
|
|
26
|
+
* modelling (structure the diagram claims, documentation coverage, notation
|
|
27
|
+
* fidelity), while S1-S8/A1-A14 check the machine's behaviour (guard
|
|
28
|
+
* exhaustiveness under real valuations, invariant paths, deadlock/liveness in
|
|
29
|
+
* the runtime state space). Findings name the engine check to run next.
|
|
30
|
+
*
|
|
31
|
+
* @module logicprobe-uml
|
|
32
|
+
*/
|
|
33
|
+
import { type HashSpec, type NarrativeCoverage, type ReportSchema, type Verdict } from './engine.js';
|
|
34
|
+
import type { GuardNode, LogicModelV1, UpdateSpec } from './engine.js';
|
|
35
|
+
export type UmlNotation = 'mermaid' | 'plantuml';
|
|
36
|
+
export type UmlDiagram = 'state' | 'activity' | 'sequence';
|
|
37
|
+
export declare const UML_NOTATIONS: readonly UmlNotation[];
|
|
38
|
+
export declare const UML_DIAGRAMS: readonly UmlDiagram[];
|
|
39
|
+
/**
|
|
40
|
+
* What the caller is going to do with the artifact, declared up front.
|
|
41
|
+
*
|
|
42
|
+
* The view follows the question, not the machine, so the tool cannot pick it. What it
|
|
43
|
+
* can do is refuse a pairing that cannot serve the question — before the work, not as
|
|
44
|
+
* a finding after it.
|
|
45
|
+
*/
|
|
46
|
+
export type UmlIntent = 'present' | 'verify' | 'fidelity';
|
|
47
|
+
export declare const UML_INTENTS: readonly UmlIntent[];
|
|
48
|
+
/** The tool actions, for the entry check. `labels` is `action=explain-labels`. */
|
|
49
|
+
export type UmlIntentAction = 'render' | 'parse' | 'review' | 'labels';
|
|
50
|
+
export interface UmlRenderResult {
|
|
51
|
+
notation: UmlNotation;
|
|
52
|
+
diagram: UmlDiagram;
|
|
53
|
+
/** The diagram source; hand this to the user or a renderer as-is. */
|
|
54
|
+
primary: string;
|
|
55
|
+
warnings: string[];
|
|
56
|
+
}
|
|
57
|
+
export interface UmlParseResult {
|
|
58
|
+
notation: UmlNotation;
|
|
59
|
+
diagram: UmlDiagram;
|
|
60
|
+
model: LogicModelV1;
|
|
61
|
+
/**
|
|
62
|
+
* Display labels found in the diagram, keyed by state id. They are how a
|
|
63
|
+
* reader learns what a symbol means; a missing entry is an undocumented
|
|
64
|
+
* symbol, which the review reports.
|
|
65
|
+
*/
|
|
66
|
+
labels: Record<string, string>;
|
|
67
|
+
/**
|
|
68
|
+
* Declarations found in the text that LogicModelV1 cannot represent. A non-empty
|
|
69
|
+
* list means the parsed model is NOT this diagram: the text belongs to another
|
|
70
|
+
* diagram family (component, package, class, deployment, …), so whatever came
|
|
71
|
+
* out is a by-product of reading keywords the parser does not own.
|
|
72
|
+
*/
|
|
73
|
+
discardedConstructs: DiscardedConstruct[];
|
|
74
|
+
/**
|
|
75
|
+
* Arrows whose endpoints were declared by a discarded construct. They survive
|
|
76
|
+
* parsing as state transitions, which is exactly why they are counted out loud.
|
|
77
|
+
*/
|
|
78
|
+
discardedEdges: number;
|
|
79
|
+
warnings: string[];
|
|
80
|
+
}
|
|
81
|
+
/** One declaration the parser could not represent, with the source line that carried it. */
|
|
82
|
+
export interface DiscardedConstruct {
|
|
83
|
+
/** The construct keyword, lower-cased (`component`, `package`, `classDiagram`). */
|
|
84
|
+
construct: string;
|
|
85
|
+
/** 1-based line number in the diagram source. */
|
|
86
|
+
line: number;
|
|
87
|
+
/** The source line, trimmed. */
|
|
88
|
+
text: string;
|
|
89
|
+
}
|
|
90
|
+
export interface UmlFinding {
|
|
91
|
+
code: string;
|
|
92
|
+
severity: 'error' | 'warning' | 'info';
|
|
93
|
+
message: string;
|
|
94
|
+
states?: string[];
|
|
95
|
+
events?: string[];
|
|
96
|
+
transitions?: Array<{
|
|
97
|
+
from: string;
|
|
98
|
+
event: string;
|
|
99
|
+
to: string;
|
|
100
|
+
}>;
|
|
101
|
+
detail?: string;
|
|
102
|
+
/** Machine-readable context for the finding (ids, coverage, rule matches), same shape as the engine's findings. */
|
|
103
|
+
evidence?: Record<string, unknown>;
|
|
104
|
+
}
|
|
105
|
+
export interface UmlRoundTripReport {
|
|
106
|
+
notation: UmlNotation;
|
|
107
|
+
diagram: UmlDiagram;
|
|
108
|
+
ok: boolean;
|
|
109
|
+
/** Which published hash specification the two hashes follow (see references/hash-spec.md). */
|
|
110
|
+
hashSpec: HashSpec;
|
|
111
|
+
modelHash: string;
|
|
112
|
+
parsedHash: string;
|
|
113
|
+
diffs: string[];
|
|
114
|
+
warnings: string[];
|
|
115
|
+
}
|
|
116
|
+
export interface UmlReviewReport {
|
|
117
|
+
/** The review ran and produced this report. It does NOT mean the modelling passed — read `verdict`. */
|
|
118
|
+
ok: boolean;
|
|
119
|
+
ran: boolean;
|
|
120
|
+
verdict: Verdict;
|
|
121
|
+
verdictReason: string;
|
|
122
|
+
/** The versioned report contract this result follows. */
|
|
123
|
+
schema: ReportSchema;
|
|
124
|
+
source: 'model' | 'diagram' | 'model+diagram';
|
|
125
|
+
summary: {
|
|
126
|
+
errors: number;
|
|
127
|
+
warnings: number;
|
|
128
|
+
info: number;
|
|
129
|
+
states: number;
|
|
130
|
+
events: number;
|
|
131
|
+
transitions: number;
|
|
132
|
+
terminalStates: number;
|
|
133
|
+
reachableStates: number;
|
|
134
|
+
documentedStates: number;
|
|
135
|
+
};
|
|
136
|
+
findings: UmlFinding[];
|
|
137
|
+
roundTrip: UmlRoundTripReport | null;
|
|
138
|
+
/** Diagram display labels, when a diagram took part in the review. */
|
|
139
|
+
labels?: Record<string, string>;
|
|
140
|
+
/** Model parsed from the diagram, when a diagram was given (feed it to `logicprobe_verify`). */
|
|
141
|
+
model?: LogicModelV1;
|
|
142
|
+
/** Diagram rendered from the model, when only a model was given. */
|
|
143
|
+
primary?: string;
|
|
144
|
+
/** Paths of the `_`-prefixed metadata keys found in the supplied model, when it carried any. */
|
|
145
|
+
metadataKeys?: string[];
|
|
146
|
+
/** How much of the model the narrative documents; absent when there is no narrative. */
|
|
147
|
+
narrativeCoverage?: NarrativeCoverage;
|
|
148
|
+
/** Hashes of what was reviewed, in one place. */
|
|
149
|
+
hashes: {
|
|
150
|
+
hashSpec: HashSpec;
|
|
151
|
+
modelHash?: string;
|
|
152
|
+
parsedHash?: string;
|
|
153
|
+
};
|
|
154
|
+
/** Declarations the parser could not represent; a non-empty list fails the review. */
|
|
155
|
+
discardedConstructs?: DiscardedConstruct[];
|
|
156
|
+
/** Arrows whose endpoints came from a discarded construct. */
|
|
157
|
+
discardedEdges?: number;
|
|
158
|
+
warnings: string[];
|
|
159
|
+
nextSteps: string[];
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* A UML front-end refusal. `code` lets the tool report *why* it refused instead of
|
|
163
|
+
* collapsing every refusal into a generic input error.
|
|
164
|
+
*/
|
|
165
|
+
export declare class UmlError extends Error {
|
|
166
|
+
readonly code: string;
|
|
167
|
+
constructor(message: string, code?: string);
|
|
168
|
+
}
|
|
169
|
+
/** Canonical guard text. Rendering wraps every composite node in parentheses, and the parser flattens same-operator chains, so render∘parse is the identity. */
|
|
170
|
+
export declare function guardText(node: GuardNode): string;
|
|
171
|
+
/**
|
|
172
|
+
* The `(notation, view)` cells this module can draw.
|
|
173
|
+
*
|
|
174
|
+
* PlantUML activity is the cell that does not exist: its activity syntax is a
|
|
175
|
+
* structured flowchart language, so a graph with merges or cycles needs a while/if
|
|
176
|
+
* reconstruction this module does not perform. Refusing is the honest outcome —
|
|
177
|
+
* quietly emitting a state diagram under an "activity" request would mislabel the
|
|
178
|
+
* model.
|
|
179
|
+
*/
|
|
180
|
+
export declare function assertUmlView(notation: UmlNotation, diagram: UmlDiagram): void;
|
|
181
|
+
/**
|
|
182
|
+
* Refuse, before any work, a request whose declared purpose the view cannot serve.
|
|
183
|
+
*
|
|
184
|
+
* Without an intent this changes nothing: the review still reports `UML019` when the
|
|
185
|
+
* fidelity check does not apply to the view it was given. With one, an impossible
|
|
186
|
+
* pairing is an error carrying a code, instead of a report about the wrong artifact —
|
|
187
|
+
* which is the failure this check exists to prevent.
|
|
188
|
+
*
|
|
189
|
+
* @param intent - the declared purpose, or `undefined` to leave the behaviour unchanged.
|
|
190
|
+
* @param action - which action is about to run.
|
|
191
|
+
* @param view - the requested `(notation, diagram)`, for the actions that have one.
|
|
192
|
+
*/
|
|
193
|
+
export declare function checkUmlIntent(intent: UmlIntent | undefined, action: UmlIntentAction, view?: {
|
|
194
|
+
notation: UmlNotation;
|
|
195
|
+
diagram: UmlDiagram;
|
|
196
|
+
}): void;
|
|
197
|
+
/**
|
|
198
|
+
* Render a LogicModelV1 as UML.
|
|
199
|
+
*
|
|
200
|
+
* Mermaid covers all three views; PlantUML covers state and sequence (see
|
|
201
|
+
* `assertUmlView` for why activity is refused).
|
|
202
|
+
*
|
|
203
|
+
* @param input - candidate LogicModelV1.
|
|
204
|
+
* @param notation - `mermaid` (default) or `plantuml`.
|
|
205
|
+
* @param diagram - `state` (default), `activity`, or `sequence`.
|
|
206
|
+
* @param maxSteps - cap on the sequence trace length.
|
|
207
|
+
* @param intent - what the diagram is for; a view that cannot serve it is refused first.
|
|
208
|
+
*/
|
|
209
|
+
export declare function renderUml(input: unknown, notation?: UmlNotation, diagram?: UmlDiagram, maxSteps?: number, intent?: UmlIntent): UmlRenderResult;
|
|
210
|
+
/** Parse a guard expression such as `(retry < 3 && armed == true)`. */
|
|
211
|
+
export declare function parseGuardText(text: string): GuardNode;
|
|
212
|
+
/** Parse a UML action clause such as `retry := retry + 1, armed := true`. */
|
|
213
|
+
export declare function parseUpdatesText(text: string, warnings: string[]): UpdateSpec[];
|
|
214
|
+
/**
|
|
215
|
+
* Findings a parse result carries on its own. A diagram from another family parses
|
|
216
|
+
* into something; without this finding that something is presented as a model of the
|
|
217
|
+
* file, which is a false guarantee of exactly the kind this plugin exists to prevent.
|
|
218
|
+
*/
|
|
219
|
+
export declare function parseFindings(parsed: UmlParseResult): UmlFinding[];
|
|
220
|
+
/** One accepted way of writing a state's meaning into a diagram label. */
|
|
221
|
+
export interface LabelForm {
|
|
222
|
+
form: string;
|
|
223
|
+
example: string;
|
|
224
|
+
note: string;
|
|
225
|
+
}
|
|
226
|
+
export interface LabelExplanation {
|
|
227
|
+
notation: UmlNotation;
|
|
228
|
+
/** The comment prefix a `logicprobe:` directive uses in this notation. */
|
|
229
|
+
directivePrefix: string;
|
|
230
|
+
directiveLines: Array<{
|
|
231
|
+
example: string;
|
|
232
|
+
meaning: string;
|
|
233
|
+
}>;
|
|
234
|
+
/** Accepted label spellings, in the order `documentedMeaning` accepts them. */
|
|
235
|
+
acceptedLabelForms: LabelForm[];
|
|
236
|
+
/** What the renderer itself writes, so a hand-edited diagram can match it. */
|
|
237
|
+
renderedForm: string;
|
|
238
|
+
ignoredLines: Array<{
|
|
239
|
+
pattern: string;
|
|
240
|
+
behaviour: string;
|
|
241
|
+
}>;
|
|
242
|
+
rules: string[];
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* What the front end expects of labels and comments, so "why does my hand-drawn diagram
|
|
246
|
+
* report label drift or ignored lines?" has a printed answer instead of a guess.
|
|
247
|
+
* `tests/uml/run.mjs` feeds every claim here back through the parser, so this text cannot
|
|
248
|
+
* drift away from the behaviour it describes.
|
|
249
|
+
*/
|
|
250
|
+
export declare function explainLabels(notation?: UmlNotation): LabelExplanation;
|
|
251
|
+
/**
|
|
252
|
+
* Parse a Mermaid or PlantUML diagram back into a LogicModelV1.
|
|
253
|
+
*
|
|
254
|
+
* State and activity diagrams carry the whole machine, so they parse into a
|
|
255
|
+
* complete model. Sequence diagrams do not: a trace shows the paths that were
|
|
256
|
+
* walked, not the branches that were not, so parsing one would silently prune
|
|
257
|
+
* the machine. That case is refused rather than approximated.
|
|
258
|
+
*
|
|
259
|
+
* @param text - diagram source.
|
|
260
|
+
* @param notation - `auto` (default) detects Mermaid vs PlantUML from the text.
|
|
261
|
+
*/
|
|
262
|
+
export declare function parseUml(text: string, notation?: UmlNotation | 'auto'): UmlParseResult;
|
|
263
|
+
/** Compare two machines by structure — the fidelity measure behind the round-trip check. */
|
|
264
|
+
export declare function diffModels(left: LogicModelV1, right: LogicModelV1): string[];
|
|
265
|
+
export interface UmlReviewOptions {
|
|
266
|
+
/** LogicModelV1 to review. Provide it, `diagram`, or both. */
|
|
267
|
+
model?: unknown;
|
|
268
|
+
/** Diagram text: reviewed on its own, or compared against `model` when both are given. */
|
|
269
|
+
diagram?: string;
|
|
270
|
+
notation?: UmlNotation | 'auto';
|
|
271
|
+
diagramKind?: UmlDiagram;
|
|
272
|
+
/** Render-and-reparse fidelity check (default true; only meaningful with a model). */
|
|
273
|
+
roundTrip?: boolean;
|
|
274
|
+
/** Cap on the sequence trace used for the fidelity check. */
|
|
275
|
+
maxSteps?: number;
|
|
276
|
+
/** What the review is for; a view that cannot serve it is refused before any work. */
|
|
277
|
+
intent?: UmlIntent;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Review a UML model of a code flow.
|
|
281
|
+
*
|
|
282
|
+
* Three inputs are possible and each answers a different question:
|
|
283
|
+
*
|
|
284
|
+
* - `model` only — "is this machine well-modelled?" The review checks the
|
|
285
|
+
* structure the diagram would draw, then renders and re-parses it to prove the
|
|
286
|
+
* diagram carries the machine faithfully (round trip).
|
|
287
|
+
* - `diagram` only — "what does this diagram actually say?" The diagram is parsed
|
|
288
|
+
* into a model, and that model is reviewed; nothing can be said about fidelity
|
|
289
|
+
* to a machine the caller did not provide.
|
|
290
|
+
* - both — "does this diagram match this model?" Any structural difference is a
|
|
291
|
+
* modelling defect and is reported both as round-trip diffs and as a finding.
|
|
292
|
+
*/
|
|
293
|
+
export declare function reviewUml(options: UmlReviewOptions): UmlReviewReport;
|