@specverse/engines 4.1.15 → 4.1.17
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/dist/inference/index.d.ts +2 -1
- package/dist/inference/index.d.ts.map +1 -1
- package/dist/inference/index.js +2 -1
- package/dist/inference/index.js.map +1 -1
- package/dist/inference/quint-transpiler.d.ts +18 -1
- package/dist/inference/quint-transpiler.d.ts.map +1 -1
- package/dist/inference/quint-transpiler.js +382 -63
- package/dist/inference/quint-transpiler.js.map +1 -1
- package/dist/inference/verification.d.ts +78 -0
- package/dist/inference/verification.d.ts.map +1 -0
- package/dist/inference/verification.js +482 -0
- package/dist/inference/verification.js.map +1 -0
- package/dist/libs/instance-factories/cli/templates/commander/command-generator.js +30 -5
- package/dist/realize/index.d.ts.map +1 -1
- package/dist/realize/index.js +9 -26
- package/dist/realize/index.js.map +1 -1
- package/libs/instance-factories/cli/templates/commander/command-generator.ts +35 -5
- package/package.json +1 -1
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* L3 Verification Runner
|
|
3
|
+
*
|
|
4
|
+
* Runs the Quint-transpiled guards against a spec snapshot and reports
|
|
5
|
+
* pass / fail / skipped. A guard is skipped when any of its state-var
|
|
6
|
+
* dependencies is missing from the snapshot — a raw (pre-inference)
|
|
7
|
+
* spec, for example, won't have `inferredControllers`, so guards that
|
|
8
|
+
* need it are skipped rather than failed.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* const result = await verifySpec(parsedSpec, { entitiesDir });
|
|
12
|
+
* if (result.failed.length > 0) process.exit(1);
|
|
13
|
+
*
|
|
14
|
+
* The caller is responsible for deciding what "the spec" is — raw,
|
|
15
|
+
* inferred, or something else. `verifySpec` runs whichever guards are
|
|
16
|
+
* applicable.
|
|
17
|
+
*/
|
|
18
|
+
import { createRequire } from 'module';
|
|
19
|
+
import { dirname, join } from 'path';
|
|
20
|
+
import { transpileEntityGuards, extractStateVariables, generateGuardsModule } from './quint-transpiler.js';
|
|
21
|
+
/**
|
|
22
|
+
* Build a Quint-shaped snapshot from a SpecVerse AST.
|
|
23
|
+
*
|
|
24
|
+
* The AST nests collections under `components` and uses shorthand
|
|
25
|
+
* strings for relationships and convention-format attributes. The
|
|
26
|
+
* guards were written against a flatter, more structured shape — each
|
|
27
|
+
* top-level state var (`models`, `controllers`, etc.) is an array of
|
|
28
|
+
* entities, and each entity's nested collections (`attributes`,
|
|
29
|
+
* `relationships`, …) are keyed maps.
|
|
30
|
+
*
|
|
31
|
+
* This function performs the normalization. The caller passes any spec
|
|
32
|
+
* (raw or inferred); only keys actually present in the spec are
|
|
33
|
+
* populated in the returned snapshot.
|
|
34
|
+
*/
|
|
35
|
+
export function buildSnapshot(spec, stateVars) {
|
|
36
|
+
const toArray = (v) => {
|
|
37
|
+
if (!v)
|
|
38
|
+
return [];
|
|
39
|
+
if (Array.isArray(v))
|
|
40
|
+
return v;
|
|
41
|
+
return Object.entries(v).map(([name, data]) => {
|
|
42
|
+
if (data && typeof data === 'object')
|
|
43
|
+
return { name, ...data };
|
|
44
|
+
return { name, value: data };
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
const toKeyedMap = (v) => {
|
|
48
|
+
if (!v)
|
|
49
|
+
return {};
|
|
50
|
+
if (Array.isArray(v)) {
|
|
51
|
+
const out = {};
|
|
52
|
+
for (const item of v) {
|
|
53
|
+
const key = item?.name || item?.id;
|
|
54
|
+
if (key)
|
|
55
|
+
out[key] = item;
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
return v;
|
|
60
|
+
};
|
|
61
|
+
// Parse shorthand relationship strings into structured objects so
|
|
62
|
+
// Quint guards that read `.relType` and `.targetModel` work on raw
|
|
63
|
+
// specs too. Examples:
|
|
64
|
+
// "hasMany Component" → {relType, targetModel}
|
|
65
|
+
// "hasMany Post cascade" → + {cascade: true}
|
|
66
|
+
// "manyToMany Tag through=TagLink" → + {through: "TagLink"}
|
|
67
|
+
// "belongsTo User" → {relType, targetModel}
|
|
68
|
+
const parseRelationshipShorthand = (s, name) => {
|
|
69
|
+
const parts = s.trim().split(/\s+/);
|
|
70
|
+
const relType = parts[0];
|
|
71
|
+
const targetModel = parts[1];
|
|
72
|
+
const rest = parts.slice(2);
|
|
73
|
+
const obj = { name, relType, targetModel };
|
|
74
|
+
for (const token of rest) {
|
|
75
|
+
if (token.includes('=')) {
|
|
76
|
+
const [k, v] = token.split('=');
|
|
77
|
+
obj[k] = v;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
obj[token] = true;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return obj;
|
|
84
|
+
};
|
|
85
|
+
const normalizeRelationships = (rels) => {
|
|
86
|
+
if (!rels)
|
|
87
|
+
return {};
|
|
88
|
+
const result = {};
|
|
89
|
+
const entries = Array.isArray(rels)
|
|
90
|
+
? rels.map((r) => [r.name, r])
|
|
91
|
+
: Object.entries(rels);
|
|
92
|
+
for (const [name, value] of entries) {
|
|
93
|
+
if (typeof value === 'string') {
|
|
94
|
+
result[name] = parseRelationshipShorthand(value, name);
|
|
95
|
+
}
|
|
96
|
+
else if (value && typeof value === 'object') {
|
|
97
|
+
// The parser stores structured relationships as { type, target }
|
|
98
|
+
// (e.g. { name: 'components', type: 'hasMany', target: 'Component' }).
|
|
99
|
+
// Quint invariants read them as { relType, targetModel }. Map
|
|
100
|
+
// between the two so guards can run against the parsed shape.
|
|
101
|
+
const relType = value.relType ?? value.type;
|
|
102
|
+
const targetModel = value.targetModel ?? value.target;
|
|
103
|
+
result[name] = { ...value, name, relType, targetModel };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
};
|
|
108
|
+
const MODEL_NESTED = ['attributes', 'lifecycles', 'behaviors', 'profiles'];
|
|
109
|
+
// relationships handled specially so shorthand strings get parsed
|
|
110
|
+
const CONTROLLER_NESTED = ['endpoints', 'actions', 'operations'];
|
|
111
|
+
const SERVICE_NESTED = ['operations'];
|
|
112
|
+
const EVENT_NESTED = ['attributes'];
|
|
113
|
+
const VIEW_NESTED = ['layouts', 'uiComponents'];
|
|
114
|
+
const DEPLOYMENT_NESTED = ['instances'];
|
|
115
|
+
const normalizeEntity = (entity, keys) => {
|
|
116
|
+
if (!entity || typeof entity !== 'object')
|
|
117
|
+
return entity;
|
|
118
|
+
const out = { ...entity };
|
|
119
|
+
for (const k of keys)
|
|
120
|
+
if (k in out)
|
|
121
|
+
out[k] = toKeyedMap(out[k]);
|
|
122
|
+
// Relationships need their own normalization to parse shorthand strings.
|
|
123
|
+
if ('relationships' in out)
|
|
124
|
+
out.relationships = normalizeRelationships(out.relationships);
|
|
125
|
+
return out;
|
|
126
|
+
};
|
|
127
|
+
const normList = (arr, keys) => arr.map(e => normalizeEntity(e, keys));
|
|
128
|
+
// Field aliases and derivations: convenience flags the Quint specs
|
|
129
|
+
// use that are simple views of data already in the spec. These are
|
|
130
|
+
// NOT synthesizing new information — they expose existing data
|
|
131
|
+
// under Quint's field naming.
|
|
132
|
+
/**
|
|
133
|
+
* Parser stores lifecycle states as a flat array of strings for the
|
|
134
|
+
* shorthand form (`flow: "draft -> open -> closed"` → `states: ['draft',
|
|
135
|
+
* 'open', 'closed']`). Quint invariants expect structured
|
|
136
|
+
* LifecycleState records with `isInitial` / `isTerminal` flags. The
|
|
137
|
+
* shorthand form always makes the first state initial and the last
|
|
138
|
+
* terminal by convention, so we synthesize the structure here.
|
|
139
|
+
*/
|
|
140
|
+
const structureLifecycle = (lc) => {
|
|
141
|
+
if (!lc || typeof lc !== 'object')
|
|
142
|
+
return { name: '', states: [], transitions: [] };
|
|
143
|
+
const rawStates = Array.isArray(lc.states) ? lc.states : [];
|
|
144
|
+
const structuredStates = rawStates.map((s, i) => {
|
|
145
|
+
if (typeof s === 'string') {
|
|
146
|
+
return { name: s, isInitial: i === 0, isTerminal: i === rawStates.length - 1 };
|
|
147
|
+
}
|
|
148
|
+
// Already structured — pass through, filling in flags if missing
|
|
149
|
+
return {
|
|
150
|
+
isInitial: false,
|
|
151
|
+
isTerminal: false,
|
|
152
|
+
...s,
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
// Transitions: if the lifecycle has a `flow` shorthand, derive
|
|
156
|
+
// `from`/`to` pairs for adjacent states.
|
|
157
|
+
let structuredTransitions = [];
|
|
158
|
+
if (Array.isArray(lc.transitions) && lc.transitions.length > 0 && typeof lc.transitions[0] === 'object') {
|
|
159
|
+
structuredTransitions = lc.transitions;
|
|
160
|
+
}
|
|
161
|
+
else if (rawStates.length > 1) {
|
|
162
|
+
structuredTransitions = [];
|
|
163
|
+
for (let i = 0; i < rawStates.length - 1; i++) {
|
|
164
|
+
const from = typeof rawStates[i] === 'string' ? rawStates[i] : rawStates[i].name;
|
|
165
|
+
const to = typeof rawStates[i + 1] === 'string' ? rawStates[i + 1] : rawStates[i + 1].name;
|
|
166
|
+
structuredTransitions.push({ name: `${from}_to_${to}`, from, to });
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
...lc,
|
|
171
|
+
states: structuredStates,
|
|
172
|
+
transitions: structuredTransitions,
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
const aliasModelFields = (m) => {
|
|
176
|
+
const lifecycleEntries = m.lifecycles && typeof m.lifecycles === 'object'
|
|
177
|
+
? Object.values(m.lifecycles)
|
|
178
|
+
: [];
|
|
179
|
+
const firstLifecycle = lifecycleEntries[0];
|
|
180
|
+
return {
|
|
181
|
+
...m,
|
|
182
|
+
hasLifecycle: lifecycleEntries.length > 0,
|
|
183
|
+
lifecycle: firstLifecycle
|
|
184
|
+
? structureLifecycle(firstLifecycle)
|
|
185
|
+
: { name: '', states: [], transitions: [] },
|
|
186
|
+
};
|
|
187
|
+
};
|
|
188
|
+
const aliasViewFields = (v) => ({
|
|
189
|
+
...v,
|
|
190
|
+
// Parser stores `type` (matches YAML `type: list`), Quint uses
|
|
191
|
+
// `viewType` to avoid keyword collision. Keep both.
|
|
192
|
+
viewType: v.viewType ?? v.type,
|
|
193
|
+
});
|
|
194
|
+
// Collect top-level + component-nested entities for each state var.
|
|
195
|
+
// Only populate keys where the spec actually has data; leave others
|
|
196
|
+
// unset so the verification runner can skip dependent guards.
|
|
197
|
+
//
|
|
198
|
+
// When flattening, tag each entity with `.component` (the parent
|
|
199
|
+
// component name) and `.system` (true for entities under
|
|
200
|
+
// build-system / AI / tooling components — these are meta-models
|
|
201
|
+
// describing the language itself and don't need runtime controllers).
|
|
202
|
+
const SYSTEM_COMPONENT_PATTERN = /^(BuildSystem|ToolsSupport|AISupport|Tooling|MetaModel)/i;
|
|
203
|
+
const snapshot = {};
|
|
204
|
+
const componentList = spec?.components
|
|
205
|
+
? (Array.isArray(spec.components) ? spec.components : Object.entries(spec.components).map(([name, data]) => ({ name, ...(data || {}) })))
|
|
206
|
+
: [];
|
|
207
|
+
const tagWithComponent = (item, componentName) => {
|
|
208
|
+
if (!item || typeof item !== 'object')
|
|
209
|
+
return item;
|
|
210
|
+
const isSystem = SYSTEM_COMPONENT_PATTERN.test(componentName);
|
|
211
|
+
return { component: componentName, system: isSystem, ...item };
|
|
212
|
+
};
|
|
213
|
+
for (const v of stateVars) {
|
|
214
|
+
const topLevel = toArray(spec?.[v]);
|
|
215
|
+
const nested = [];
|
|
216
|
+
for (const comp of componentList) {
|
|
217
|
+
const val = comp?.[v];
|
|
218
|
+
if (val) {
|
|
219
|
+
const compName = comp?.name || '';
|
|
220
|
+
for (const item of toArray(val)) {
|
|
221
|
+
nested.push(tagWithComponent(item, compName));
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
if (topLevel.length > 0 || nested.length > 0) {
|
|
226
|
+
snapshot[v] = [...topLevel, ...nested];
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
// `components` is its own state var, populated from the list
|
|
230
|
+
if (stateVars.includes('components') && componentList.length > 0) {
|
|
231
|
+
snapshot.components = componentList;
|
|
232
|
+
}
|
|
233
|
+
// Normalize per-entity nested collections
|
|
234
|
+
if (snapshot.models)
|
|
235
|
+
snapshot.models = normList(snapshot.models, MODEL_NESTED).map(aliasModelFields);
|
|
236
|
+
if (snapshot.controllers)
|
|
237
|
+
snapshot.controllers = normList(snapshot.controllers, CONTROLLER_NESTED);
|
|
238
|
+
if (snapshot.services)
|
|
239
|
+
snapshot.services = normList(snapshot.services, SERVICE_NESTED);
|
|
240
|
+
if (snapshot.events)
|
|
241
|
+
snapshot.events = normList(snapshot.events, EVENT_NESTED);
|
|
242
|
+
if (snapshot.views)
|
|
243
|
+
snapshot.views = normList(snapshot.views, VIEW_NESTED).map(aliasViewFields);
|
|
244
|
+
if (snapshot.deployments)
|
|
245
|
+
snapshot.deployments = normList(snapshot.deployments, DEPLOYMENT_NESTED);
|
|
246
|
+
// `inferredControllers` / `inferredServices` are Quint internal aliases
|
|
247
|
+
// for inference output. Populate them only when the respective
|
|
248
|
+
// non-inferred collection is present AND non-empty — this is the
|
|
249
|
+
// signal that inference (or a user writing the expanded form) has run.
|
|
250
|
+
if (stateVars.includes('inferredControllers') && snapshot.controllers?.length) {
|
|
251
|
+
snapshot.inferredControllers = snapshot.controllers;
|
|
252
|
+
}
|
|
253
|
+
if (stateVars.includes('inferredServices') && snapshot.services?.length) {
|
|
254
|
+
snapshot.inferredServices = snapshot.services;
|
|
255
|
+
}
|
|
256
|
+
return snapshot;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Scan a guard body for `<loopVar>.<field>` accesses that are bound to
|
|
260
|
+
* a state-var collection (e.g. `c.depth` inside `commands.forall(c => ...)`).
|
|
261
|
+
* For each such field, check whether it's populated on AT LEAST ONE
|
|
262
|
+
* entity in the relevant snapshot collection. Return the fields that
|
|
263
|
+
* aren't populated anywhere — those are the reason to skip the guard.
|
|
264
|
+
*
|
|
265
|
+
* This is a best-effort heuristic; it only catches the common case
|
|
266
|
+
* where a Quint invariant references a field the runtime data doesn't
|
|
267
|
+
* populate (typically fields added by inference that a raw spec lacks).
|
|
268
|
+
*/
|
|
269
|
+
function findUnusableFields(guard, snapshot) {
|
|
270
|
+
const quint = guard.quint || '';
|
|
271
|
+
// Find forall / exists / filter / map bindings: e.g. `commands.forall(c => ...)`
|
|
272
|
+
// produces the binding `c -> commands`. We scan for `<stateVar>.<op>(<var> =>`
|
|
273
|
+
// and then look for `<var>.<field>` accesses elsewhere in the body.
|
|
274
|
+
const bindingRe = /(\w+)\.(?:forall|exists|filter|map|flatMap)\(\s*(\w+)\s*=>/g;
|
|
275
|
+
const bindings = new Map(); // var → state var name
|
|
276
|
+
let m;
|
|
277
|
+
while ((m = bindingRe.exec(quint)) !== null) {
|
|
278
|
+
const [, stateVar, varName] = m;
|
|
279
|
+
if (guard.dependencies.includes(stateVar) && !bindings.has(varName)) {
|
|
280
|
+
bindings.set(varName, stateVar);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if (bindings.size === 0)
|
|
284
|
+
return [];
|
|
285
|
+
const missing = new Set();
|
|
286
|
+
for (const [varName, stateVar] of bindings) {
|
|
287
|
+
const fieldRe = new RegExp(`\\b${varName}\\.(\\w+)`, 'g');
|
|
288
|
+
const fields = new Set();
|
|
289
|
+
let fm;
|
|
290
|
+
while ((fm = fieldRe.exec(quint)) !== null) {
|
|
291
|
+
// Skip methods (followed by `(`)
|
|
292
|
+
const after = quint[fm.index + fm[0].length];
|
|
293
|
+
if (after === '(')
|
|
294
|
+
continue;
|
|
295
|
+
fields.add(fm[1]);
|
|
296
|
+
}
|
|
297
|
+
const collection = snapshot[stateVar] || [];
|
|
298
|
+
for (const field of fields) {
|
|
299
|
+
const anyHas = collection.some(item => item && typeof item === 'object' && field in item);
|
|
300
|
+
if (!anyHas)
|
|
301
|
+
missing.add(field);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return [...missing].sort();
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Resolve the entities source directory when not explicitly provided.
|
|
308
|
+
*/
|
|
309
|
+
function resolveEntitiesDir() {
|
|
310
|
+
const req = createRequire(import.meta.url);
|
|
311
|
+
const pkgPath = req.resolve('@specverse/entities/package.json');
|
|
312
|
+
return join(dirname(pkgPath), 'src');
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Run the L3 verification gate against the provided spec.
|
|
316
|
+
*
|
|
317
|
+
* `spec` can be any SpecVerse AST — raw, inferred, or anywhere in
|
|
318
|
+
* between. Only guards whose dependencies are present in the
|
|
319
|
+
* resulting snapshot run; the rest are reported as skipped.
|
|
320
|
+
*/
|
|
321
|
+
export async function verifySpec(spec, opts = {}) {
|
|
322
|
+
const entitiesDir = opts.entitiesDir || resolveEntitiesDir();
|
|
323
|
+
const guards = transpileEntityGuards(entitiesDir);
|
|
324
|
+
const stateVars = extractStateVariables(entitiesDir);
|
|
325
|
+
// Deduplicate guards by (kind, name) to match generateGuardsModule
|
|
326
|
+
const seen = new Set();
|
|
327
|
+
const uniqueGuards = guards.filter(g => {
|
|
328
|
+
const key = `${g.kind}:${g.name}`;
|
|
329
|
+
if (seen.has(key))
|
|
330
|
+
return false;
|
|
331
|
+
seen.add(key);
|
|
332
|
+
return true;
|
|
333
|
+
});
|
|
334
|
+
// Build the snapshot — caller can override which vars are "available"
|
|
335
|
+
// by passing an explicit availableVars list, but by default we derive
|
|
336
|
+
// it from what buildSnapshot populates.
|
|
337
|
+
const snapshot = buildSnapshot(spec, stateVars);
|
|
338
|
+
const availableVars = new Set(opts.availableVars || Object.keys(snapshot));
|
|
339
|
+
const invariants = uniqueGuards.filter(g => g.kind === 'invariant');
|
|
340
|
+
const failed = [];
|
|
341
|
+
const skipped = [];
|
|
342
|
+
const errors = [];
|
|
343
|
+
let passed = 0;
|
|
344
|
+
// Partition: which guards can run against this snapshot?
|
|
345
|
+
// A guard is runnable when (a) all its state-var dependencies are in
|
|
346
|
+
// the snapshot AND (b) for every `<loopVar>.<field>` access in its
|
|
347
|
+
// body, that field exists on at least one entity of the relevant
|
|
348
|
+
// state var. This second check catches cases like `c.depth <= 3`
|
|
349
|
+
// where the field is populated only by inference — on a raw spec,
|
|
350
|
+
// the guard would silently return false from `undefined <= 3`, which
|
|
351
|
+
// is a data-completeness issue, not an invariant violation.
|
|
352
|
+
const runnable = [];
|
|
353
|
+
for (const g of invariants) {
|
|
354
|
+
const missingVars = g.dependencies.filter(d => !availableVars.has(d));
|
|
355
|
+
if (missingVars.length > 0) {
|
|
356
|
+
skipped.push({ name: g.name, entity: g.entity, missingDeps: missingVars });
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
const missingFields = findUnusableFields(g, snapshot);
|
|
360
|
+
if (missingFields.length > 0) {
|
|
361
|
+
skipped.push({ name: g.name, entity: g.entity, missingDeps: missingFields.map(f => `field ${f}`) });
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
runnable.push(g);
|
|
365
|
+
}
|
|
366
|
+
if (runnable.length === 0) {
|
|
367
|
+
return { total: invariants.length, passed: 0, failed, skipped, errors };
|
|
368
|
+
}
|
|
369
|
+
// Transpile guards to a runnable module — only the ones we need, so
|
|
370
|
+
// state vars filter down naturally.
|
|
371
|
+
const guardsCode = generateGuardsModule(runnable, stateVars);
|
|
372
|
+
const esbuild = await import('esbuild');
|
|
373
|
+
const compiled = esbuild.transformSync(guardsCode, {
|
|
374
|
+
loader: 'ts',
|
|
375
|
+
format: 'esm',
|
|
376
|
+
target: 'es2022',
|
|
377
|
+
}).code;
|
|
378
|
+
const dataUrl = 'data:text/javascript;base64,' + Buffer.from(compiled).toString('base64');
|
|
379
|
+
const mod = await import(dataUrl);
|
|
380
|
+
if (typeof mod.setSpecSnapshot === 'function') {
|
|
381
|
+
mod.setSpecSnapshot(snapshot);
|
|
382
|
+
}
|
|
383
|
+
// Classify errors: a thrown exception from undefined field access
|
|
384
|
+
// (e.g. `.every` on undefined, `.X` on undefined, `X is not a function`
|
|
385
|
+
// on a missing array method) means the guard expected a field the
|
|
386
|
+
// spec doesn't have. Report it as "skipped — data-completeness",
|
|
387
|
+
// not as a transpiler error.
|
|
388
|
+
const classifyError = (msg) => {
|
|
389
|
+
if (/Cannot read properties of (undefined|null)/.test(msg) ||
|
|
390
|
+
/\bof undefined\b/.test(msg) ||
|
|
391
|
+
/Cannot convert undefined or null to object/.test(msg) ||
|
|
392
|
+
/ is not a function\b/.test(msg)) {
|
|
393
|
+
const field = msg.match(/reading '([^']+)'/)?.[1]
|
|
394
|
+
|| msg.match(/\b(\w+) is not a function/)?.[1];
|
|
395
|
+
return { isShape: true, field };
|
|
396
|
+
}
|
|
397
|
+
return { isShape: false };
|
|
398
|
+
};
|
|
399
|
+
for (const g of runnable) {
|
|
400
|
+
const fn = mod[`check_${g.name}`];
|
|
401
|
+
if (typeof fn !== 'function')
|
|
402
|
+
continue;
|
|
403
|
+
try {
|
|
404
|
+
const ok = fn();
|
|
405
|
+
if (ok === false) {
|
|
406
|
+
failed.push({
|
|
407
|
+
name: g.name,
|
|
408
|
+
entity: g.entity,
|
|
409
|
+
module: g.module,
|
|
410
|
+
quint: g.quint,
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
passed++;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
catch (e) {
|
|
418
|
+
const msg = e.message || String(e);
|
|
419
|
+
const cls = classifyError(msg);
|
|
420
|
+
if (cls.isShape) {
|
|
421
|
+
skipped.push({
|
|
422
|
+
name: g.name,
|
|
423
|
+
entity: g.entity,
|
|
424
|
+
missingDeps: cls.field ? [`field ${cls.field}`] : ['undefined field'],
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
errors.push({ name: g.name, entity: g.entity, message: msg });
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
return {
|
|
433
|
+
total: invariants.length,
|
|
434
|
+
passed,
|
|
435
|
+
failed,
|
|
436
|
+
skipped,
|
|
437
|
+
errors,
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Format a verification result for CLI output.
|
|
442
|
+
*/
|
|
443
|
+
export function formatVerificationResult(result, verbose = false) {
|
|
444
|
+
const lines = [];
|
|
445
|
+
const applicable = result.passed + result.failed.length + result.errors.length;
|
|
446
|
+
lines.push(`L3 verification: ${result.passed}/${applicable} invariants hold`);
|
|
447
|
+
if (result.skipped.length > 0) {
|
|
448
|
+
lines.push(` ${result.skipped.length} skipped (not applicable to this spec)`);
|
|
449
|
+
}
|
|
450
|
+
if (result.failed.length > 0) {
|
|
451
|
+
lines.push(` ${result.failed.length} failed:`);
|
|
452
|
+
const toShow = verbose ? result.failed : result.failed.slice(0, 10);
|
|
453
|
+
for (const f of toShow) {
|
|
454
|
+
lines.push(` ✗ ${f.entity}/${f.name}`);
|
|
455
|
+
if (verbose && f.quint) {
|
|
456
|
+
const first = f.quint.split('\n')[0].slice(0, 120);
|
|
457
|
+
lines.push(` ${first}`);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
if (!verbose && result.failed.length > 10) {
|
|
461
|
+
lines.push(` ...and ${result.failed.length - 10} more`);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
if (result.errors.length > 0) {
|
|
465
|
+
lines.push(` ${result.errors.length} errored (shape mismatch):`);
|
|
466
|
+
const toShow = verbose ? result.errors : result.errors.slice(0, 5);
|
|
467
|
+
for (const e of toShow) {
|
|
468
|
+
lines.push(` ⚠ ${e.entity}/${e.name}: ${e.message}`);
|
|
469
|
+
}
|
|
470
|
+
if (!verbose && result.errors.length > 5) {
|
|
471
|
+
lines.push(` ...and ${result.errors.length - 5} more`);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
if (verbose && result.skipped.length > 0) {
|
|
475
|
+
lines.push(' skipped guards:');
|
|
476
|
+
for (const s of result.skipped) {
|
|
477
|
+
lines.push(` - ${s.entity}/${s.name} (needs: ${s.missingDeps.join(', ')})`);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
return lines.join('\n');
|
|
481
|
+
}
|
|
482
|
+
//# sourceMappingURL=verification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verification.js","sourceRoot":"","sources":["../../src/inference/verification.ts"],"names":[],"mappings":"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"}
|
|
@@ -20,7 +20,7 @@ function generateCommand(context) {
|
|
|
20
20
|
const flagType = flag.type?.toLowerCase();
|
|
21
21
|
const valuePart = flagType === "boolean" ? "" : ` <${flagName.replace(/^--/, "")}>`;
|
|
22
22
|
const defaultVal = flag.default !== void 0 ? `, ${commanderDefault(flag.default, flagType)}` : "";
|
|
23
|
-
const desc = flag.description || `${flagName} option
|
|
23
|
+
const desc = escapeSingleQuotes(flag.description || `${flagName} option`);
|
|
24
24
|
return ` .option('${alias}${flagName}${valuePart}', '${desc}'${defaultVal})`;
|
|
25
25
|
});
|
|
26
26
|
const optionTypes = Object.entries(flags).map(([flagName, flag]) => {
|
|
@@ -123,6 +123,27 @@ import type { ParserEngine } from '@specverse/types';`,
|
|
|
123
123
|
console.warn('Warnings:');
|
|
124
124
|
result.warnings.forEach((w: string) => console.warn(' ', w));
|
|
125
125
|
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// L3 verification \u2014 opt-in via --verify flag. Runs the
|
|
129
|
+
// transpiled Quint guards against the parsed spec. Guards
|
|
130
|
+
// whose state-var dependencies aren't present in this spec
|
|
131
|
+
// are reported as skipped (not failed).
|
|
132
|
+
if (options.verify) {
|
|
133
|
+
try {
|
|
134
|
+
const { verifySpec, formatVerificationResult } = await import('@specverse/engines/inference');
|
|
135
|
+
const verification = await verifySpec(result.ast);
|
|
136
|
+
if (options.json) {
|
|
137
|
+
console.log(JSON.stringify({ valid: true, verification }, null, 2));
|
|
138
|
+
} else {
|
|
139
|
+
console.log('');
|
|
140
|
+
console.log(formatVerificationResult(verification, options.verbose));
|
|
141
|
+
}
|
|
142
|
+
if (verification.failed.length > 0) process.exit(1);
|
|
143
|
+
} catch (ve: any) {
|
|
144
|
+
console.error('Verification error:', ve.message);
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
126
147
|
}`
|
|
127
148
|
},
|
|
128
149
|
infer: {
|
|
@@ -862,7 +883,7 @@ function generateLeafCommand(name, description, commandStr, optionDefs, actionPa
|
|
|
862
883
|
const finalActionParams = renameUnusedActionParams(actionParams, handler);
|
|
863
884
|
return `program
|
|
864
885
|
.command('${commandStr}')
|
|
865
|
-
.description('${description}')
|
|
886
|
+
.description('${escapeSingleQuotes(description)}')
|
|
866
887
|
${optionDefs.join("\n")}
|
|
867
888
|
.action(async (${finalActionParams}) => {
|
|
868
889
|
try {
|
|
@@ -873,6 +894,9 @@ ${optionDefs.join("\n")}
|
|
|
873
894
|
}
|
|
874
895
|
});`;
|
|
875
896
|
}
|
|
897
|
+
function escapeSingleQuotes(s) {
|
|
898
|
+
return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
899
|
+
}
|
|
876
900
|
function commanderDefault(value, flagType) {
|
|
877
901
|
if (flagType === "boolean") return JSON.stringify(Boolean(value));
|
|
878
902
|
if (typeof value === "number") return JSON.stringify(String(value));
|
|
@@ -903,7 +927,8 @@ function generateCommandWithSubcommands(name, description, subcommands, optionDe
|
|
|
903
927
|
const flagType = flag.type?.toLowerCase();
|
|
904
928
|
const valuePart = flagType === "boolean" ? "" : ` <${flagName.replace(/^--/, "")}>`;
|
|
905
929
|
const defaultVal = flag.default !== void 0 ? `, ${commanderDefault(flag.default, flagType)}` : "";
|
|
906
|
-
|
|
930
|
+
const desc = escapeSingleQuotes(flag.description || flagName);
|
|
931
|
+
return ` .option('${alias}${flagName}${valuePart}', '${desc}'${defaultVal})`;
|
|
907
932
|
});
|
|
908
933
|
const handlerKey = `${name}.${subName}`;
|
|
909
934
|
const engineHandler = ENGINE_HANDLERS[handlerKey];
|
|
@@ -914,7 +939,7 @@ function generateCommandWithSubcommands(name, description, subcommands, optionDe
|
|
|
914
939
|
return `
|
|
915
940
|
cmd
|
|
916
941
|
.command('${subCmdStr}')
|
|
917
|
-
.description('${subDesc}')
|
|
942
|
+
.description('${escapeSingleQuotes(subDesc)}')
|
|
918
943
|
${subOptionDefs.join("\n")}
|
|
919
944
|
.action(async (${finalSubActionParams}) => {
|
|
920
945
|
try {
|
|
@@ -927,7 +952,7 @@ ${subOptionDefs.join("\n")}
|
|
|
927
952
|
});
|
|
928
953
|
return `const cmd = program
|
|
929
954
|
.command('${name}')
|
|
930
|
-
.description('${description}');
|
|
955
|
+
.description('${escapeSingleQuotes(description)}');
|
|
931
956
|
${subcmdRegistrations.join("\n")}`;
|
|
932
957
|
}
|
|
933
958
|
function generateSubcommandRegistrations(_parentName, _subcommands) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/realize/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,kBAAkB,CAAC;AAGjC,cAAc,kBAAkB,CAAC;AAGjC,cAAc,uBAAuB,CAAC;AAGtC,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACpF,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAMlE,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AASnF,cAAM,sBAAuB,YAAW,aAAa;IACnD,IAAI,SAAa;IACjB,OAAO,SAAW;IAClB,YAAY,WAA+E;IAE3F,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,WAAW,CAAS;IAEtB,UAAU,CAAC,MAAM,CAAC,EAAE;QACxB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBjB,OAAO,IAAI,UAAU;IAIrB,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,GAAG;IAK1B,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,eAAe,CAAC;IAKvF;;;OAGG;IACG,UAAU,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/realize/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,kBAAkB,CAAC;AAGjC,cAAc,kBAAkB,CAAC;AAGjC,cAAc,uBAAuB,CAAC;AAGtC,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACpF,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAMlE,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AASnF,cAAM,sBAAuB,YAAW,aAAa;IACnD,IAAI,SAAa;IACjB,OAAO,SAAW;IAClB,YAAY,WAA+E;IAE3F,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,WAAW,CAAS;IAEtB,UAAU,CAAC,MAAM,CAAC,EAAE;QACxB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBjB,OAAO,IAAI,UAAU;IAIrB,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,GAAG;IAK1B,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,eAAe,CAAC;IAKvF;;;OAGG;IACG,UAAU,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAskB9F;;;OAGG;YACW,UAAU;IAwDxB,OAAO,CAAC,oBAAoB;CAuB7B;AAED,eAAO,MAAM,MAAM,wBAA+B,CAAC;AACnD,eAAe,MAAM,CAAC;AACtB,OAAO,EAAE,sBAAsB,EAAE,CAAC"}
|
package/dist/realize/index.js
CHANGED
|
@@ -68,6 +68,10 @@ class SpecVerseRealizeEngine {
|
|
|
68
68
|
const files = [];
|
|
69
69
|
const errors = [];
|
|
70
70
|
const allModels = Object.values(spec.models || {});
|
|
71
|
+
// L3 verification (Quint guards) is NOT run here. It lives in
|
|
72
|
+
// `validate --verify` so users can opt into it explicitly and run
|
|
73
|
+
// it on any spec — raw or inferred — without also generating code.
|
|
74
|
+
// See engines/src/inference/verification.ts.
|
|
71
75
|
const writeOutput = (output) => {
|
|
72
76
|
// A generator can signal "skip this file" by returning an empty string.
|
|
73
77
|
if (output.code === '')
|
|
@@ -529,32 +533,11 @@ export default {
|
|
|
529
533
|
errors.push(`SharedUtils: ${e.message}`);
|
|
530
534
|
}
|
|
531
535
|
}
|
|
532
|
-
// 9b.
|
|
533
|
-
//
|
|
534
|
-
//
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
try {
|
|
538
|
-
const { transpileEntityGuards, generateGuardsModule } = await import('../inference/index.js');
|
|
539
|
-
const { createRequire } = await import('module');
|
|
540
|
-
const req = createRequire(import.meta.url);
|
|
541
|
-
const entitiesPkg = req.resolve('@specverse/entities/package.json');
|
|
542
|
-
const entitiesSrc = join(dirname(entitiesPkg), 'src');
|
|
543
|
-
const guards = transpileEntityGuards(entitiesSrc);
|
|
544
|
-
if (guards.length > 0) {
|
|
545
|
-
const guardsCode = generateGuardsModule(guards);
|
|
546
|
-
const guardsPath = join(outputDir, 'backend', 'src', 'guards.ts');
|
|
547
|
-
const guardsDir = dirname(guardsPath);
|
|
548
|
-
if (!existsSync(guardsDir))
|
|
549
|
-
mkdirSync(guardsDir, { recursive: true });
|
|
550
|
-
writeFileSync(guardsPath, guardsCode);
|
|
551
|
-
console.log(` ✅ Runtime guards: ${guards.length} guards (${guards.filter((g) => g.kind === 'function').length} functions, ${guards.filter((g) => g.kind === 'invariant').length} invariants) from Quint specs`);
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
catch (e) {
|
|
555
|
-
errors.push(`Guards: ${e.message}`);
|
|
556
|
-
}
|
|
557
|
-
}
|
|
536
|
+
// 9b. Quint guards are no longer emitted to the generated backend.
|
|
537
|
+
// They are L3 verification assertions about the SPEC, not runtime
|
|
538
|
+
// checks on the user's data — so they run at realize time (see the
|
|
539
|
+
// L3 verification gate at the start of realizeAll) and don't ship
|
|
540
|
+
// to the user's project.
|
|
558
541
|
// 10. CLI commands (Commander.js)
|
|
559
542
|
try {
|
|
560
543
|
const cliDir = join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'libs', 'instance-factories', 'cli', 'templates', 'commander');
|