@shapeshift-labs/frontier-lang-parser 0.3.70 → 0.3.71

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.
@@ -0,0 +1,116 @@
1
+ export function proofObligationRecord(name, text, authoredLine, rowKind) {
2
+ return cleanRecord({
3
+ kind: 'frontier.lang.gateAdmissionEvidence.proofObligation',
4
+ version: 1,
5
+ id: idFrom(text, `gate_admission_obligation_${safeId(name)}`),
6
+ name,
7
+ obligationKind: readInlineWord('kind', text) ?? readInlineWord('obligationKind', text) ?? 'proof',
8
+ status: readInlineWord('status', text) ?? 'missing',
9
+ readiness: readInlineWord('readiness', text),
10
+ capability: readInlineWord('capability', text),
11
+ routeId: readInlineWord('route', text) ?? readInlineWord('routeId', text),
12
+ routeIds: readInlineList(text, 'routeIds'),
13
+ language: readInlineWord('language', text) ?? readInlineWord('sourceLanguage', text),
14
+ sourceLanguage: readInlineWord('sourceLanguage', text) ?? readInlineWord('language', text),
15
+ target: readInlineWord('target', text) ?? readInlineWord('targetLanguage', text),
16
+ sourcePath: readInlineWord('sourcePath', text) ?? readInlineWord('path', text),
17
+ sourceHash: readInlineWord('sourceHash', text),
18
+ targetHash: readInlineWord('targetHash', text),
19
+ outputHash: readInlineWord('outputHash', text),
20
+ telemetryHash: readInlineWord('telemetryHash', text),
21
+ gateIds: readInlineList(text, 'gate', 'gateId', 'gateIds'),
22
+ admissionIds: readInlineList(text, 'admission', 'admissionId', 'admissionIds'),
23
+ evidenceIds: readInlineList(text, 'evidence', 'evidenceIds'),
24
+ proofEvidenceIds: readInlineList(text, 'proofEvidence', 'proofEvidenceIds'),
25
+ requiredSignals: readInlineList(text, 'requiredSignal', 'requiredSignals'),
26
+ providedSignals: readInlineList(text, 'providedSignal', 'providedSignals'),
27
+ missingSignals: readInlineList(text, 'missingSignal', 'missingSignals'),
28
+ missingEvidence: readInlineList(text, 'missingEvidence'),
29
+ reasonCodes: readInlineList(text, 'reasonCode', 'reasonCodes', 'reason', 'reasons'),
30
+ summary: readInlineQuoted('summary', text) ?? readInlineQuoted('message', text),
31
+ failClosed: true,
32
+ ...falseClaims(),
33
+ authoredText: authoredLine.text,
34
+ sourceSpan: authoredLine.sourceSpan,
35
+ authoredSourceSpan: authoredLine.sourceSpan,
36
+ metadata: cleanRecord({ authoredName: name, authoredRowKind: rowKind, ...falseClaims() })
37
+ });
38
+ }
39
+
40
+ export function unknownRowRecord(line, authoredLine) {
41
+ const rowKind = /^([A-Za-z_$][\w$-]*)\b/.exec(line)?.[1];
42
+ const name = new RegExp('^[A-Za-z_$][\\w$-]*\\s+([A-Za-z_$@/.:*-][\\w$./@:*+-]*)').exec(line)?.[1];
43
+ return cleanRecord({
44
+ kind: 'frontier.lang.gateAdmissionEvidence.unknownRow',
45
+ version: 1,
46
+ id: `gate_admission_unknown_${safeId(rowKind ?? 'row')}_${authoredLine.startOffset}`,
47
+ rowKind,
48
+ normalizedRowKind: 'unknown',
49
+ name: name ?? rowKind ?? 'unknown',
50
+ status: 'unsupported',
51
+ reason: 'unsupported-gate-admission-row',
52
+ code: 'unsupported-gate-admission-row',
53
+ failClosed: true,
54
+ ...falseClaims(),
55
+ authoredText: line,
56
+ sourceSpan: authoredLine.sourceSpan,
57
+ authoredSourceSpan: authoredLine.sourceSpan,
58
+ metadata: cleanRecord({ authoredRowKind: rowKind, ...falseClaims() })
59
+ });
60
+ }
61
+
62
+ export function unsupportedRowProofGapRecord(unknownRow, authoredLine) {
63
+ return cleanRecord({
64
+ kind: 'frontier.lang.gateAdmissionEvidence.proofGap',
65
+ version: 1,
66
+ id: `gate_admission_gap_unsupported_${authoredLine.startOffset}`,
67
+ name: unknownRow.name,
68
+ code: 'unsupported-gate-admission-row',
69
+ status: 'missing',
70
+ evidenceIds: [unknownRow.id],
71
+ summary: `Unsupported gateEvidence row "${unknownRow.rowKind ?? 'unknown'}" requires parser support before admission.`,
72
+ failClosed: true,
73
+ ...falseClaims(),
74
+ authoredText: authoredLine.text,
75
+ sourceSpan: authoredLine.sourceSpan,
76
+ authoredSourceSpan: authoredLine.sourceSpan,
77
+ metadata: cleanRecord({ unknownRowId: unknownRow.id, authoredRowKind: unknownRow.rowKind, ...falseClaims() })
78
+ });
79
+ }
80
+
81
+ export function parserUnsupportedRowError(unknownRow) {
82
+ return cleanRecord({
83
+ code: 'unsupported-gate-admission-row',
84
+ message: `Unsupported gateEvidence row "${unknownRow.rowKind ?? 'unknown'}" must be reviewed before admission.`,
85
+ rowId: unknownRow.id,
86
+ rowKind: unknownRow.rowKind,
87
+ sourceSpan: unknownRow.sourceSpan
88
+ });
89
+ }
90
+
91
+ function falseClaims() {
92
+ return {
93
+ autoMergeClaim: false,
94
+ semanticEquivalenceClaim: false,
95
+ runtimeEquivalenceClaim: false,
96
+ gatePassImpliesAdmissionClaim: false,
97
+ targetAdapterReadinessClaim: false
98
+ };
99
+ }
100
+
101
+ function idFrom(text, fallback) { return /@id\(\s*["']([^"']+)["']\s*\)/.exec(text)?.[1] ?? fallback; }
102
+ function safeId(value) { return String(value ?? 'record').replace(/[^A-Za-z0-9_$-]+/g, '_'); }
103
+ function readInlineWord(label, text) { return new RegExp('(?:^|\\s)' + label + '\\s+([^\\s,]+)').exec(unquotedText(text))?.[1]?.trim(); }
104
+ function readInlineQuoted(label, text) { return new RegExp("(?:^|\\s)" + label + "\\s+[\"']([^\"']+)[\"']").exec(text)?.[1]?.trim(); }
105
+ function readInlineList(text, ...labels) {
106
+ const source = unquotedText(text);
107
+ for (const label of labels) {
108
+ const value = new RegExp('(?:^|\\s)' + label + '\\s+([^\\s]+)').exec(source)?.[1]?.trim();
109
+ if (value) return value.split(/[|,]/).map((item) => item.trim()).filter(Boolean);
110
+ }
111
+ return undefined;
112
+ }
113
+ function unquotedText(text) { return text.replace(/"[^"]*"|'[^']*'/g, (match) => ' '.repeat(match.length)); }
114
+ function cleanRecord(record) {
115
+ return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined && (!Array.isArray(value) || value.length > 0) && !(value && typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length === 0)));
116
+ }
@@ -1,3 +1,5 @@
1
+ import { parserUnsupportedRowError, proofObligationRecord, unknownRowRecord, unsupportedRowProofGapRecord } from './gate-admission-evidence-proof-obligations.js';
2
+
1
3
  export function parseGateAdmissionEvidenceBlock(block) {
2
4
  const name = nameFrom(block.header);
3
5
  const surface = {
@@ -9,7 +11,9 @@ export function parseGateAdmissionEvidenceBlock(block) {
9
11
  gates: [],
10
12
  evidence: [],
11
13
  admissions: [],
14
+ proofObligations: [],
12
15
  proofGaps: [],
16
+ unknownRows: [],
13
17
  parser: { status: 'authored', errors: [] },
14
18
  claims: falseClaims(),
15
19
  metadata: { authoredName: name, authoredBlockKind: block.kind }
@@ -17,22 +21,34 @@ export function parseGateAdmissionEvidenceBlock(block) {
17
21
  for (const authoredLine of readAuthoredLines(block)) {
18
22
  const line = authoredLine.text;
19
23
  if (!line || line.startsWith('#')) continue;
20
- const match = /^(gate|evidence|proofEvidence|admission|admissionDecision|gap|proofGap)\s+([A-Za-z_$@/.:*-][\w$./@:*+-]*)(.*)$/.exec(line);
21
- if (!match) continue;
24
+ const match = /^(gate|evidence|proofEvidence|admission|admissionDecision|proofObligation|obligation|gap|proofGap)\s+([A-Za-z_$@/.:*-][\w$./@:*+-]*)(.*)$/.exec(line);
25
+ if (!match) {
26
+ const unknownRow = unknownRowRecord(line, authoredLine);
27
+ surface.unknownRows.push(unknownRow);
28
+ surface.proofGaps.push(unsupportedRowProofGapRecord(unknownRow, authoredLine));
29
+ surface.parser.status = 'needs-review';
30
+ surface.parser.errors.push(parserUnsupportedRowError(unknownRow));
31
+ continue;
32
+ }
22
33
  const [, rowKind, rowName, text] = match;
23
34
  if (rowKind === 'gate') surface.gates.push(gateRecord(rowName, text, authoredLine));
24
35
  else if (rowKind === 'evidence' || rowKind === 'proofEvidence') surface.evidence.push(evidenceRecord(rowName, text, authoredLine, rowKind));
25
36
  else if (rowKind === 'admission' || rowKind === 'admissionDecision') surface.admissions.push(admissionRecord(rowName, text, authoredLine));
37
+ else if (rowKind === 'proofObligation' || rowKind === 'obligation') surface.proofObligations.push(proofObligationRecord(rowName, text, authoredLine, rowKind));
26
38
  else surface.proofGaps.push(proofGapRecord(rowName, text, authoredLine));
27
39
  }
28
40
  surface.gateIds = ids(surface.gates);
29
41
  surface.evidenceIds = ids(surface.evidence);
30
42
  surface.proofEvidenceIds = surface.evidence.filter((record) => record.proof).map((record) => record.id).filter(Boolean);
31
43
  surface.admissionIds = ids(surface.admissions);
44
+ surface.proofObligationIds = ids(surface.proofObligations);
45
+ surface.unknownRowIds = ids(surface.unknownRows);
32
46
  surface.proofGapCodes = uniqueStrings(surface.proofGaps.map((record) => record.code));
33
47
  surface.missingEvidence = uniqueStrings([
34
48
  ...surface.gates.flatMap((record) => record.missingEvidence ?? []),
35
49
  ...surface.admissions.flatMap((record) => record.missingEvidence ?? []),
50
+ ...surface.proofObligations.flatMap((record) => record.missingEvidence ?? []),
51
+ ...surface.proofObligations.flatMap((record) => record.missingSignals ?? []),
36
52
  ...surface.proofGaps.map((record) => record.code)
37
53
  ]);
38
54
  surface.summary = {
@@ -40,10 +56,13 @@ export function parseGateAdmissionEvidenceBlock(block) {
40
56
  evidenceCount: surface.evidence.length,
41
57
  proofEvidenceCount: surface.proofEvidenceIds.length,
42
58
  admissionCount: surface.admissions.length,
59
+ proofObligationCount: surface.proofObligations.length,
43
60
  proofGapCount: surface.proofGaps.length,
61
+ unknownRowCount: surface.unknownRows.length,
44
62
  missingEvidenceCount: surface.missingEvidence.length,
45
63
  passedGateCount: surface.gates.filter((record) => record.status === 'passed').length,
46
64
  failedGateCount: surface.gates.filter((record) => record.status === 'failed').length,
65
+ openProofObligationCount: surface.proofObligations.filter((record) => /missing|blocked|review|open|unknown/.test(record.status ?? '')).length,
47
66
  blockedAdmissionCount: surface.admissions.filter((record) => /blocked|missing|failed|review/.test(record.status ?? '')).length
48
67
  };
49
68
  return surface;
@@ -53,13 +72,18 @@ export function mergeGateAdmissionEvidenceBlocks(blocks) {
53
72
  const gates = uniqueRecords(blocks.flatMap((block) => block.gates ?? []));
54
73
  const evidence = uniqueRecords(blocks.flatMap((block) => block.evidence ?? []));
55
74
  const admissions = uniqueRecords(blocks.flatMap((block) => block.admissions ?? []));
75
+ const proofObligations = uniqueRecords(blocks.flatMap((block) => block.proofObligations ?? []));
56
76
  const proofGaps = uniqueRecords(blocks.flatMap((block) => block.proofGaps ?? []));
77
+ const unknownRows = uniqueRecords(blocks.flatMap((block) => block.unknownRows ?? []));
57
78
  const proofEvidenceIds = evidence.filter((record) => record.proof).map((record) => record.id).filter(Boolean);
58
79
  const missingEvidence = uniqueStrings([
59
80
  ...gates.flatMap((record) => record.missingEvidence ?? []),
60
81
  ...admissions.flatMap((record) => record.missingEvidence ?? []),
82
+ ...proofObligations.flatMap((record) => record.missingEvidence ?? []),
83
+ ...proofObligations.flatMap((record) => record.missingSignals ?? []),
61
84
  ...proofGaps.map((record) => record.code)
62
85
  ]);
86
+ const parserErrors = blocks.flatMap((block) => block.parser?.errors ?? []);
63
87
  return {
64
88
  kind: 'frontier.lang.authoredGateAdmissionEvidenceInput',
65
89
  version: 1,
@@ -70,23 +94,34 @@ export function mergeGateAdmissionEvidenceBlocks(blocks) {
70
94
  gates,
71
95
  evidence,
72
96
  admissions,
97
+ proofObligations,
73
98
  proofGaps,
99
+ unknownRows,
74
100
  gateIds: ids(gates),
75
101
  evidenceIds: ids(evidence),
76
102
  proofEvidenceIds,
77
103
  admissionIds: ids(admissions),
104
+ proofObligationIds: ids(proofObligations),
105
+ unknownRowIds: ids(unknownRows),
78
106
  proofGapCodes: uniqueStrings(proofGaps.map((record) => record.code)),
79
107
  missingEvidence,
108
+ parser: {
109
+ status: parserErrors.length ? 'needs-review' : 'authored',
110
+ errors: parserErrors
111
+ },
80
112
  summary: {
81
113
  blockCount: blocks.length,
82
114
  gateCount: gates.length,
83
115
  evidenceCount: evidence.length,
84
116
  proofEvidenceCount: proofEvidenceIds.length,
85
117
  admissionCount: admissions.length,
118
+ proofObligationCount: proofObligations.length,
86
119
  proofGapCount: proofGaps.length,
120
+ unknownRowCount: unknownRows.length,
87
121
  missingEvidenceCount: missingEvidence.length,
88
122
  passedGateCount: gates.filter((record) => record.status === 'passed').length,
89
123
  failedGateCount: gates.filter((record) => record.status === 'failed').length,
124
+ openProofObligationCount: proofObligations.filter((record) => /missing|blocked|review|open|unknown/.test(record.status ?? '')).length,
90
125
  blockedAdmissionCount: admissions.filter((record) => /blocked|missing|failed|review/.test(record.status ?? '')).length
91
126
  },
92
127
  claims: falseClaims(),
@@ -124,6 +159,7 @@ function gateRecord(name, text, authoredLine) {
124
159
  reasonCodes: readInlineList(text, 'reasonCode', 'reasonCodes'),
125
160
  failClosed: true,
126
161
  claims: falseClaims(),
162
+ authoredText: authoredLine.text,
127
163
  sourceSpan: authoredLine.sourceSpan,
128
164
  authoredSourceSpan: authoredLine.sourceSpan,
129
165
  metadata: cleanRecord({ authoredName: name, summary: readInlineQuoted('summary', text), ...falseClaims() })
@@ -159,6 +195,8 @@ function evidenceRecord(name, text, authoredLine, rowKind) {
159
195
  autoMergeClaim: false,
160
196
  semanticEquivalenceClaim: false,
161
197
  runtimeEquivalenceClaim: false,
198
+ targetAdapterReadinessClaim: false,
199
+ authoredText: authoredLine.text,
162
200
  sourceSpan: authoredLine.sourceSpan,
163
201
  authoredSourceSpan: authoredLine.sourceSpan,
164
202
  metadata: cleanRecord({ authoredName: name, authoredRowKind: rowKind, ...falseClaims() })
@@ -198,6 +236,8 @@ function admissionRecord(name, text, authoredLine) {
198
236
  autoMergeClaim: false,
199
237
  semanticEquivalenceClaim: false,
200
238
  runtimeEquivalenceClaim: false,
239
+ targetAdapterReadinessClaim: false,
240
+ authoredText: authoredLine.text,
201
241
  sourceSpan: authoredLine.sourceSpan,
202
242
  authoredSourceSpan: authoredLine.sourceSpan,
203
243
  metadata: cleanRecord({ authoredName: name, summary: readInlineQuoted('summary', text), ...falseClaims() })
@@ -221,6 +261,7 @@ function proofGapRecord(name, text, authoredLine) {
221
261
  summary: readInlineQuoted('summary', text) ?? readInlineQuoted('message', text),
222
262
  failClosed: true,
223
263
  ...falseClaims(),
264
+ authoredText: authoredLine.text,
224
265
  sourceSpan: authoredLine.sourceSpan,
225
266
  authoredSourceSpan: authoredLine.sourceSpan,
226
267
  metadata: cleanRecord({ authoredName: name, ...falseClaims() })
@@ -237,24 +278,14 @@ function readAuthoredLines(block) {
237
278
  const trailing = /\s*$/.exec(rawLine)?.[0].length ?? 0;
238
279
  const startOffset = lineStart + leading;
239
280
  const endOffset = Math.max(startOffset, rawEnd - trailing);
240
- records.push({
241
- text: rawLine.trim(),
242
- startOffset,
243
- endOffset,
244
- sourceSpan: typeof block.sourceSpan === 'function' ? block.sourceSpan(startOffset, endOffset) : undefined
245
- });
281
+ records.push({ text: rawLine.trim(), startOffset, endOffset, sourceSpan: typeof block.sourceSpan === 'function' ? block.sourceSpan(startOffset, endOffset) : undefined });
246
282
  lineStart = rawEnd + 1;
247
283
  }
248
284
  return records;
249
285
  }
250
286
 
251
287
  function falseClaims() {
252
- return {
253
- autoMergeClaim: false,
254
- semanticEquivalenceClaim: false,
255
- runtimeEquivalenceClaim: false,
256
- gatePassImpliesAdmissionClaim: false
257
- };
288
+ return { autoMergeClaim: false, semanticEquivalenceClaim: false, runtimeEquivalenceClaim: false, gatePassImpliesAdmissionClaim: false, targetAdapterReadinessClaim: false };
258
289
  }
259
290
 
260
291
  function ids(records = []) { return records.map((record) => record?.id).filter(Boolean); }
@@ -227,9 +227,9 @@ function readGenericRowSyntaxChildren(source, block, options, config) {
227
227
  for (const line of readBodyLines(source, block)) {
228
228
  if (!line.text || line.text.startsWith('#')) continue;
229
229
  const row = rowPattern.exec(line.text);
230
- if (!row) continue;
230
+ if (!row) { if (config.childKind === 'gateAdmissionEvidenceRow') children.push(genericUnknownRowChild(source, block, options, line, config, undefined, undefined, 'unsupported-gate-admission-row')); continue; }
231
231
  const [, rowKind, name, rest] = row;
232
- if (!config.rowKinds.has(rowKind)) continue;
232
+ if (!config.rowKinds.has(rowKind)) { if (config.childKind === 'gateAdmissionEvidenceRow') children.push(genericUnknownRowChild(source, block, options, line, config, rowKind, name, 'unsupported-gate-admission-row')); continue; }
233
233
  const normalizedRowKind = config.normalize?.(rowKind) ?? rowKind;
234
234
  const id = idFrom(rest, `${config.idPrefix}_${safeId(normalizedRowKind)}_${safeId(name)}`);
235
235
  let recognized = true;
@@ -264,10 +264,19 @@ function readGenericRowSyntaxChildren(source, block, options, config) {
264
264
  return children;
265
265
  }
266
266
 
267
- function readBodyLines(source, block) {
268
- return readTextLines(source, block.bodyStartOffset, block.bodyEndOffset);
267
+ function genericUnknownRowChild(source, block, options, line, config, rowKind, name, reason) {
268
+ const resolvedName = name ?? rowKind ?? 'unknown';
269
+ return cleanRecord({
270
+ kind: config.childKind === 'gateAdmissionEvidenceRow' ? 'gateAdmissionUnknownRow' : 'genericUnknownRow', rowKind,
271
+ normalizedRowKind: 'unknown', name: resolvedName, id: `gate_admission_unknown_${safeId(rowKind ?? 'row')}_${line.startOffset}`,
272
+ header: line.text, startOffset: line.startOffset, endOffset: line.endOffset, location: sourcePosition(source, line.startOffset),
273
+ parentKind: block.kind, parentId: block.id, parentName: block.name, moduleId: block.moduleId, moduleName: block.moduleName,
274
+ sourceSpan: sourceSpan(source, block, line.startOffset, line.endOffset, options), recognized: false, reason
275
+ });
269
276
  }
270
277
 
278
+ function readBodyLines(source, block) { return readTextLines(source, block.bodyStartOffset, block.bodyEndOffset); }
279
+
271
280
  function readTextLines(source, startOffset, endOffset) {
272
281
  const body = source.slice(startOffset, endOffset);
273
282
  const lines = body.split('\n');
@@ -6,7 +6,7 @@ const interlinguaRows = words('layer constraint edge obligation proofObligation
6
6
  const packageRows = words('metadata dependency script export gap proofGap evidence proofEvidence');
7
7
  const runtimeRows = words('host runtimeHost hostProfile sourceHost targetHost capability hostCapability hostBinding binding requirement runtimeRequirement requiredRuntime evidence proofEvidence gap proofGap');
8
8
  const semanticEditRows = words('script semanticEditScript projection semanticEditProjection replay semanticEditReplay');
9
- const gateAdmissionRows = words('gate evidence proofEvidence admission admissionDecision gap proofGap');
9
+ const gateAdmissionRows = words('gate evidence proofEvidence admission admissionDecision proofObligation obligation gap proofGap');
10
10
 
11
11
  export const ROW_SYNTAX_CONFIG = Object.freeze({
12
12
  interlingua: rowConfig('interlinguaRow', 'interlingua_row', interlinguaRows, normalizeInterlinguaRow),
@@ -135,6 +135,7 @@ function normalizeSemanticEditRow(rowKind) {
135
135
  function normalizeGateAdmissionRow(rowKind) {
136
136
  if (rowKind === 'proofEvidence') return 'evidence';
137
137
  if (rowKind === 'admissionDecision') return 'admission';
138
+ if (rowKind === 'obligation') return 'proofObligation';
138
139
  if (rowKind === 'gap') return 'proofGap';
139
140
  return rowKind;
140
141
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapeshift-labs/frontier-lang-parser",
3
- "version": "0.3.70",
3
+ "version": "0.3.71",
4
4
  "description": "Parser for the first Frontier Lang .frontier syntax slice.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -22,7 +22,7 @@
22
22
  ],
23
23
  "scripts": {
24
24
  "build": "node scripts/build.mjs",
25
- "test": "npm run build && node test/smoke.mjs && node test/member-identity-smoke.mjs && node test/generic-row-parse-identity-smoke.mjs && node test/type-variant-payload-smoke.mjs && node test/type-generic-ref-smoke.mjs && node test/type-parameter-constraints-smoke.mjs && node test/type-structural-expression-smoke.mjs && node test/action-body-smoke.mjs && node test/action-structured-literals-smoke.mjs && node test/action-return-smoke.mjs && node test/action-else-smoke.mjs && node test/action-match-smoke.mjs && node test/action-for-in-smoke.mjs && node test/action-repeat-smoke.mjs && node test/action-call-smoke.mjs && node test/semantic-operation-edit-smoke.mjs && node test/target-projection-aggregate-smoke.mjs && node test/conversion-constraint-fields-smoke.mjs && node test/conversion-evidence-smoke.mjs && node test/package-canvas-surface-smoke.mjs && node test/view-render-graph-smoke.mjs && node test/resource-graph-smoke.mjs && node test/interlingua-smoke.mjs && node test/dialect-registry-smoke.mjs",
25
+ "test": "npm run build && node test/smoke.mjs && node test/member-identity-smoke.mjs && node test/generic-row-parse-identity-smoke.mjs && node test/type-variant-payload-smoke.mjs && node test/type-generic-ref-smoke.mjs && node test/type-parameter-constraints-smoke.mjs && node test/type-structural-expression-smoke.mjs && node test/action-body-smoke.mjs && node test/action-structured-literals-smoke.mjs && node test/action-return-smoke.mjs && node test/action-else-smoke.mjs && node test/action-match-smoke.mjs && node test/action-for-in-smoke.mjs && node test/action-repeat-smoke.mjs && node test/action-call-smoke.mjs && node test/semantic-operation-edit-smoke.mjs && node test/target-projection-aggregate-smoke.mjs && node test/conversion-constraint-fields-smoke.mjs && node test/conversion-evidence-smoke.mjs && node test/gate-admission-evidence-smoke.mjs && node test/package-canvas-surface-smoke.mjs && node test/view-render-graph-smoke.mjs && node test/resource-graph-smoke.mjs && node test/interlingua-smoke.mjs && node test/dialect-registry-smoke.mjs",
26
26
  "typecheck": "node ./node_modules/typescript/bin/tsc --noEmit -p test/tsconfig.json",
27
27
  "fuzz": "npm run build && node fuzz/smoke.mjs",
28
28
  "bench": "npm run build && node bench/smoke.mjs",