@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 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?.query?.proofEvidenceIds ?? []).concat(blocks.flatMap((block) => block.record?.query?.constraintEvidenceIds ?? [])))],
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))); }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapeshift-labs/frontier-lang-parser",
3
- "version": "0.3.21",
3
+ "version": "0.3.23",
4
4
  "description": "Parser for the first Frontier Lang .frontier syntax slice.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",