@shapeshift-labs/frontier-lang-parser 0.3.42 → 0.3.44

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.
@@ -82,6 +82,11 @@ function parseActionBodyLine(line, index) {
82
82
  if (rowKind === 'callEffect') {
83
83
  return compactRecord({ kind: 'callEffect', id: idFrom(rest, `action_body_callEffect_${name}`), name, capability: readInlineWord('capability', rest) ?? readInlineWord('effect', rest) ?? name, input: readInlineActionValue('input', rest) });
84
84
  }
85
+ if (rowKind === 'let') {
86
+ const value = readInlineActionBindingValue('value', rest);
87
+ if (!rawName || rawName.startsWith('@') || !isActionBindingName(name) || !value) return undefined;
88
+ return compactRecord({ kind: 'let', id: idFrom(rest, `action_body_let_${name}`), name, value });
89
+ }
85
90
  if (rowKind === 'return') {
86
91
  const valueText = rawName?.startsWith('@') ? rest.trim() : `${rawName ?? ''}${rest ?? ''}`.trim();
87
92
  return compactRecord({ kind: 'return', id: idFrom(rest, `action_body_return_${index}`), value: valueText ? readActionValue(valueText) : undefined });
@@ -158,6 +163,11 @@ function readInlineActionValue(label, text) {
158
163
  return value ? readActionValue(value) : undefined;
159
164
  }
160
165
 
166
+ function readInlineActionBindingValue(label, text) {
167
+ const value = readInlineActionValue(label, text);
168
+ return isSupportedBindingValue(value) ? value : undefined;
169
+ }
170
+
161
171
  function readActionValue(value) {
162
172
  const text = value.trim();
163
173
  const quoted = /^["']([^"']*)["']$/.exec(text);
@@ -169,6 +179,16 @@ function readActionValue(value) {
169
179
  return { expression: text };
170
180
  }
171
181
 
182
+ function isSupportedBindingValue(value) {
183
+ if (!value) return false;
184
+ if (Object.prototype.hasOwnProperty.call(value, 'value')) return true;
185
+ return /^[A-Za-z_$][\w$-]*(?:\.[A-Za-z_$][\w$-]*)*$/.test(String(value.expression ?? '').trim());
186
+ }
187
+
188
+ function isActionBindingName(value) {
189
+ return /^[A-Za-z_$][\w$-]*$/.test(String(value ?? ''));
190
+ }
191
+
172
192
  function idFrom(header, fallback) { return /@id\(\s*["']([^"']+)["']\s*\)/.exec(header)?.[1] ?? fallback; }
173
193
  function readInlineWord(label, text) { return new RegExp('(?:^|\\s)' + label + '\\s+([^\\s,]+)').exec(text)?.[1]?.trim(); }
174
194
  function firstIdentifier(text) { return /^([A-Za-z_$][\w$-]*)\b/.exec(text)?.[1]; }
@@ -1,4 +1,4 @@
1
- const ACTION_BODY_ROWS = new Set(['set', 'insert', 'remove', 'merge', 'callEffect', 'return', 'if']);
1
+ const ACTION_BODY_ROWS = new Set(['set', 'insert', 'remove', 'merge', 'callEffect', 'return', 'if', 'let']);
2
2
 
3
3
  export function readActionSyntaxChildren(source, block, options) {
4
4
  const body = source.slice(block.bodyStartOffset, block.bodyEndOffset);
@@ -56,7 +56,8 @@ function actionSyntaxChild(source, block, options, line, state, parentActionBody
56
56
  const rowKind = row?.[1] ?? 'unknown';
57
57
  const name = actionRowName(rowKind, row?.[2], rowIndex);
58
58
  const rest = row?.[2]?.startsWith('@') ? ` ${row[2]}${row[3] ?? ''}` : (row?.[3] ?? '');
59
- const recognized = ACTION_BODY_ROWS.has(rowKind);
59
+ const validation = validateActionRow(rowKind, row?.[2], rest);
60
+ const recognized = ACTION_BODY_ROWS.has(rowKind) && validation.ok;
60
61
  return cleanRecord({
61
62
  kind: recognized ? 'actionBodyRow' : 'actionUnknownRow',
62
63
  rowKind,
@@ -75,7 +76,7 @@ function actionSyntaxChild(source, block, options, line, state, parentActionBody
75
76
  parentActionBodyId,
76
77
  sourceSpan: sourceSpan(source, block, line.startOffset, line.endOffset, options),
77
78
  recognized,
78
- reason: recognized ? undefined : 'unsupported-action-body-row'
79
+ reason: recognized ? undefined : validation.reason
79
80
  });
80
81
  }
81
82
 
@@ -86,6 +87,29 @@ function actionRowName(rowKind, rawName, rowIndex) {
86
87
  return rawName && !rawName.startsWith('@') ? rawName : `${rowKind}_${rowIndex}`;
87
88
  }
88
89
 
90
+ function validateActionRow(rowKind, rawName, rest) {
91
+ if (!ACTION_BODY_ROWS.has(rowKind)) return { ok: false, reason: 'unsupported-action-body-row' };
92
+ if (rowKind !== 'let') return { ok: true };
93
+ if (!rawName || rawName.startsWith('@') || !/^[A-Za-z_$][\w$-]*$/.test(rawName)) {
94
+ return { ok: false, reason: 'unsupported-action-binding-name' };
95
+ }
96
+ const value = readInlineValue('value', rest);
97
+ if (!value || !isSupportedBindingValue(value)) {
98
+ return { ok: false, reason: 'unsupported-action-binding-value' };
99
+ }
100
+ return { ok: true };
101
+ }
102
+
103
+ function readInlineValue(label, text) {
104
+ return new RegExp('(?:^|\\s)' + label + '\\s+(.+?)(?=\\s+[A-Za-z_$][\\w$-]*\\s+|$)').exec(text)?.[1]?.trim();
105
+ }
106
+
107
+ function isSupportedBindingValue(value) {
108
+ if (/^["'][^"']*["']$/.test(value)) return true;
109
+ if (/^(true|false|null|-?\d+(?:\.\d+)?)$/.test(value)) return true;
110
+ return /^[A-Za-z_$][\w$-]*(?:\.[A-Za-z_$][\w$-]*)*$/.test(value);
111
+ }
112
+
89
113
  function readNestedBodyBlocks(kind, source) {
90
114
  const blocks = [];
91
115
  const header = new RegExp('\\b' + kind.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '(?:\\s+([^{}\\n]+?))?\\s*\\{', 'g');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapeshift-labs/frontier-lang-parser",
3
- "version": "0.3.42",
3
+ "version": "0.3.44",
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/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/action-body-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",
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",