@specverse/engines 6.34.0 → 6.37.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/dist/analyse-prepass/adapters/typescript-decorators.d.ts.map +1 -1
- package/dist/analyse-prepass/adapters/typescript-decorators.js +112 -34
- package/dist/analyse-prepass/adapters/typescript-decorators.js.map +1 -1
- package/dist/analyse-prepass/backends/grep-only.d.ts.map +1 -1
- package/dist/analyse-prepass/backends/grep-only.js +17 -0
- package/dist/analyse-prepass/backends/grep-only.js.map +1 -1
- package/dist/analyse-prepass/method-body-walker.d.ts.map +1 -1
- package/dist/analyse-prepass/method-body-walker.js +7 -1
- package/dist/analyse-prepass/method-body-walker.js.map +1 -1
- package/dist/libs/instance-factories/cli/templates/commander/command-generator.js +36 -1
- package/dist/libs/instance-factories/orms/templates/prisma/schema-generator.js +51 -3
- package/dist/libs/instance-factories/services/templates/prisma/behavior-generator.js +4 -1
- package/dist/realize/per-action-emitter.d.ts +2 -33
- package/dist/realize/per-action-emitter.d.ts.map +1 -1
- package/dist/realize/per-action-emitter.js.map +1 -1
- package/libs/instance-factories/cli/__tests__/command-generator.test.ts +83 -0
- package/libs/instance-factories/cli/templates/commander/command-generator.ts +36 -1
- package/libs/instance-factories/orms/templates/prisma/__tests__/schema-generator.test.ts +315 -0
- package/libs/instance-factories/orms/templates/prisma/schema-generator.ts +94 -3
- package/libs/instance-factories/services/templates/_shared/step-matching.ts +11 -29
- package/libs/instance-factories/services/templates/prisma/__tests__/behavior-generator.test.ts +85 -0
- package/libs/instance-factories/services/templates/prisma/behavior-generator.ts +21 -1
- package/package.json +2 -2
|
@@ -30,35 +30,17 @@ export function toVar(name: string): string {
|
|
|
30
30
|
return name.charAt(0).toLowerCase() + name.slice(1);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
name: string;
|
|
45
|
-
pattern: RegExp;
|
|
46
|
-
/** Emit inline code for this step. Return empty string to signal
|
|
47
|
-
* "regex matched but I can't safely emit" (caller falls through to AI). */
|
|
48
|
-
generateCall: (match: RegExpMatchArray, ctx: C) => string;
|
|
49
|
-
/** Optional helper-method body that some libraries (e.g. prisma's
|
|
50
|
-
* `check {condition}` convention) emit alongside the call site. */
|
|
51
|
-
generateMethod?: (match: RegExpMatchArray, ctx: C) => string;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export interface MatchResult {
|
|
55
|
-
matched: boolean;
|
|
56
|
-
call: string;
|
|
57
|
-
helperMethod?: string;
|
|
58
|
-
functionName?: string;
|
|
59
|
-
inputs?: string[];
|
|
60
|
-
resultVar?: string;
|
|
61
|
-
}
|
|
33
|
+
// #54 (2026-05-10): SharedStepContext, SharedConvention, MatchResult
|
|
34
|
+
// and MatcherFn are now canonical in @specverse/types. Re-exported here
|
|
35
|
+
// so existing dynamic-import call sites that grab types from this path
|
|
36
|
+
// keep working. New code should import directly from @specverse/types.
|
|
37
|
+
export type {
|
|
38
|
+
SharedStepContext,
|
|
39
|
+
SharedConvention,
|
|
40
|
+
MatchResult,
|
|
41
|
+
MatcherFn,
|
|
42
|
+
} from '@specverse/types';
|
|
43
|
+
import type { SharedStepContext, SharedConvention, MatchResult } from '@specverse/types';
|
|
62
44
|
|
|
63
45
|
// ── Audit-trail recorder hook ──────────────────────────────────────────
|
|
64
46
|
// Forward-logging discipline (engines 6.22.0+): the matcher records every
|
package/libs/instance-factories/services/templates/prisma/__tests__/behavior-generator.test.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* behavior-generator.ts — postcondition emission tests (#53D).
|
|
3
|
+
*
|
|
4
|
+
* The generator emits one `console.assert(true, '<text>');` line per
|
|
5
|
+
* postcondition string in the dev-mode block. Pre-#53D the wrapper was
|
|
6
|
+
* single-quoted; postcondition text containing apostrophes — common in
|
|
7
|
+
* natural prose like "no other nodes' cache entries are affected" —
|
|
8
|
+
* terminated the JS string and esbuild rejected the file.
|
|
9
|
+
*
|
|
10
|
+
* #53D fix: emit with backticks + escape any backticks / `${` markers
|
|
11
|
+
* in the source. These tests pin the new shape so a future change
|
|
12
|
+
* can't silently regress to single-quoted strings.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { describe, it, expect } from 'vitest';
|
|
16
|
+
import { generatePostconditionVerification } from '../behavior-generator.js';
|
|
17
|
+
|
|
18
|
+
describe('generatePostconditionVerification — 53D apostrophe handling', () => {
|
|
19
|
+
it('returns empty string for empty input', () => {
|
|
20
|
+
expect(generatePostconditionVerification([])).toBe('');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('emits backtick-wrapped strings (not single-quoted)', () => {
|
|
24
|
+
const out = generatePostconditionVerification(['simple postcondition']);
|
|
25
|
+
expect(out).toContain('`POSTCONDITION: simple postcondition`');
|
|
26
|
+
expect(out).not.toContain("'POSTCONDITION:");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('preserves apostrophes verbatim in postcondition text', () => {
|
|
30
|
+
const out = generatePostconditionVerification([
|
|
31
|
+
"no other nodes' cache entries are affected",
|
|
32
|
+
]);
|
|
33
|
+
expect(out).toContain("nodes' cache entries");
|
|
34
|
+
// Must not have escaped the apostrophe — backticks accept it natively.
|
|
35
|
+
expect(out).not.toContain("nodes\\'");
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('escapes embedded backticks to prevent string termination', () => {
|
|
39
|
+
const out = generatePostconditionVerification([
|
|
40
|
+
'value matches `expected` shape',
|
|
41
|
+
]);
|
|
42
|
+
expect(out).toContain('value matches \\`expected\\` shape');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('escapes ${...} interpolation markers to prevent template execution', () => {
|
|
46
|
+
const out = generatePostconditionVerification([
|
|
47
|
+
'rejects ${malicious} payloads',
|
|
48
|
+
]);
|
|
49
|
+
expect(out).toContain('rejects \\${malicious} payloads');
|
|
50
|
+
// The marker must NOT appear unescaped — that would let the spec
|
|
51
|
+
// author smuggle template-literal interpolation into realized code.
|
|
52
|
+
expect(out).not.toMatch(/[^\\]\$\{malicious\}/);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('escapes backslashes before other escapes (stable round-trip)', () => {
|
|
56
|
+
const out = generatePostconditionVerification(['regex \\d+ matches']);
|
|
57
|
+
expect(out).toContain('regex \\\\d+ matches');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('emits one console.assert line per postcondition', () => {
|
|
61
|
+
const out = generatePostconditionVerification(['p1', 'p2', 'p3']);
|
|
62
|
+
const matches = out.match(/console\.assert\(true,/g);
|
|
63
|
+
expect(matches?.length).toBe(3);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('wraps the assertion block in NODE_ENV development guard', () => {
|
|
67
|
+
const out = generatePostconditionVerification(['p1']);
|
|
68
|
+
expect(out).toContain("process.env.NODE_ENV === 'development'");
|
|
69
|
+
expect(out).toContain('// === POSTCONDITIONS (dev-mode) ===');
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('produces output that parses as valid JavaScript', async () => {
|
|
73
|
+
// The whole point of #53D — the emitted code must actually parse.
|
|
74
|
+
// Use Function() as a lightweight syntax-check (rejects malformed
|
|
75
|
+
// template literals just as esbuild would).
|
|
76
|
+
const realistic = generatePostconditionVerification([
|
|
77
|
+
"no other nodes' cache entries are affected",
|
|
78
|
+
'response includes a `Last-Modified` header',
|
|
79
|
+
'rejects ${oversized} payloads with 413',
|
|
80
|
+
]);
|
|
81
|
+
// Wrap in a function body to give it a syntactic context.
|
|
82
|
+
const wrap = `(function() {\n${realistic}\n})`;
|
|
83
|
+
expect(() => new Function(`return ${wrap}`)).not.toThrow();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -323,8 +323,28 @@ function inferLogicFromOperationName(context: BehaviorContext): string {
|
|
|
323
323
|
return { success: true };`;
|
|
324
324
|
}
|
|
325
325
|
|
|
326
|
+
/**
|
|
327
|
+
* Escape a postcondition string for safe inclusion in a JS template
|
|
328
|
+
* literal (backtick) — the only chars that can break a backtick string
|
|
329
|
+
* are unescaped backticks and `${` interpolation markers.
|
|
330
|
+
*
|
|
331
|
+
* Postcondition text comes verbatim from the spec author and frequently
|
|
332
|
+
* contains apostrophes (e.g. "no other nodes' cache entries are
|
|
333
|
+
* affected"). Pre-53D the emitter wrapped these in single quotes, so
|
|
334
|
+
* the apostrophe terminated the JS string and esbuild rejected the
|
|
335
|
+
* file. Switching to backticks + this escape closes that class.
|
|
336
|
+
*/
|
|
337
|
+
function escapeForBacktick(text: string): string {
|
|
338
|
+
return text.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$\{/g, '\\${');
|
|
339
|
+
}
|
|
340
|
+
|
|
326
341
|
/**
|
|
327
342
|
* Generate postcondition verification (dev-mode assertions).
|
|
343
|
+
*
|
|
344
|
+
* 53D fix: emit with backtick template literals (not single quotes) so
|
|
345
|
+
* postconditions containing apostrophes — which the spec format
|
|
346
|
+
* encourages for natural prose — survive realize without breaking
|
|
347
|
+
* esbuild's parse.
|
|
328
348
|
*/
|
|
329
349
|
export function generatePostconditionVerification(
|
|
330
350
|
postconditions: string[]
|
|
@@ -332,7 +352,7 @@ export function generatePostconditionVerification(
|
|
|
332
352
|
if (postconditions.length === 0) return '';
|
|
333
353
|
|
|
334
354
|
const checks = postconditions.map(pc =>
|
|
335
|
-
` console.assert(true,
|
|
355
|
+
` console.assert(true, \`POSTCONDITION: ${escapeForBacktick(pc)}\`);`
|
|
336
356
|
);
|
|
337
357
|
|
|
338
358
|
return ` // === POSTCONDITIONS (dev-mode) ===
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@specverse/engines",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.37.0",
|
|
4
4
|
"description": "SpecVerse toolchain — parser, inference, realize, generators, AI, registry, bundles",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"@specverse/engines": "^6.29.3",
|
|
66
66
|
"@specverse/entities": "^5.4.0",
|
|
67
67
|
"@specverse/runtime": "^5.0.1",
|
|
68
|
-
"@specverse/types": "^5.
|
|
68
|
+
"@specverse/types": "^5.2.0",
|
|
69
69
|
"ai": "^6.0.168",
|
|
70
70
|
"ajv": "^8.17.0",
|
|
71
71
|
"ajv-formats": "^2.1.0",
|