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

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); }
package/dist/metadata.js CHANGED
@@ -264,6 +264,11 @@ function mergeResourceGraphBlocks(blocks) {
264
264
  lifetimeRelationIds: blocks.flatMap((block) => ids(block.graph?.lifetimeRelations)),
265
265
  borrowScopeIds: blocks.flatMap((block) => ids(block.graph?.borrowScopes)),
266
266
  unsafeBoundaryIds: blocks.flatMap((block) => ids(block.graph?.unsafeBoundaries)),
267
+ memoryRegionIds: blocks.flatMap((block) => ids(block.graph?.memoryRegions)),
268
+ dataLayoutIds: blocks.flatMap((block) => ids(block.graph?.dataLayouts)),
269
+ pointerEdgeIds: blocks.flatMap((block) => ids(block.graph?.pointerEdges)),
270
+ memoryAccessIds: blocks.flatMap((block) => ids(block.graph?.memoryAccesses)),
271
+ abiBoundaryIds: blocks.flatMap((block) => ids(block.graph?.abiBoundaries)),
267
272
  conflictIds: blocks.flatMap((block) => ids(block.graph?.conflicts)),
268
273
  proofObligationIds: blocks.flatMap((block) => ids(block.graph?.proofObligations)),
269
274
  summary: {
@@ -280,6 +285,11 @@ function mergeResourceGraphBlocks(blocks) {
280
285
  lifetimeRelationCount: sum(blocks, 'lifetimeRelations'),
281
286
  borrowScopeCount: sum(blocks, 'borrowScopes'),
282
287
  unsafeBoundaryCount: sum(blocks, 'unsafeBoundaries'),
288
+ memoryRegionCount: sum(blocks, 'memoryRegions'),
289
+ dataLayoutCount: sum(blocks, 'dataLayouts'),
290
+ pointerEdgeCount: sum(blocks, 'pointerEdges'),
291
+ memoryAccessCount: sum(blocks, 'memoryAccesses'),
292
+ abiBoundaryCount: sum(blocks, 'abiBoundaries'),
283
293
  conflictCount: sum(blocks, 'conflicts'),
284
294
  proofObligationCount: sum(blocks, 'proofObligations'),
285
295
  unsafeBoundariesWithoutProof: sum(blocks, 'unsafeBoundariesWithoutProof')
@@ -12,6 +12,11 @@ const GROUPS = {
12
12
  lifetimeRelation: 'lifetimeRelations',
13
13
  borrowScope: 'borrowScopes',
14
14
  unsafeBoundary: 'unsafeBoundaries',
15
+ memoryRegion: 'memoryRegions',
16
+ dataLayout: 'dataLayouts',
17
+ pointerEdge: 'pointerEdges',
18
+ memoryAccess: 'memoryAccesses',
19
+ abiBoundary: 'abiBoundaries',
15
20
  conflict: 'conflicts',
16
21
  proofObligation: 'proofObligations'
17
22
  };
@@ -41,6 +46,11 @@ export function parseResourceGraphBlock(block) {
41
46
  borrowScopes: [],
42
47
  borrowScopeRegions: [],
43
48
  unsafeBoundaries: [],
49
+ memoryRegions: [],
50
+ dataLayouts: [],
51
+ pointerEdges: [],
52
+ memoryAccesses: [],
53
+ abiBoundaries: [],
44
54
  conflicts: [],
45
55
  proofObligations: [],
46
56
  parser: { status: 'authored', errors: rowIdentity.errors },
@@ -54,14 +64,14 @@ export function parseResourceGraphBlock(block) {
54
64
  metadata: { name }
55
65
  };
56
66
 
57
- for (const rawLine of block.body.split('\n')) {
58
- const line = rawLine.trim();
67
+ for (const authoredLine of readAuthoredLines(block)) {
68
+ const line = authoredLine.text;
59
69
  if (!line || line.startsWith('#') || isGraphPropertyLine(line)) continue;
60
70
  const match = /^([A-Za-z_$][\w$-]*)\s+([A-Za-z_$][\w$-]*)(.*)$/.exec(line);
61
71
  if (!match) continue;
62
72
  const [, rowKind, rowName, rest] = match;
63
73
  const normalized = normalizeRowKind(rowKind);
64
- const record = parseResourceRecord(normalized, rowName, rest, graph);
74
+ const record = parseResourceRecord(normalized, rowName, rest, graph, authoredLine);
65
75
  const group = GROUPS[normalized];
66
76
  if (record && group) rowIdentity.push(graph[group], record, { rowKind, normalizedRowKind: normalized, name: rowName });
67
77
  }
@@ -73,6 +83,7 @@ export function parseResourceGraphBlock(block) {
73
83
  resourceIds: ids(graph.resources),
74
84
  ownerIds: ids(graph.owners),
75
85
  lifetimeRegionIds: ids(graph.lifetimeRegions),
86
+ lowLevelPrimitiveIds: ids([...graph.memoryRegions, ...graph.dataLayouts, ...graph.pointerEdges, ...graph.memoryAccesses, ...graph.abiBoundaries]),
76
87
  sourcePaths: unique(allRecords(graph).map((record) => record.sourcePath)),
77
88
  evidenceIds: unique([...graph.evidenceIds, ...allRecords(graph).flatMap((record) => record.evidenceIds ?? [])]),
78
89
  blockerReasonCodes: unique(graph.conflicts.map((record) => record.reasonCode))
@@ -90,8 +101,8 @@ export function parseResourceGraphBlock(block) {
90
101
  };
91
102
  }
92
103
 
93
- function parseResourceRecord(kind, name, text, graph) {
94
- const common = commonRecord(kind, name, text, graph);
104
+ function parseResourceRecord(kind, name, text, graph, authoredLine = {}) {
105
+ const common = commonRecord(kind, name, text, graph, authoredLine);
95
106
  if (kind === 'resource') return cleanRecord({ ...common, resourceKind: readInlineWord('resourceKind', text) ?? readInlineWord('kind', text) ?? name, ownerId: readInlineWord('owner', text) ?? readInlineWord('ownerId', text), ownerName: readInlineWord('ownerName', text) });
96
107
  if (kind === 'owner') return cleanRecord({ ...common, ownerKind: readInlineWord('ownerKind', text) ?? readInlineWord('kind', text) ?? 'owner' });
97
108
  if (kind === 'loan') return cleanRecord({ ...common, resourceId: readInlineWord('resource', text) ?? readInlineWord('resourceId', text), ownerId: readInlineWord('owner', text) ?? readInlineWord('ownerId', text), lifetimeRegionId: readInlineWord('lifetime', text) ?? readInlineWord('lifetimeRegion', text) ?? readInlineWord('lifetimeRegionId', text), mode: readInlineWord('mode', text) ?? 'unknown', access: readInlineWord('access', text) });
@@ -103,18 +114,31 @@ function parseResourceRecord(kind, name, text, graph) {
103
114
  if (kind === 'lifetimeRelation') return cleanRecord({ ...common, relationKind: readInlineWord('relationKind', text) ?? readInlineWord('kind', text) ?? 'outlives', fromLifetimeId: readInlineWord('fromLifetime', text) ?? readInlineWord('fromLifetimeId', text) ?? readInlineWord('from', text), toLifetimeId: readInlineWord('toLifetime', text) ?? readInlineWord('toLifetimeId', text) ?? readInlineWord('to', text), from: readInlineWord('from', text), to: readInlineWord('to', text) });
104
115
  if (kind === 'borrowScope') return cleanRecord({ ...common, scopeKind: readInlineWord('scopeKind', text) ?? readInlineWord('kind', text) ?? 'borrow-scope', constraintKind: readInlineWord('constraintKind', text), constraintKinds: readInlineList(text, 'constraint', 'constraints', 'constraintKind', 'constraintKinds') ?? [], ownershipKind: readInlineWord('ownershipKind', text), lifetimeKind: readInlineWord('lifetimeKind', text), controlFlowKind: readInlineWord('controlFlowKind', text), sourceControlFlowId: readInlineWord('sourceControlFlow', text) ?? readInlineWord('sourceControlFlowId', text), lifetimeRegionId: readInlineWord('lifetime', text) ?? readInlineWord('lifetimeRegion', text) ?? readInlineWord('lifetimeRegionId', text), resourceId: readInlineWord('resource', text) ?? readInlineWord('resourceId', text) });
105
116
  if (kind === 'unsafeBoundary') return cleanRecord({ ...common, resourceId: readInlineWord('resource', text) ?? readInlineWord('resourceId', text), unsafeBoundary: true, proofStatus: readInlineWord('proofStatus', text) ?? readInlineWord('status', text) ?? 'missing', kind: readInlineWord('kind', text) });
117
+ if (kind === 'memoryRegion') return cleanRecord({ ...common, resourceId: readInlineWord('resource', text) ?? readInlineWord('resourceId', text), memoryKind: readInlineWord('memoryKind', text) ?? readInlineWord('kind', text) ?? name, regionKind: readInlineWord('regionKind', text), addressSpace: readInlineWord('addressSpace', text) ?? readInlineWord('space', text), address: readInlineWord('address', text) ?? readInlineWord('baseAddress', text), sizeBytes: readInlineNumber('sizeBytes', text) ?? readInlineNumber('size', text), alignmentBytes: readInlineNumber('alignmentBytes', text) ?? readInlineNumber('alignment', text), pointerWidth: readInlineNumber('pointerWidth', text), endian: readInlineWord('endian', text) ?? readInlineWord('endianness', text), volatile: readInlineFlag('volatile', text), atomic: readInlineFlag('atomic', text), shared: readInlineFlag('shared', text) });
118
+ if (kind === 'dataLayout') return cleanRecord({ ...common, resourceId: readInlineWord('resource', text) ?? readInlineWord('resourceId', text), typeId: readInlineWord('type', text) ?? readInlineWord('typeId', text), structId: readInlineWord('struct', text) ?? readInlineWord('structId', text), fieldId: readInlineWord('field', text) ?? readInlineWord('fieldId', text), bitfieldId: readInlineWord('bitfield', text) ?? readInlineWord('bitfieldId', text), layoutKind: readInlineWord('layoutKind', text) ?? readInlineWord('kind', text), repr: readInlineWord('repr', text), abi: readInlineWord('abi', text), endian: readInlineWord('endian', text) ?? readInlineWord('endianness', text), sizeBytes: readInlineNumber('sizeBytes', text) ?? readInlineNumber('size', text), alignmentBytes: readInlineNumber('alignmentBytes', text) ?? readInlineNumber('alignment', text), offsetBytes: readInlineNumber('offsetBytes', text) ?? readInlineNumber('offset', text), bitWidth: readInlineNumber('bitWidth', text) ?? readInlineNumber('width', text), fieldOrder: readInlineList(text, 'fieldOrder', 'fields'), constraintKinds: readInlineList(text, 'constraint', 'constraints', 'constraintKind', 'constraintKinds') });
119
+ if (kind === 'pointerEdge') return cleanRecord({ ...common, resourceId: readInlineWord('resource', text) ?? readInlineWord('resourceId', text), targetResourceId: readInlineWord('targetResource', text) ?? readInlineWord('targetResourceId', text) ?? readInlineWord('target', text), ownerId: readInlineWord('owner', text) ?? readInlineWord('ownerId', text), lifetimeRegionId: readInlineWord('lifetime', text) ?? readInlineWord('lifetimeRegion', text) ?? readInlineWord('lifetimeRegionId', text), pointerKind: readInlineWord('pointerKind', text) ?? readInlineWord('kind', text) ?? 'pointer', addressSpace: readInlineWord('addressSpace', text) ?? readInlineWord('space', text), pointerWidth: readInlineNumber('pointerWidth', text), aliasKind: readInlineWord('aliasKind', text), mode: readInlineWord('mode', text), provenance: readInlineWord('provenance', text), nullable: readInlineFlag('nullable', text), mutable: readInlineFlag('mutable', text) });
120
+ if (kind === 'memoryAccess') return cleanRecord({ ...common, resourceId: readInlineWord('resource', text) ?? readInlineWord('resourceId', text), accessKind: readInlineWord('accessKind', text) ?? readInlineWord('kind', text) ?? name, operationKind: readInlineWord('operation', text) ?? readInlineWord('operationKind', text), memoryOrder: readInlineWord('memoryOrder', text) ?? readInlineWord('ordering', text), lockId: readInlineWord('lock', text) ?? readInlineWord('lockId', text), synchronizationKey: readInlineWord('sync', text) ?? readInlineWord('synchronizationKey', text), reads: readInlineList(text, 'read', 'reads'), writes: readInlineList(text, 'write', 'writes'), volatile: readInlineFlag('volatile', text), atomic: readInlineFlag('atomic', text), proofStatus: readInlineWord('proofStatus', text) ?? readInlineWord('status', text) ?? 'missing' });
121
+ if (kind === 'abiBoundary') return cleanRecord({ ...common, resourceId: readInlineWord('resource', text) ?? readInlineWord('resourceId', text), callableId: readInlineWord('callable', text) ?? readInlineWord('callableId', text), functionId: readInlineWord('function', text) ?? readInlineWord('functionId', text), boundaryKind: readInlineWord('boundaryKind', text) ?? readInlineWord('kind', text) ?? 'abi-boundary', abi: readInlineWord('abi', text), abiKind: readInlineWord('abiKind', text), callingConvention: readInlineWord('callingConvention', text) ?? readInlineWord('convention', text), pointerWidth: readInlineNumber('pointerWidth', text), endian: readInlineWord('endian', text) ?? readInlineWord('endianness', text), ffiBoundary: readInlineWord('ffiBoundary', text), proofStatus: readInlineWord('proofStatus', text) ?? readInlineWord('status', text) ?? 'missing' });
106
122
  if (kind === 'conflict') return cleanRecord({ ...common, resourceId: readInlineWord('resource', text) ?? readInlineWord('resourceId', text), ownerId: readInlineWord('owner', text) ?? readInlineWord('ownerId', text), loanId: readInlineWord('loan', text) ?? readInlineWord('loanId', text), aliasId: readInlineWord('alias', text) ?? readInlineWord('aliasId', text), unsafeBoundaryId: readInlineWord('unsafeBoundary', text) ?? readInlineWord('unsafeBoundaryId', text), reasonCode: readInlineWord('reasonCode', text), message: readInlineQuoted('message', text), status: readInlineWord('status', text) ?? 'open', severity: readInlineWord('severity', text) ?? 'error' });
107
123
  if (kind === 'proofObligation') return cleanRecord({ ...common, resourceId: readInlineWord('resource', text) ?? readInlineWord('resourceId', text), conflictId: readInlineWord('conflict', text) ?? readInlineWord('conflictId', text), kind: readInlineWord('kind', text), status: readInlineWord('status', text) ?? 'open', statement: readInlineQuoted('statement', text) });
108
124
  return undefined;
109
125
  }
110
126
 
111
- function commonRecord(kind, name, text, graph) {
127
+ function commonRecord(kind, name, text, graph, authoredLine = {}) {
112
128
  return cleanRecord({
113
129
  recordKind: recordKind(kind),
114
130
  id: idFrom(text, `${recordPrefix(kind)}_${name}`),
115
131
  name,
116
132
  sourcePath: readInlineWord('sourcePath', text) ?? readInlineWord('path', text) ?? graph.sourcePath,
117
133
  sourceHash: readInlineWord('sourceHash', text) ?? graph.sourceHash,
134
+ sourceSpan: authoredLine.sourceSpan,
135
+ authoredSourceSpan: authoredLine.sourceSpan,
136
+ sourceMapIds: readInlineList(text, 'sourceMap', 'sourceMaps', 'sourceMapId', 'sourceMapIds'),
137
+ sourceMapMappingIds: readInlineList(text, 'sourceMapMapping', 'sourceMapMappings', 'sourceMapMappingId', 'sourceMapMappingIds'),
138
+ proofEvidenceIds: readInlineList(text, 'proofEvidence', 'proofEvidenceId', 'proofEvidenceIds'),
139
+ proofObligationIds: readInlineList(text, 'proofObligation', 'proofObligations', 'proofObligationId', 'proofObligationIds', 'obligation', 'obligations'),
140
+ missingEvidence: readInlineList(text, 'missingEvidence'),
141
+ failClosed: readInlineFlag('failClosed', text),
118
142
  evidenceIds: readInlineList(text, 'evidence', 'evidenceIds') ?? graph.evidenceIds,
119
143
  metadata: { authoredName: name }
120
144
  });
@@ -134,6 +158,11 @@ function summarize(graph) {
134
158
  lifetimeRelations: graph.lifetimeRelations.length,
135
159
  borrowScopes: graph.borrowScopes.length,
136
160
  unsafeBoundaries: graph.unsafeBoundaries.length,
161
+ memoryRegions: graph.memoryRegions.length,
162
+ dataLayouts: graph.dataLayouts.length,
163
+ pointerEdges: graph.pointerEdges.length,
164
+ memoryAccesses: graph.memoryAccesses.length,
165
+ abiBoundaries: graph.abiBoundaries.length,
137
166
  conflicts: graph.conflicts.length,
138
167
  proofObligations: graph.proofObligations.length,
139
168
  unsafeBoundariesWithoutProof: graph.unsafeBoundaries.filter((record) => record.proofStatus !== 'passed').length,
@@ -155,6 +184,11 @@ function allRecords(graph) {
155
184
  ...graph.lifetimeRelations,
156
185
  ...graph.borrowScopes,
157
186
  ...graph.unsafeBoundaries,
187
+ ...graph.memoryRegions,
188
+ ...graph.dataLayouts,
189
+ ...graph.pointerEdges,
190
+ ...graph.memoryAccesses,
191
+ ...graph.abiBoundaries,
158
192
  ...graph.conflicts,
159
193
  ...graph.proofObligations
160
194
  ];
@@ -165,6 +199,11 @@ function normalizeRowKind(kind) {
165
199
  if (kind === 'outlives' || kind === 'lifetimeRelation' || kind === 'lifeRelation') return 'lifetimeRelation';
166
200
  if (kind === 'borrow' || kind === 'borrowScope' || kind === 'borrowRegion') return 'borrowScope';
167
201
  if (kind === 'unsafe' || kind === 'unsafeBoundary') return 'unsafeBoundary';
202
+ if (kind === 'memory' || kind === 'memoryRegion' || kind === 'region') return 'memoryRegion';
203
+ if (kind === 'layout' || kind === 'dataLayout') return 'dataLayout';
204
+ if (kind === 'pointer' || kind === 'ptr' || kind === 'address') return 'pointerEdge';
205
+ if (kind === 'access' || kind === 'memoryAccess' || kind === 'atomic' || kind === 'volatile') return 'memoryAccess';
206
+ if (kind === 'abi' || kind === 'abiBoundary' || kind === 'callBoundary') return 'abiBoundary';
168
207
  if (kind === 'proof' || kind === 'obligation' || kind === 'proofObligation') return 'proofObligation';
169
208
  return kind;
170
209
  }
@@ -174,6 +213,11 @@ function recordKind(kind) {
174
213
  if (kind === 'lifetimeRelation') return 'lifetime-relation';
175
214
  if (kind === 'borrowScope') return 'borrow-scope';
176
215
  if (kind === 'unsafeBoundary') return 'unsafe-boundary';
216
+ if (kind === 'memoryRegion') return 'memory-region';
217
+ if (kind === 'dataLayout') return 'data-layout';
218
+ if (kind === 'pointerEdge') return 'pointer-edge';
219
+ if (kind === 'memoryAccess') return 'memory-access';
220
+ if (kind === 'abiBoundary') return 'abi-boundary';
177
221
  if (kind === 'proofObligation') return 'proof-obligation';
178
222
  return kind;
179
223
  }
@@ -195,6 +239,7 @@ function readListLine(label, body) {
195
239
  }
196
240
  function readInlineWord(label, text) { return new RegExp('(?:^|\\s)' + label + '\\s+([^\\s,]+)').exec(text)?.[1]?.trim(); }
197
241
  function readInlineQuoted(label, text) { return new RegExp("(?:^|\\s)" + label + "\\s+[\"']([^\"']+)[\"']").exec(text)?.[1]?.trim(); }
242
+ function readInlineFlag(label, text) { return new RegExp('(?:^|\\s)' + label + '(?:\\s|$)').test(text) || undefined; }
198
243
  function readInlineNumber(label, text) {
199
244
  const value = readInlineWord(label, text);
200
245
  return value === undefined ? undefined : Number(value);
@@ -208,6 +253,21 @@ function readInlineList(text, ...labels) {
208
253
  }
209
254
  function ids(records = []) { return records.map((record) => record?.id).filter(Boolean); }
210
255
  function unique(values = []) { return [...new Set(values.filter(Boolean))]; }
256
+ function readAuthoredLines(block) {
257
+ const lines = block.body.split('\n');
258
+ const records = [];
259
+ let lineStart = block.syntax?.bodyStartOffset ?? 0;
260
+ for (const rawLine of lines) {
261
+ const rawEnd = lineStart + rawLine.length;
262
+ const leading = /^\s*/.exec(rawLine)?.[0].length ?? 0;
263
+ const trailing = /\s*$/.exec(rawLine)?.[0].length ?? 0;
264
+ const startOffset = lineStart + leading;
265
+ const endOffset = Math.max(startOffset, rawEnd - trailing);
266
+ records.push({ text: rawLine.trim(), sourceSpan: typeof block.sourceSpan === 'function' ? block.sourceSpan(startOffset, endOffset) : undefined });
267
+ lineStart = rawEnd + 1;
268
+ }
269
+ return records;
270
+ }
211
271
  function cleanRecord(record) {
212
272
  return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined && (!Array.isArray(value) || value.length > 0)));
213
273
  }
@@ -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),
@@ -16,8 +16,8 @@ export const ROW_SYNTAX_CONFIG = Object.freeze({
16
16
  runtimeCapabilities: rowConfig('runtimeCapabilityRow', 'runtime_capability_row', runtimeRows, normalizeRuntimeCapabilityRow),
17
17
  runtimeCapabilityMatrix: rowConfig('runtimeCapabilityRow', 'runtime_capability_row', runtimeRows, normalizeRuntimeCapabilityRow),
18
18
  runtimeHosts: rowConfig('runtimeCapabilityRow', 'runtime_capability_row', runtimeRows, normalizeRuntimeCapabilityRow),
19
- resourceGraph: rowConfig('resourceGraphRow', 'resource_graph_row', words('resource owner loan alias move drop escape lifetime lifetimeRegion life outlives lifetimeRelation lifeRelation borrow borrowScope borrowRegion unsafe unsafeBoundary conflict proof proofObligation obligation'), normalizeResourceGraphRow),
20
- semanticResourceGraph: rowConfig('resourceGraphRow', 'resource_graph_row', words('resource owner loan alias move drop escape lifetime lifetimeRegion life outlives lifetimeRelation lifeRelation borrow borrowScope borrowRegion unsafe unsafeBoundary conflict proof proofObligation obligation'), normalizeResourceGraphRow),
19
+ resourceGraph: rowConfig('resourceGraphRow', 'resource_graph_row', words('resource owner loan alias move drop escape lifetime lifetimeRegion life outlives lifetimeRelation lifeRelation borrow borrowScope borrowRegion unsafe unsafeBoundary memory memoryRegion region layout dataLayout pointer ptr address access memoryAccess atomic volatile abi abiBoundary callBoundary conflict proof proofObligation obligation'), normalizeResourceGraphRow),
20
+ semanticResourceGraph: rowConfig('resourceGraphRow', 'resource_graph_row', words('resource owner loan alias move drop escape lifetime lifetimeRegion life outlives lifetimeRelation lifeRelation borrow borrowScope borrowRegion unsafe unsafeBoundary memory memoryRegion region layout dataLayout pointer ptr address access memoryAccess atomic volatile abi abiBoundary callBoundary conflict proof proofObligation obligation'), normalizeResourceGraphRow),
21
21
  applicationSurface: rowConfig('applicationSurfaceRow', 'application_surface_row', appRows, normalizeApplicationSurfaceRow),
22
22
  appHost: rowConfig('applicationSurfaceRow', 'application_surface_row', appRows, normalizeApplicationSurfaceRow),
23
23
  plugin: rowConfig('applicationSurfaceRow', 'application_surface_row', appRows, normalizeApplicationSurfaceRow),
@@ -79,6 +79,11 @@ function normalizeResourceGraphRow(rowKind) {
79
79
  if (rowKind === 'lifeRelation') return 'lifetimeRelation';
80
80
  if (rowKind === 'borrowRegion') return 'borrowScope';
81
81
  if (rowKind === 'unsafe') return 'unsafeBoundary';
82
+ if (rowKind === 'memory' || rowKind === 'region') return 'memoryRegion';
83
+ if (rowKind === 'layout') return 'dataLayout';
84
+ if (rowKind === 'pointer' || rowKind === 'ptr' || rowKind === 'address') return 'pointerEdge';
85
+ if (rowKind === 'access' || rowKind === 'atomic' || rowKind === 'volatile') return 'memoryAccess';
86
+ if (rowKind === 'abi' || rowKind === 'callBoundary') return 'abiBoundary';
82
87
  if (rowKind === 'proof' || rowKind === 'proofObligation') return 'obligation';
83
88
  return rowKind;
84
89
  }
@@ -135,6 +140,7 @@ function normalizeSemanticEditRow(rowKind) {
135
140
  function normalizeGateAdmissionRow(rowKind) {
136
141
  if (rowKind === 'proofEvidence') return 'evidence';
137
142
  if (rowKind === 'admissionDecision') return 'admission';
143
+ if (rowKind === 'obligation') return 'proofObligation';
138
144
  if (rowKind === 'gap') return 'proofGap';
139
145
  return rowKind;
140
146
  }
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.72",
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",