@shapeshift-labs/frontier-lang-parser 0.3.21 → 0.3.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/dist/index.js +4 -1
- package/dist/metadata.js +1 -1
- package/dist/target-projection.js +84 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -220,6 +220,23 @@ npm install @shapeshift-labs/frontier-lang-parser
|
|
|
220
220
|
|
|
221
221
|
The parser projects text into `@shapeshift-labs/frontier-lang-kernel` documents. The syntax is intentionally small and experimental.
|
|
222
222
|
|
|
223
|
+
## Authored target projection syntax
|
|
224
|
+
|
|
225
|
+
`.frontier` target blocks can carry projection contracts next to their emit settings. These rows describe what a target lowering claims to represent, what it still needs proof for, and which losses or missing evidence must stay visible to merge and translation tooling.
|
|
226
|
+
|
|
227
|
+
```frontier
|
|
228
|
+
target rust @id("target_rust") {
|
|
229
|
+
language rust
|
|
230
|
+
package example_todo
|
|
231
|
+
emitPath src/generated/todo.rs
|
|
232
|
+
moduleFormat crate
|
|
233
|
+
projection rustAdapter @id("target_projection_rust") disposition target-adapter readiness needs-review represented semantic-symbol|source-map missing semantic-ownership evidence artifact_todo_title_probe proof artifact_todo_title_probe loss loss_borrow_scope missingEvidence translation-borrow-scope:borrow-across-await
|
|
234
|
+
layer ownership @id("target_layer_rust_ownership") kind semantic-ownership status missing missingEvidence translation-borrow-scope:borrow-across-await
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
The parser stores these rows on the target node metadata as `projectionContracts` and `projectionLayers`. They are target-lowering evidence, not proof of equivalence: `autoMergeClaim` and `semanticEquivalenceClaim` remain false.
|
|
239
|
+
|
|
223
240
|
## Authored decision graph syntax
|
|
224
241
|
|
|
225
242
|
`.frontier` files can carry semantic merge admission evidence directly in `decisionGraph` or `admissionGraph` blocks. These blocks preserve the causal review shape around a candidate edit: semantic changes, gates, evidence records, patch events, admission decisions, merge decisions, graph nodes, and graph edges.
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import { parseParadigmBlock } from './paradigm.js';
|
|
|
9
9
|
import { parseProofBlock } from './proof.js';
|
|
10
10
|
import { parseResourceGraphBlock } from './resource-graph.js';
|
|
11
11
|
import { parseNativeSourceBlock } from './source-evidence.js';
|
|
12
|
+
import { parseTargetProjectionMetadata } from './target-projection.js';
|
|
12
13
|
import { parseViewBlock } from './view.js';
|
|
13
14
|
|
|
14
15
|
export function parseFrontierSource(source, options = {}) {
|
|
@@ -193,6 +194,7 @@ function parseLattice(block) {
|
|
|
193
194
|
}
|
|
194
195
|
function parseTarget(block) {
|
|
195
196
|
const name = nameFrom(block.header);
|
|
197
|
+
const metadata = parseTargetProjectionMetadata(block.body, name);
|
|
196
198
|
return targetNode({
|
|
197
199
|
id: idFrom(block.header, `target_${name}`),
|
|
198
200
|
name,
|
|
@@ -201,7 +203,8 @@ function parseTarget(block) {
|
|
|
201
203
|
packageName: readWord('package', block.body),
|
|
202
204
|
emitPath: readWord('emitPath', block.body),
|
|
203
205
|
moduleFormat: readWord('moduleFormat', block.body)
|
|
204
|
-
}
|
|
206
|
+
},
|
|
207
|
+
...(metadata ? { metadata } : {})
|
|
205
208
|
});
|
|
206
209
|
}
|
|
207
210
|
function readList(label, body) { const line = new RegExp('^\\s*' + label + '\\s+([^\\n]+)', 'm').exec(body)?.[1]; return line ? line.split(',').map((item) => item.trim()).filter(Boolean) : undefined; }
|
package/dist/metadata.js
CHANGED
|
@@ -168,7 +168,7 @@ function mergeInterlinguaBlocks(blocks) {
|
|
|
168
168
|
obligationIds: blocks.flatMap((block) => ids(block.record?.obligations)),
|
|
169
169
|
loweringIds: blocks.flatMap((block) => ids(block.record?.loweringRecords)),
|
|
170
170
|
liftIds: blocks.flatMap((block) => ids(block.record?.liftRecords)),
|
|
171
|
-
evidenceIds: [...new Set(blocks.flatMap((block) => block.record?.
|
|
171
|
+
evidenceIds: [...new Set(blocks.flatMap((block) => block.record?.lowering?.evidenceIds ?? []).concat(blocks.flatMap((block) => block.record?.query?.proofEvidenceIds ?? []), blocks.flatMap((block) => block.record?.query?.constraintEvidenceIds ?? [])))],
|
|
172
172
|
routeIds: [...new Set(interlinguaRecords.map((record) => record.routeId).filter(Boolean))],
|
|
173
173
|
summary: {
|
|
174
174
|
interlinguaCount: interlinguaRecords.length,
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
export function parseTargetProjectionMetadata(body, targetName) {
|
|
2
|
+
const projectionContracts = readTargetProjectionContracts(body, targetName);
|
|
3
|
+
const projectionLayers = readTargetProjectionLayers(body, targetName);
|
|
4
|
+
if (!projectionContracts.length && !projectionLayers.length) return undefined;
|
|
5
|
+
return cleanObject({
|
|
6
|
+
authoredTargetProjection: true,
|
|
7
|
+
projectionContracts,
|
|
8
|
+
projectionLayers,
|
|
9
|
+
projectionContractIds: projectionContracts.map((entry) => entry.id),
|
|
10
|
+
projectionLayerIds: projectionLayers.map((entry) => entry.id),
|
|
11
|
+
evidenceIds: uniqueStrings([...projectionContracts.flatMap((entry) => entry.evidenceIds ?? []), ...projectionLayers.flatMap((entry) => entry.evidenceIds ?? [])]),
|
|
12
|
+
proofEvidenceIds: uniqueStrings(projectionContracts.flatMap((entry) => entry.proofEvidenceIds ?? [])),
|
|
13
|
+
lossIds: uniqueStrings(projectionContracts.flatMap((entry) => entry.lossIds ?? [])),
|
|
14
|
+
missingEvidence: uniqueStrings([...projectionContracts.flatMap((entry) => entry.missingEvidence ?? []), ...projectionLayers.flatMap((entry) => entry.missingEvidence ?? [])]),
|
|
15
|
+
semanticEquivalenceClaim: false,
|
|
16
|
+
autoMergeClaim: false
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function readTargetProjectionContracts(body, targetName) {
|
|
21
|
+
const rows = [];
|
|
22
|
+
const re = /^\s*(projection|lowering)\s+([A-Za-z_$][\w$-]*)([^\n]*)$/gm;
|
|
23
|
+
let match;
|
|
24
|
+
while ((match = re.exec(body))) {
|
|
25
|
+
const [, rowKind, name, text] = match;
|
|
26
|
+
rows.push(cleanObject({
|
|
27
|
+
id: idFrom(text, `target_projection_${targetName}_${name}`),
|
|
28
|
+
kind: 'frontier.lang.targetProjectionContract',
|
|
29
|
+
name,
|
|
30
|
+
rowKind,
|
|
31
|
+
disposition: readInlineWord('disposition', text) ?? readInlineWord('mode', text),
|
|
32
|
+
readiness: readInlineWord('readiness', text),
|
|
33
|
+
adapterId: readInlineWord('adapter', text) ?? readInlineWord('adapterId', text),
|
|
34
|
+
sourceLanguage: readInlineWord('sourceLanguage', text) ?? readInlineWord('source', text),
|
|
35
|
+
representedLayerKinds: readInlineList(text, 'represented', 'representedLayerKinds'),
|
|
36
|
+
missingLayerKinds: readInlineList(text, 'missing', 'missingLayerKinds'),
|
|
37
|
+
requiredLayerKinds: readInlineList(text, 'requires', 'required', 'requiredLayerKinds'),
|
|
38
|
+
evidenceIds: readInlineList(text, 'evidence', 'evidenceId', 'evidenceIds'),
|
|
39
|
+
proofEvidenceIds: readInlineList(text, 'proof', 'proofEvidence', 'proofEvidenceIds'),
|
|
40
|
+
lossIds: readInlineList(text, 'loss', 'lossId', 'lossIds'),
|
|
41
|
+
missingEvidence: readInlineList(text, 'missingEvidence'),
|
|
42
|
+
review: readInlineList(text, 'review'),
|
|
43
|
+
blockers: readInlineList(text, 'blocker', 'blockers'),
|
|
44
|
+
semanticEquivalenceClaim: false,
|
|
45
|
+
autoMergeClaim: false
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
return rows;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function readTargetProjectionLayers(body, targetName) {
|
|
52
|
+
const rows = [];
|
|
53
|
+
const re = /^\s*layer\s+([A-Za-z_$][\w$-]*)([^\n]*)$/gm;
|
|
54
|
+
let match;
|
|
55
|
+
while ((match = re.exec(body))) {
|
|
56
|
+
const [, name, text] = match;
|
|
57
|
+
rows.push(cleanObject({
|
|
58
|
+
id: idFrom(text, `target_layer_${targetName}_${name}`),
|
|
59
|
+
kind: 'frontier.lang.targetProjectionLayer',
|
|
60
|
+
name,
|
|
61
|
+
layerKind: readInlineWord('kind', text) ?? readInlineWord('layerKind', text) ?? name,
|
|
62
|
+
status: readInlineWord('status', text) ?? 'represented',
|
|
63
|
+
evidenceIds: readInlineList(text, 'evidence', 'evidenceId', 'evidenceIds'),
|
|
64
|
+
missingEvidence: readInlineList(text, 'missingEvidence'),
|
|
65
|
+
review: readInlineList(text, 'review'),
|
|
66
|
+
blockers: readInlineList(text, 'blocker', 'blockers'),
|
|
67
|
+
semanticEquivalenceClaim: false,
|
|
68
|
+
autoMergeClaim: false
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
return rows;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function idFrom(text, fallback) { return /@id\(\s*["']([^"']+)["']\s*\)/.exec(text)?.[1] ?? fallback; }
|
|
75
|
+
function readInlineWord(label, text) { return new RegExp('(?:^|\\s)' + label + '\\s+([^\\s,]+)').exec(text)?.[1]?.trim(); }
|
|
76
|
+
function readInlineList(text, ...labels) {
|
|
77
|
+
for (const label of labels) {
|
|
78
|
+
const value = new RegExp('(?:^|\\s)' + label + '\\s+([^\\s]+)').exec(text)?.[1]?.trim();
|
|
79
|
+
if (value) return value.split(/[|,]/).map((item) => item.trim()).filter(Boolean);
|
|
80
|
+
}
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
function uniqueStrings(values) { return [...new Set(values.filter(Boolean))]; }
|
|
84
|
+
function cleanObject(object) { return Object.fromEntries(Object.entries(object).filter(([, value]) => value !== undefined && (!Array.isArray(value) || value.length > 0))); }
|