@swaggerexpert/arazzo-runtime-expression 1.0.1 → 2.0.2

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.
Files changed (57) hide show
  1. package/README.md +157 -77
  2. package/SECURITY.md +2 -1
  3. package/cjs/apg-lite.cjs +28 -28
  4. package/cjs/errors/ArazzoRuntimeExpressionError.cjs +44 -0
  5. package/cjs/errors/ArazzoRuntimeExpressionParseError.cjs +8 -0
  6. package/cjs/extract.cjs +35 -9
  7. package/cjs/{runtime-expression.cjs → grammar.cjs} +824 -286
  8. package/cjs/index.cjs +17 -5
  9. package/cjs/parse/callbacks/cst.cjs +28 -0
  10. package/cjs/parse/index.cjs +31 -32
  11. package/cjs/parse/trace/Expectations.cjs +10 -0
  12. package/cjs/parse/trace/Trace.cjs +35 -0
  13. package/cjs/parse/translators/ASTTranslator/index.cjs +15 -0
  14. package/cjs/parse/translators/ASTTranslator/transformers.cjs +225 -0
  15. package/cjs/parse/translators/CSTTranslator.cjs +55 -0
  16. package/cjs/parse/translators/XMLTranslator.cjs +12 -0
  17. package/cjs/test/index.cjs +18 -0
  18. package/es/errors/ArazzoRuntimeExpressionError.mjs +40 -0
  19. package/es/errors/ArazzoRuntimeExpressionParseError.mjs +3 -0
  20. package/es/extract.mjs +34 -9
  21. package/es/{runtime-expression.mjs → grammar.mjs} +824 -286
  22. package/es/index.mjs +9 -3
  23. package/es/parse/callbacks/cst.mjs +24 -0
  24. package/es/parse/index.mjs +31 -32
  25. package/es/parse/trace/Expectations.mjs +6 -0
  26. package/es/parse/trace/Trace.mjs +30 -0
  27. package/es/parse/translators/ASTTranslator/index.mjs +9 -0
  28. package/es/parse/translators/ASTTranslator/transformers.mjs +219 -0
  29. package/es/parse/translators/CSTTranslator.mjs +50 -0
  30. package/es/parse/translators/XMLTranslator.mjs +7 -0
  31. package/es/test/index.mjs +13 -0
  32. package/package.json +21 -14
  33. package/types/index.d.ts +364 -34
  34. package/cjs/parse/callbacks/body-reference.cjs +0 -14
  35. package/cjs/parse/callbacks/expression.cjs +0 -15
  36. package/cjs/parse/callbacks/header-reference.cjs +0 -14
  37. package/cjs/parse/callbacks/json-pointer.cjs +0 -14
  38. package/cjs/parse/callbacks/name.cjs +0 -14
  39. package/cjs/parse/callbacks/parameter-name.cjs +0 -14
  40. package/cjs/parse/callbacks/path-reference.cjs +0 -14
  41. package/cjs/parse/callbacks/query-reference.cjs +0 -14
  42. package/cjs/parse/callbacks/reference-token.cjs +0 -14
  43. package/cjs/parse/callbacks/source.cjs +0 -14
  44. package/cjs/parse/callbacks/token.cjs +0 -15
  45. package/cjs/test.cjs +0 -15
  46. package/es/parse/callbacks/body-reference.mjs +0 -10
  47. package/es/parse/callbacks/expression.mjs +0 -11
  48. package/es/parse/callbacks/header-reference.mjs +0 -10
  49. package/es/parse/callbacks/json-pointer.mjs +0 -10
  50. package/es/parse/callbacks/name.mjs +0 -10
  51. package/es/parse/callbacks/parameter-name.mjs +0 -10
  52. package/es/parse/callbacks/path-reference.mjs +0 -10
  53. package/es/parse/callbacks/query-reference.mjs +0 -10
  54. package/es/parse/callbacks/reference-token.mjs +0 -10
  55. package/es/parse/callbacks/source.mjs +0 -10
  56. package/es/parse/callbacks/token.mjs +0 -10
  57. package/es/test.mjs +0 -10
package/README.md CHANGED
@@ -20,7 +20,7 @@ It supports Runtime Expressions defined in following Arazzo specification versio
20
20
  <table>
21
21
  <tr>
22
22
  <td align="right" valign="middle">
23
- <img src="https://cdn2.hubspot.net/hubfs/4008838/website/logos/logos_for_download/Tidelift_primary-shorthand-logo.png" alt="Tidelift" width="60" />
23
+ <img src="https://raw.githubusercontent.com/swaggerexpert/arazzo-runtime-expression/main/assets/tidelift.webp" alt="Tidelift" width="60" />
24
24
  </td>
25
25
  <td valign="middle">
26
26
  <a href="https://tidelift.com/subscription/pkg/npm-.swaggerexpert-arazzo-runtime-expression?utm_source=npm-swaggerexpert-arazzo-runtime-expression&utm_medium=referral&utm_campaign=readme">
@@ -37,7 +37,11 @@ It supports Runtime Expressions defined in following Arazzo specification versio
37
37
  - [Usage](#usage)
38
38
  - [Extraction](#extraction)
39
39
  - [Parsing](#parsing)
40
+ - [Translators](#translators)
41
+ - [Statistics](#statistics)
42
+ - [Tracing](#tracing)
40
43
  - [Validation](#validation)
44
+ - [Errors](#errors)
41
45
  - [Grammar](#grammar)
42
46
  - [More about Arazzo runtime expressions](#more-about-arazzo-runtime-expressions)
43
47
  - [License](#license)
@@ -63,17 +67,32 @@ and use [apg-lite](https://github.com/ldthomas/apg-lite) parser generator.
63
67
 
64
68
  Arazzo embeds Runtime Expressions into string values surrounded with `{}` curly braces.
65
69
  To extract Runtime Expressions from this embedded form, use the **extract** function.
66
- Extracted Runtime Expression can be used for further parsing of validation.
70
+ The function returns an array of all extracted expressions, which can be used for further parsing or validation.
67
71
 
68
72
  ```js
69
73
  import { extract, test, parse } from '@swaggerexpert/arazzo-runtime-expression';
70
74
 
71
- const expression = extract('{$request.header.accept}'); // => '$request.header.accept'
75
+ // Extract single expression
76
+ extract('{$request.header.accept}'); // => ['$request.header.accept']
72
77
 
73
- test(expression); // => true
74
- parse(expression); // => { result, ast }
78
+ // Extract multiple expressions from a template string
79
+ extract('client_id={$inputs.clientId}&grant_type={$inputs.grantType}');
80
+ // => ['$inputs.clientId', '$inputs.grantType']
81
+
82
+ // No expressions found
83
+ extract('no expressions here'); // => []
84
+
85
+ // Use extracted expressions
86
+ const expressions = extract('{$url}');
87
+ test(expressions[0]); // => true
88
+ parse(expressions[0]); // => { result, tree }
75
89
  ```
76
90
 
91
+ **Known limitation:** `$request.body#/...` and `$response.body#/...` expressions with JSON pointers cannot be reliably
92
+ extracted from `{expression}` syntax. This is because [RFC 6901](https://datatracker.ietf.org/doc/html/rfc6901)
93
+ (JSON Pointer) allows the `}` character in pointer paths, making it impossible to determine where the expression ends.
94
+ Use `parse()` directly on the raw expression for these cases.
95
+
77
96
  #### Parsing
78
97
 
79
98
  Parsing a Runtime Expression is as simple as importing the **parse** function and calling it.
@@ -88,97 +107,101 @@ const parseResult = parse('$request.header.accept');
88
107
 
89
108
  ```
90
109
  {
91
- result: {
92
- success: true,
93
- state: 101,
94
- stateName: 'MATCH',
95
- length: 22,
96
- matched: 22,
97
- maxMatched: 22,
98
- maxTreeDepth: 13,
99
- nodeHits: 152
100
- },
101
- ast: fnast {
102
- callbacks: [
103
- expression: [Function: expression],
104
- 'parameter-name': [Function: parameterName],
105
- source: [Function: source],
106
- 'header-reference': [Function: headerReference],
107
- 'query-reference': [Function: queryReference],
108
- 'path-reference': [Function: pathReference],
109
- 'body-reference': [Function: bodyReference],
110
- 'json-pointer': [Function: jsonPointer],
111
- 'reference-token': [Function: referenceToken],
112
- name: [Function: name],
113
- token: [Function: token]
114
- ],
115
- init: [Function (anonymous)],
116
- ruleDefined: [Function (anonymous)],
117
- udtDefined: [Function (anonymous)],
118
- down: [Function (anonymous)],
119
- up: [Function (anonymous)],
120
- translate: [Function (anonymous)],
121
- setLength: [Function (anonymous)],
122
- getLength: [Function (anonymous)],
123
- toXml: [Function (anonymous)]
124
- }
110
+ result: <ParseResult['result']>,
111
+ tree: <ParseResult['tree']>,
112
+ stats: <ParseResult['stats']>,
113
+ trace: <ParseResult['trace']>,
125
114
  }
126
115
  ```
127
116
 
128
- ###### Interpreting AST as list of entries
117
+ [TypeScript typings](https://github.com/swaggerexpert/arazzo-runtime-expression/blob/main/types/index.d.ts) are available for all fields attached to parse result object returned by the `parse` function.
118
+
119
+ ##### Translators
120
+
121
+ `@swaggerexpert/arazzo-runtime-expression` provides several translators to convert the parse result into different tree representations.
122
+
123
+ ###### CST translator
124
+
125
+ [Concrete Syntax Tree](https://en.wikipedia.org/wiki/Parse_tree) (Parse tree) representation is available on parse result
126
+ when instance of `CSTTranslator` is provided via a `translator` option to the `parse` function.
127
+ CST is suitable to be consumed by other tools like IDEs, editors, etc...
128
+
129
+ ```js
130
+ import { parse, CSTTranslator } from '@swaggerexpert/arazzo-runtime-expression';
131
+
132
+ const { tree: cst } = parse('$request.header.accept', { translator: new CSTTranslator() });
133
+ ```
134
+
135
+ CST tree has a shape documented by [TypeScript typings (CSTNode)](https://github.com/swaggerexpert/arazzo-runtime-expression/blob/main/types/index.d.ts).
136
+
137
+ ###### AST translator
138
+
139
+ **Default translator**. [Abstract Syntax Tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree) representation is available on parse result
140
+ by default or when instance of `ASTTranslator` is provided via a `translator` option to the `parse` function.
141
+ AST is suitable to be consumed by implementations that need to analyze the structure of the runtime expression.
129
142
 
130
143
  ```js
131
144
  import { parse } from '@swaggerexpert/arazzo-runtime-expression';
132
145
 
133
- const parseResult = parse('$request.header.accept');
134
- const parts = [];
146
+ const { tree: ast } = parse('$request.header.accept');
147
+ ```
148
+
149
+ or
150
+
151
+ ```js
152
+ import { parse, ASTTranslator } from '@swaggerexpert/arazzo-runtime-expression';
135
153
 
136
- parseResult.ast.translate(parts);
154
+ const { tree: ast } = parse('$request.header.accept', { translator: new ASTTranslator() });
137
155
  ```
138
156
 
139
- After running the above code, **parts** variable has the following shape:
157
+ AST tree has a shape documented by [TypeScript typings (ASTNode)](https://github.com/swaggerexpert/arazzo-runtime-expression/blob/main/types/index.d.ts).
158
+
159
+ ###### XML translator
140
160
 
141
161
  ```js
142
- [
143
- [ 'expression', '$request.header.accept' ],
144
- [ 'source', 'header.accept' ],
145
- [ 'header-reference', 'header.accept' ],
146
- [ 'token', 'accept' ],
147
- ]
162
+ import { parse, XMLTranslator } from '@swaggerexpert/arazzo-runtime-expression';
163
+
164
+ const { tree: xml } = parse('$request.header.accept', { translator: new XMLTranslator() });
148
165
  ```
149
166
 
150
- ###### Interpreting AST as XML
167
+ ##### Statistics
168
+
169
+ `parse` function returns additional statistical information about the parsing process.
170
+ Collection of the statistics can be enabled by setting `stats` option to `true`.
151
171
 
152
172
  ```js
153
173
  import { parse } from '@swaggerexpert/arazzo-runtime-expression';
154
174
 
155
- const parseResult = parse('$request.header.accept');
156
- const xml = parseResult.ast.toXml();
175
+ const { stats } = parse('$request.header.accept', { stats: true });
176
+
177
+ stats.displayStats(); // returns operator statistics as string
157
178
  ```
158
179
 
159
- After running the above code, **xml** variable has the following content:
160
-
161
- ```xml
162
- <?xml version="1.0" encoding="utf-8"?>
163
- <root nodes="4" characters="22">
164
- <!-- input string -->
165
- $request.header.accept
166
- <node name="expression" index="0" length="22">
167
- $request.header.accept
168
- <node name="source" index="9" length="13">
169
- header.accept
170
- <node name="header-reference" index="9" length="13">
171
- header.accept
172
- <node name="token" index="16" length="6">
173
- accept
174
- </node><!-- name="token" -->
175
- </node><!-- name="header-reference" -->
176
- </node><!-- name="source" -->
177
- </node><!-- name="expression" -->
178
- </root>
180
+ ##### Tracing
181
+
182
+ `parse` function returns additional tracing information about the parsing process.
183
+ Tracing can be enabled by setting `trace` option to `true`. Tracing is essential
184
+ for debugging failed parses or analyzing rule execution flow.
185
+
186
+ ```js
187
+ import { parse } from '@swaggerexpert/arazzo-runtime-expression';
188
+
189
+ const { result, trace } = parse('$invalid', { trace: true });
190
+
191
+ result.success; // false
192
+ trace.displayTrace(); // returns trace information as string
179
193
  ```
180
194
 
181
- > NOTE: AST can also be traversed in classical way using [depth first traversal](https://www.tutorialspoint.com/data_structures_algorithms/depth_first_traversal.htm). For more information about this option please refer to [apg-js](https://github.com/ldthomas/apg-js) and [apg-js-examples](https://github.com/ldthomas/apg-js-examples).
195
+ Tracing also allows you to infer expected tokens at a failure point. This is useful for generating meaningful syntax error messages.
196
+
197
+ ```js
198
+ import { parse } from '@swaggerexpert/arazzo-runtime-expression';
199
+
200
+ const { trace } = parse('$invalid', { trace: true });
201
+
202
+ const expectations = trace.inferExpectations();
203
+ console.log(expectations.toString()); // e.g., "expected '$url', '$method', '$statusCode', '$request.', ..."
204
+ ```
182
205
 
183
206
  #### Validation
184
207
 
@@ -191,6 +214,30 @@ test('$request.header.accept'); // => true
191
214
  test('nonsensical string'); // => false
192
215
  ```
193
216
 
217
+ #### Errors
218
+
219
+ `@swaggerexpert/arazzo-runtime-expression` provides a structured error class hierarchy,
220
+ enabling precise error handling across runtime expression operations.
221
+
222
+ ```js
223
+ import { ArazzoRuntimeExpressionError, ArazzoRuntimeExpressionParseError } from '@swaggerexpert/arazzo-runtime-expression';
224
+ ```
225
+
226
+ **ArazzoRuntimeExpressionError** is the base class for all errors. **ArazzoRuntimeExpressionParseError** is thrown when parsing fails
227
+ and includes additional context about the expression that failed to parse.
228
+
229
+ ```js
230
+ import { parse, ArazzoRuntimeExpressionParseError } from '@swaggerexpert/arazzo-runtime-expression';
231
+
232
+ try {
233
+ parse(123); // non-string input
234
+ } catch (error) {
235
+ if (error instanceof ArazzoRuntimeExpressionParseError) {
236
+ console.log(error.runtimeExpression); // the expression that failed
237
+ }
238
+ }
239
+ ```
240
+
194
241
  #### Grammar
195
242
 
196
243
  New grammar instance can be created in following way:
@@ -219,8 +266,7 @@ The runtime expression is defined by the following [ABNF](https://tools.ietf.org
219
266
 
220
267
  ```abnf
221
268
  ; Arazzo runtime expression ABNF syntax
222
- expression = ( "$url" / "$method" / "$statusCode" / "$request." source / "$response." source / "$inputs." name / "$outputs." name / "$steps." name / "$workflows." name / "$sourceDescriptions." name / "$components." name / "$components.parameters." parameter-name)
223
- parameter-name = name ; Reuses 'name' rule for parameter names
269
+ expression = ( "$url" / "$method" / "$statusCode" / "$request." source / "$response." source / "$inputs." name / "$outputs." name / "$steps." name / "$workflows." name / "$sourceDescriptions." name / "$components." name )
224
270
  source = ( header-reference / query-reference / path-reference / body-reference )
225
271
  header-reference = "header." token
226
272
  query-reference = "query." name
@@ -228,6 +274,39 @@ path-reference = "path." name
228
274
  body-reference = "body" ["#" json-pointer ]
229
275
  name = *( CHAR )
230
276
 
277
+ ; Grammar for parsing template strings with embedded expressions
278
+ expression-string = *( literal-char / embedded-expression )
279
+ embedded-expression = "{" expression "}"
280
+ literal-char = %x00-7A / %x7C / %x7E-10FFFF ; anything except { (%x7B) and } (%x7D)
281
+
282
+ ; Secondary grammar for parsing $steps name part
283
+ ; Format: {stepId}.{field}.{subField}[#/{jsonPointer}]
284
+ steps-name = steps-id "." steps-field "." steps-sub-field ["#" json-pointer]
285
+ steps-id = 1*(ALPHA / DIGIT / "_" / "-")
286
+ steps-field = "outputs"
287
+ steps-sub-field = 1*(ALPHA / DIGIT / "." / "-" / "_")
288
+
289
+ ; Secondary grammar for parsing $workflows name part
290
+ ; Format: {workflowId}.{field}.{subField}[#/{jsonPointer}]
291
+ workflows-name = workflows-id "." workflows-field "." workflows-sub-field ["#" json-pointer]
292
+ workflows-id = 1*(ALPHA / DIGIT / "_" / "-")
293
+ workflows-field = "inputs" / "outputs"
294
+ workflows-sub-field = 1*(ALPHA / DIGIT / "." / "-" / "_")
295
+
296
+ ; Secondary grammar for parsing $sourceDescriptions name part
297
+ ; Format: {sourceName}.{reference}
298
+ ; reference can be operationId (unconstrained) or workflowId (constrained)
299
+ source-descriptions-name = source-descriptions-source-name "." source-descriptions-reference
300
+ source-descriptions-source-name = 1*(ALPHA / DIGIT / "_" / "-")
301
+ source-descriptions-reference = 1*CHAR
302
+
303
+ ; Secondary grammar for parsing $components name part
304
+ ; Format: {field}.{subField}
305
+ ; Allowed fields: parameters, successActions, failureActions
306
+ components-name = components-field "." components-sub-field
307
+ components-field = "parameters" / "successActions" / "failureActions"
308
+ components-sub-field = 1*(ALPHA / DIGIT / "." / "-" / "_")
309
+
231
310
  ; https://datatracker.ietf.org/doc/html/rfc6901#section-3
232
311
  json-pointer = *( "/" reference-token )
233
312
  reference-token = *( unescaped / escaped )
@@ -256,7 +335,8 @@ CHAR = unescape /
256
335
  %x74 / ; t tab U+0009
257
336
  %x75 4HEXDIG ) ; uXXXX U+XXXX
258
337
  escape = %x5C ; \
259
- unescape = %x20-21 / %x23-5B / %x5D-10FFFF
338
+ unescape = %x20-21 / %x23-5B / %x5D-7A / %x7C / %x7E-10FFFF
339
+ ; %x7B ('{') and %x7D ('}') are excluded from 'unescape'
260
340
 
261
341
  ; https://datatracker.ietf.org/doc/html/rfc5234#appendix-B.1
262
342
  HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
package/SECURITY.md CHANGED
@@ -6,7 +6,8 @@ If you believe you've found an exploitable security issue in @swaggerexpert/araz
6
6
 
7
7
  | Version | Supported |
8
8
  |---------|--------------------|
9
- | ^1.0.0 | :white_check_mark: |
9
+ | ^1.0.0 | :x: |
10
+ | ^2.0.0 | :white_check_mark: |
10
11
 
11
12
  ## Reporting a Vulnerability
12
13
 
package/cjs/apg-lite.cjs CHANGED
@@ -2,31 +2,31 @@
2
2
 
3
3
  exports.__esModule = true;
4
4
  exports.utilities = exports.identifiers = exports.Trace = exports.Stats = exports.Parser = exports.Ast = void 0;
5
- /* *************************************************************************************
6
- * copyright: Copyright (c) 2023 Lowell D. Thomas, all rights reserved
7
- * license: BSD-2-Clause (https://opensource.org/licenses/BSD-2-Clause)
8
- *
9
- * Redistribution and use in source and binary forms, with or without
10
- * modification, are permitted provided that the following conditions are met:
11
- *
12
- * 1. Redistributions of source code must retain the above copyright notice, this
13
- * list of conditions and the following disclaimer.
14
- *
15
- * 2. Redistributions in binary form must reproduce the above copyright notice,
16
- * this list of conditions and the following disclaimer in the documentation
17
- * and/or other materials provided with the distribution.
18
- *
19
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
- *
5
+ /* *************************************************************************************
6
+ * copyright: Copyright (c) 2023 Lowell D. Thomas, all rights reserved
7
+ * license: BSD-2-Clause (https://opensource.org/licenses/BSD-2-Clause)
8
+ *
9
+ * Redistribution and use in source and binary forms, with or without
10
+ * modification, are permitted provided that the following conditions are met:
11
+ *
12
+ * 1. Redistributions of source code must retain the above copyright notice, this
13
+ * list of conditions and the following disclaimer.
14
+ *
15
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
16
+ * this list of conditions and the following disclaimer in the documentation
17
+ * and/or other materials provided with the distribution.
18
+ *
19
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ *
30
30
  * ********************************************************************************* */
31
31
 
32
32
  const Parser = exports.Parser = function fnparser() {
@@ -665,7 +665,7 @@ const Ast = exports.Ast = function fnast() {
665
665
  a.ruleDefined = index => !!nodeCallbacks[index];
666
666
  /* AST node UDT callbacks - called by the parser's `UDT` operator */
667
667
  a.udtDefined = index => !!nodeCallbacks[rules.length + index];
668
- /* called by the parser's `RNM` & `UDT` operators
668
+ /* called by the parser's `RNM` & `UDT` operators
669
669
  builds a record for the downward traversal of the node */
670
670
  a.down = (callbackIndex, name) => {
671
671
  const thisIndex = records.length;
@@ -963,8 +963,8 @@ const Stats = exports.Stats = function fnstats() {
963
963
  out += displayRow('TOTAL', totals.match, totals.empty, totals.nomatch, totals.total);
964
964
  return out;
965
965
  };
966
- /*
967
- Display rule/udt
966
+ /*
967
+ Display rule/udt
968
968
  */
969
969
  this.displayHits = type => {
970
970
  let out = '';
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.default = void 0;
5
+ class ArazzoRuntimeExpressionError extends Error {
6
+ constructor(message, options = undefined) {
7
+ super(message, options);
8
+ this.name = this.constructor.name;
9
+ if (typeof message === 'string') {
10
+ this.message = message;
11
+ }
12
+ if (typeof Error.captureStackTrace === 'function') {
13
+ Error.captureStackTrace(this, this.constructor);
14
+ } else {
15
+ this.stack = new Error(message).stack;
16
+ }
17
+
18
+ /**
19
+ * This needs to stay here until our minimum supported version of Node.js is >= 16.9.0.
20
+ * Node.js is >= 16.9.0 supports error causes natively.
21
+ */
22
+ if (options != null && typeof options === 'object' && Object.hasOwn(options, 'cause') && !('cause' in this)) {
23
+ const {
24
+ cause
25
+ } = options;
26
+ this.cause = cause;
27
+ if (cause instanceof Error && 'stack' in cause) {
28
+ this.stack = `${this.stack}\nCAUSE: ${cause.stack}`;
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Allows to assign arbitrary properties to the error object.
34
+ */
35
+ if (options != null && typeof options === 'object') {
36
+ const {
37
+ cause,
38
+ ...causelessOptions
39
+ } = options;
40
+ Object.assign(this, causelessOptions);
41
+ }
42
+ }
43
+ }
44
+ var _default = exports.default = ArazzoRuntimeExpressionError;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.default = void 0;
5
+ var _ArazzoRuntimeExpressionError = _interopRequireDefault(require("./ArazzoRuntimeExpressionError.cjs"));
6
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
7
+ class ArazzoRuntimeExpressionParseError extends _ArazzoRuntimeExpressionError.default {}
8
+ var _default = exports.default = ArazzoRuntimeExpressionParseError;
package/cjs/extract.cjs CHANGED
@@ -2,20 +2,46 @@
2
2
 
3
3
  exports.__esModule = true;
4
4
  exports.default = void 0;
5
+ var _apgLite = require("apg-lite.cjs");
6
+ var _grammar = _interopRequireDefault(require("./grammar.cjs"));
7
+ var _CSTTranslator = _interopRequireDefault(require("./parse/translators/CSTTranslator.cjs"));
8
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
+ const grammar = new _grammar.default();
10
+
5
11
  /**
6
- * This function is used for extracting the expression from Arazzo Runtime Expression notation.
12
+ * Extract runtime expressions from a string containing embedded {expression} patterns.
7
13
  *
8
14
  * @example
9
15
  *
10
- * extract('{$url}'); // => '$url'
16
+ * extract('{$url}'); // => ['$url']
17
+ * extract('id={$inputs.id}&name={$inputs.name}'); // => ['$inputs.id', '$inputs.name']
11
18
  */
12
-
13
- const extract = arazzoRuntimeExpression => {
14
- var _match$groups$express, _match$groups;
15
- if (typeof arazzoRuntimeExpression !== 'string') {
16
- return null;
19
+ const extract = str => {
20
+ if (typeof str !== 'string') {
21
+ return [];
17
22
  }
18
- const match = arazzoRuntimeExpression.match(/^{(?<expression>.+)}$/);
19
- return (_match$groups$express = match == null || (_match$groups = match.groups) == null ? void 0 : _match$groups.expression) != null ? _match$groups$express : null;
23
+ const parser = new _apgLite.Parser();
24
+ parser.ast = new _CSTTranslator.default();
25
+ const result = parser.parse(grammar, 'expression-string', str);
26
+ if (!result.success) {
27
+ return [];
28
+ }
29
+ const cst = parser.ast.getTree();
30
+ const expressions = [];
31
+
32
+ // Traverse CST to find all embedded-expression nodes
33
+ const traverse = node => {
34
+ if (node.type === 'embedded-expression') {
35
+ const exprNode = node.children.find(c => c.type === 'expression');
36
+ if (exprNode) {
37
+ expressions.push(exprNode.text);
38
+ }
39
+ }
40
+ for (const child of node.children || []) {
41
+ traverse(child);
42
+ }
43
+ };
44
+ traverse(cst);
45
+ return expressions;
20
46
  };
21
47
  var _default = exports.default = extract;