@fieldia/core 0.9.2 → 0.10.0
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/package.json +1 -1
- package/schema/page.schema.json +1128 -89
- package/src/lib/expression/evaluator.d.mts +6 -5
- package/src/lib/expression/evaluator.d.ts +6 -5
- package/src/lib/expression/evaluator.js +37 -22
- package/src/lib/expression/evaluator.js.map +1 -1
- package/src/lib/expression/evaluator.mjs +32 -18
- package/src/lib/expression/evaluator.mjs.map +1 -1
- package/src/lib/expression/expression.d.mts +21 -0
- package/src/lib/expression/expression.d.ts +21 -0
- package/src/lib/expression/expression.js +29 -0
- package/src/lib/expression/expression.js.map +1 -0
- package/src/lib/expression/expression.mjs +26 -0
- package/src/lib/expression/expression.mjs.map +1 -0
- package/src/lib/expression/extractFieldNames.js +6 -1
- package/src/lib/expression/extractFieldNames.js.map +1 -1
- package/src/lib/expression/extractFieldNames.mjs +6 -1
- package/src/lib/expression/extractFieldNames.mjs.map +1 -1
- package/src/lib/expression/functions.d.mts +35 -0
- package/src/lib/expression/functions.d.ts +35 -0
- package/src/lib/expression/functions.js +129 -0
- package/src/lib/expression/functions.js.map +1 -0
- package/src/lib/expression/functions.mjs +124 -0
- package/src/lib/expression/functions.mjs.map +1 -0
- package/src/lib/expression/modifier.d.mts +3 -1
- package/src/lib/expression/modifier.d.ts +3 -1
- package/src/lib/expression/modifier.js +4 -27
- package/src/lib/expression/modifier.js.map +1 -1
- package/src/lib/expression/modifier.mjs +3 -26
- package/src/lib/expression/modifier.mjs.map +1 -1
- package/src/lib/expression/operations.d.mts +25 -0
- package/src/lib/expression/operations.d.ts +25 -0
- package/src/lib/expression/operations.js +81 -0
- package/src/lib/expression/operations.js.map +1 -0
- package/src/lib/expression/operations.mjs +72 -0
- package/src/lib/expression/operations.mjs.map +1 -0
- package/src/lib/expression/order.d.mts +11 -0
- package/src/lib/expression/order.d.ts +11 -0
- package/src/lib/expression/order.js +36 -0
- package/src/lib/expression/order.js.map +1 -0
- package/src/lib/expression/order.mjs +33 -0
- package/src/lib/expression/order.mjs.map +1 -0
- package/src/lib/expression/parser.d.mts +34 -4
- package/src/lib/expression/parser.d.ts +34 -4
- package/src/lib/expression/parser.js +72 -6
- package/src/lib/expression/parser.js.map +1 -1
- package/src/lib/expression/parser.mjs +72 -6
- package/src/lib/expression/parser.mjs.map +1 -1
- package/src/lib/expression/reads.d.mts +8 -0
- package/src/lib/expression/reads.d.ts +8 -0
- package/src/lib/expression/reads.js +48 -0
- package/src/lib/expression/reads.js.map +1 -0
- package/src/lib/expression/reads.mjs +44 -0
- package/src/lib/expression/reads.mjs.map +1 -0
- package/src/lib/expression/tokenizer.d.mts +7 -6
- package/src/lib/expression/tokenizer.d.ts +7 -6
- package/src/lib/expression/tokenizer.js +28 -18
- package/src/lib/expression/tokenizer.js.map +1 -1
- package/src/lib/expression/tokenizer.mjs +28 -18
- package/src/lib/expression/tokenizer.mjs.map +1 -1
- package/src/lib/format/field.d.mts +686 -5
- package/src/lib/format/field.d.ts +686 -5
- package/src/lib/format/field.js +115 -13
- package/src/lib/format/field.js.map +1 -1
- package/src/lib/format/field.mjs +114 -12
- package/src/lib/format/field.mjs.map +1 -1
- package/src/lib/format/layout.d.mts +388 -10
- package/src/lib/format/layout.d.ts +388 -10
- package/src/lib/format/layout.js +50 -3
- package/src/lib/format/layout.js.map +1 -1
- package/src/lib/format/layout.mjs +49 -2
- package/src/lib/format/layout.mjs.map +1 -1
- package/src/lib/format/names.d.mts +1 -1
- package/src/lib/format/names.d.ts +1 -1
- package/src/lib/format/names.js +1 -0
- package/src/lib/format/names.js.map +1 -1
- package/src/lib/format/names.mjs +1 -0
- package/src/lib/format/names.mjs.map +1 -1
- package/src/lib/format/page.d.mts +391 -4
- package/src/lib/format/page.d.ts +391 -4
- package/src/lib/format/page.js +13 -0
- package/src/lib/format/page.js.map +1 -1
- package/src/lib/format/page.mjs +13 -0
- package/src/lib/format/page.mjs.map +1 -1
- package/src/lib/format/references.d.mts +14 -1
- package/src/lib/format/references.d.ts +14 -1
- package/src/lib/format/references.js +96 -8
- package/src/lib/format/references.js.map +1 -1
- package/src/lib/format/references.mjs +96 -8
- package/src/lib/format/references.mjs.map +1 -1
- package/src/lib/format/translate.d.mts +20 -0
- package/src/lib/format/translate.d.ts +20 -0
- package/src/lib/format/translate.js +79 -21
- package/src/lib/format/translate.js.map +1 -1
- package/src/lib/format/translate.mjs +76 -21
- package/src/lib/format/translate.mjs.map +1 -1
- package/src/lib/record/check.d.mts +19 -1
- package/src/lib/record/check.d.ts +19 -1
- package/src/lib/record/check.js +84 -21
- package/src/lib/record/check.js.map +1 -1
- package/src/lib/record/check.mjs +82 -21
- package/src/lib/record/check.mjs.map +1 -1
- package/src/lib/record/compute.d.mts +24 -0
- package/src/lib/record/compute.d.ts +24 -0
- package/src/lib/record/compute.js +107 -0
- package/src/lib/record/compute.js.map +1 -0
- package/src/lib/record/compute.mjs +103 -0
- package/src/lib/record/compute.mjs.map +1 -0
- package/src/lib/record/data-source.d.mts +9 -1
- package/src/lib/record/data-source.d.ts +9 -1
- package/src/lib/record/data-source.js.map +1 -1
- package/src/lib/record/data-source.mjs.map +1 -1
- package/src/lib/record/env.d.mts +9 -0
- package/src/lib/record/env.d.ts +9 -0
- package/src/lib/record/env.js +28 -0
- package/src/lib/record/env.js.map +1 -0
- package/src/lib/record/env.mjs +25 -0
- package/src/lib/record/env.mjs.map +1 -0
- package/src/lib/record/form.d.mts +24 -0
- package/src/lib/record/form.d.ts +24 -0
- package/src/lib/record/form.js +160 -32
- package/src/lib/record/form.js.map +1 -1
- package/src/lib/record/form.mjs +160 -32
- package/src/lib/record/form.mjs.map +1 -1
- package/src/lib/record/inputs.d.mts +5 -0
- package/src/lib/record/inputs.d.ts +5 -0
- package/src/lib/record/inputs.js +47 -0
- package/src/lib/record/inputs.js.map +1 -0
- package/src/lib/record/inputs.mjs +44 -0
- package/src/lib/record/inputs.mjs.map +1 -0
- package/src/lib/record/limits.d.mts +13 -0
- package/src/lib/record/limits.d.ts +13 -0
- package/src/lib/record/limits.js +45 -0
- package/src/lib/record/limits.js.map +1 -0
- package/src/lib/record/limits.mjs +41 -0
- package/src/lib/record/limits.mjs.map +1 -0
- package/src/lib/record/locales/all.d.mts +7 -0
- package/src/lib/record/locales/all.d.ts +7 -0
- package/src/lib/record/locales/all.js +13 -0
- package/src/lib/record/locales/all.js.map +1 -0
- package/src/lib/record/locales/all.mjs +10 -0
- package/src/lib/record/locales/all.mjs.map +1 -0
- package/src/lib/record/locales/ar.d.mts +3 -0
- package/src/lib/record/locales/ar.d.ts +3 -0
- package/src/lib/record/locales/ar.js +55 -0
- package/src/lib/record/locales/ar.js.map +1 -0
- package/src/lib/record/locales/ar.mjs +52 -0
- package/src/lib/record/locales/ar.mjs.map +1 -0
- package/src/lib/record/locales/de.d.mts +3 -0
- package/src/lib/record/locales/de.d.ts +3 -0
- package/src/lib/record/locales/de.js +55 -0
- package/src/lib/record/locales/de.js.map +1 -0
- package/src/lib/record/locales/de.mjs +52 -0
- package/src/lib/record/locales/de.mjs.map +1 -0
- package/src/lib/record/locales/fr.d.mts +3 -0
- package/src/lib/record/locales/fr.d.ts +3 -0
- package/src/lib/record/locales/fr.js +55 -0
- package/src/lib/record/locales/fr.js.map +1 -0
- package/src/lib/record/locales/fr.mjs +52 -0
- package/src/lib/record/locales/fr.mjs.map +1 -0
- package/src/lib/record/memory-data-source.d.mts +3 -0
- package/src/lib/record/memory-data-source.d.ts +3 -0
- package/src/lib/record/memory-data-source.js +8 -0
- package/src/lib/record/memory-data-source.js.map +1 -1
- package/src/lib/record/memory-data-source.mjs +8 -0
- package/src/lib/record/memory-data-source.mjs.map +1 -1
- package/src/lib/record/messages.d.mts +46 -0
- package/src/lib/record/messages.d.ts +46 -0
- package/src/lib/record/messages.js +58 -101
- package/src/lib/record/messages.js.map +1 -1
- package/src/lib/record/messages.mjs +58 -101
- package/src/lib/record/messages.mjs.map +1 -1
- package/src/lib/record/rules.d.mts +33 -0
- package/src/lib/record/rules.d.ts +33 -0
- package/src/lib/record/rules.js +83 -0
- package/src/lib/record/rules.js.map +1 -0
- package/src/lib/record/rules.mjs +79 -0
- package/src/lib/record/rules.mjs.map +1 -0
- package/src/lib/record/score.d.mts +16 -0
- package/src/lib/record/score.d.ts +16 -0
- package/src/lib/record/score.js +35 -0
- package/src/lib/record/score.js.map +1 -0
- package/src/lib/record/score.mjs +32 -0
- package/src/lib/record/score.mjs.map +1 -0
- package/src/lib/record/set-when.d.mts +24 -0
- package/src/lib/record/set-when.d.ts +24 -0
- package/src/lib/record/set-when.js +68 -0
- package/src/lib/record/set-when.js.map +1 -0
- package/src/lib/record/set-when.mjs +65 -0
- package/src/lib/record/set-when.mjs.map +1 -0
- package/src/lib/record/structures.d.mts +14 -0
- package/src/lib/record/structures.d.ts +14 -0
- package/src/lib/record/structures.js +32 -0
- package/src/lib/record/structures.js.map +1 -0
- package/src/lib/record/structures.mjs +28 -0
- package/src/lib/record/structures.mjs.map +1 -0
- package/src/lib/record/values.d.mts +10 -5
- package/src/lib/record/values.d.ts +10 -5
- package/src/lib/record/values.js +20 -6
- package/src/lib/record/values.js.map +1 -1
- package/src/lib/record/values.mjs +19 -6
- package/src/lib/record/values.mjs.map +1 -1
- package/src/runtime.d.mts +10 -7
- package/src/runtime.d.ts +10 -7
- package/src/runtime.js +12 -1
- package/src/runtime.js.map +1 -1
- package/src/runtime.mjs +5 -2
- package/src/runtime.mjs.map +1 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The order to work fields out in: each after the fields it reads. `reads`
|
|
3
|
+
* maps each worked-out field to the fields its expression reads; names not in
|
|
4
|
+
* the map are plain values and need no order. A circle — a field read, at
|
|
5
|
+
* some remove, by itself — has no order: it is listed among the cycles, as
|
|
6
|
+
* the fields around it (`a → b → a`), and its fields still come out once each.
|
|
7
|
+
*/
|
|
8
|
+
export declare function dependencyOrder(reads: ReadonlyMap<string, readonly string[]>): {
|
|
9
|
+
order: string[];
|
|
10
|
+
cycles: string[][];
|
|
11
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.dependencyOrder = dependencyOrder;
|
|
4
|
+
/**
|
|
5
|
+
* The order to work fields out in: each after the fields it reads. `reads`
|
|
6
|
+
* maps each worked-out field to the fields its expression reads; names not in
|
|
7
|
+
* the map are plain values and need no order. A circle — a field read, at
|
|
8
|
+
* some remove, by itself — has no order: it is listed among the cycles, as
|
|
9
|
+
* the fields around it (`a → b → a`), and its fields still come out once each.
|
|
10
|
+
*/
|
|
11
|
+
function dependencyOrder(reads) {
|
|
12
|
+
const order = [];
|
|
13
|
+
const cycles = [];
|
|
14
|
+
const done = new Set();
|
|
15
|
+
const path = [];
|
|
16
|
+
const visit = (name) => {
|
|
17
|
+
if (done.has(name))
|
|
18
|
+
return;
|
|
19
|
+
const at = path.indexOf(name);
|
|
20
|
+
if (at !== -1) {
|
|
21
|
+
cycles.push([...path.slice(at), name]);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
path.push(name);
|
|
25
|
+
for (const read of reads.get(name) ?? [])
|
|
26
|
+
if (reads.has(read))
|
|
27
|
+
visit(read);
|
|
28
|
+
path.pop();
|
|
29
|
+
done.add(name);
|
|
30
|
+
order.push(name);
|
|
31
|
+
};
|
|
32
|
+
for (const name of reads.keys())
|
|
33
|
+
visit(name);
|
|
34
|
+
return { order, cycles };
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=order.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"order.js","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/order.ts"],"names":[],"mappings":";;AAOA,0CAoBC;AA3BD;;;;;;GAMG;AACH,SAAgB,eAAe,CAAC,KAA6C;IAC3E,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAe,EAAE,CAAC;IAC9B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,MAAM,KAAK,GAAG,CAAC,IAAY,EAAQ,EAAE;QACnC,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO;QAC3B,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC;YACd,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;YACvC,OAAO;QACT,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChB,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3E,IAAI,CAAC,GAAG,EAAE,CAAC;QACX,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE;QAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The order to work fields out in: each after the fields it reads. `reads`
|
|
3
|
+
* maps each worked-out field to the fields its expression reads; names not in
|
|
4
|
+
* the map are plain values and need no order. A circle — a field read, at
|
|
5
|
+
* some remove, by itself — has no order: it is listed among the cycles, as
|
|
6
|
+
* the fields around it (`a → b → a`), and its fields still come out once each.
|
|
7
|
+
*/
|
|
8
|
+
export function dependencyOrder(reads) {
|
|
9
|
+
const order = [];
|
|
10
|
+
const cycles = [];
|
|
11
|
+
const done = new Set();
|
|
12
|
+
const path = [];
|
|
13
|
+
const visit = (name) => {
|
|
14
|
+
if (done.has(name))
|
|
15
|
+
return;
|
|
16
|
+
const at = path.indexOf(name);
|
|
17
|
+
if (at !== -1) {
|
|
18
|
+
cycles.push([...path.slice(at), name]);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
path.push(name);
|
|
22
|
+
for (const read of reads.get(name) ?? [])
|
|
23
|
+
if (reads.has(read))
|
|
24
|
+
visit(read);
|
|
25
|
+
path.pop();
|
|
26
|
+
done.add(name);
|
|
27
|
+
order.push(name);
|
|
28
|
+
};
|
|
29
|
+
for (const name of reads.keys())
|
|
30
|
+
visit(name);
|
|
31
|
+
return { order, cycles };
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=order.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"order.mjs","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/order.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,KAA6C;IAC3E,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAe,EAAE,CAAC;IAC9B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,MAAM,KAAK,GAAG,CAAC,IAAY,EAAQ,EAAE;QACnC,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO;QAC3B,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC;YACd,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;YACvC,OAAO;QACT,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChB,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3E,IAAI,CAAC,GAAG,EAAE,CAAC;QACX,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE;QAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAC3B,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Expression parser
|
|
2
|
+
* Expression parser, ported from the React form engine and grown arithmetic
|
|
3
|
+
* and functions.
|
|
3
4
|
*
|
|
4
5
|
* Recursive descent parser that converts tokens into an Abstract Syntax Tree (AST).
|
|
5
6
|
* Implements Python-like operator precedence:
|
|
@@ -7,13 +8,16 @@
|
|
|
7
8
|
* 2. AND
|
|
8
9
|
* 3. NOT
|
|
9
10
|
* 4. Comparison operators (==, !=, <, >, <=, >=, in, not in)
|
|
10
|
-
* 5.
|
|
11
|
+
* 5. + and -
|
|
12
|
+
* 6. *, / and %
|
|
13
|
+
* 7. A minus sign before a value
|
|
14
|
+
* 8. Values, identifiers and function calls (highest precedence)
|
|
11
15
|
*/
|
|
12
16
|
import { type Token } from './tokenizer.mjs';
|
|
13
17
|
/**
|
|
14
18
|
* AST Node Types
|
|
15
19
|
*/
|
|
16
|
-
export type ASTNode = BinaryOpNode | UnaryOpNode | LiteralNode | IdentifierNode;
|
|
20
|
+
export type ASTNode = BinaryOpNode | UnaryOpNode | LiteralNode | IdentifierNode | CallNode;
|
|
17
21
|
export interface BinaryOpNode {
|
|
18
22
|
type: 'BinaryOp';
|
|
19
23
|
operator: string;
|
|
@@ -33,6 +37,12 @@ export interface IdentifierNode {
|
|
|
33
37
|
type: 'Identifier';
|
|
34
38
|
name: string;
|
|
35
39
|
}
|
|
40
|
+
/** A function called with its values: `round(price * qty, 2)`. */
|
|
41
|
+
export interface CallNode {
|
|
42
|
+
type: 'Call';
|
|
43
|
+
name: string;
|
|
44
|
+
args: ASTNode[];
|
|
45
|
+
}
|
|
36
46
|
/**
|
|
37
47
|
* Recursive Descent Expression Parser
|
|
38
48
|
*/
|
|
@@ -65,9 +75,29 @@ export declare class ExpressionParser {
|
|
|
65
75
|
* comp_op: '==' | '!=' | '<>' | '<' | '>' | '<=' | '>=' | 'in' | 'not in'
|
|
66
76
|
*/
|
|
67
77
|
private parseComparison;
|
|
78
|
+
/**
|
|
79
|
+
* Adding and taking away, left to right
|
|
80
|
+
* sum: product (('+' | '-') product)*
|
|
81
|
+
*/
|
|
82
|
+
private parseSum;
|
|
83
|
+
/**
|
|
84
|
+
* Multiplying, dividing and the remainder, left to right
|
|
85
|
+
* product: unary (('*' | '/' | '%') unary)*
|
|
86
|
+
*/
|
|
87
|
+
private parseProduct;
|
|
88
|
+
/**
|
|
89
|
+
* A minus sign before a value: -5, -price, -(a + b)
|
|
90
|
+
* unary: '-' unary | value
|
|
91
|
+
*/
|
|
92
|
+
private parseUnary;
|
|
93
|
+
/**
|
|
94
|
+
* A function's name, then its values in parentheses, separated by commas.
|
|
95
|
+
* call: name '(' (or_expr (',' or_expr)*)? ')'
|
|
96
|
+
*/
|
|
97
|
+
private parseCall;
|
|
68
98
|
/**
|
|
69
99
|
* Parse value expressions (highest precedence)
|
|
70
|
-
* value: '(' or_expr ')' | literal | identifier
|
|
100
|
+
* value: '(' or_expr ')' | literal | call | identifier
|
|
71
101
|
*/
|
|
72
102
|
private parseValue;
|
|
73
103
|
/**
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Expression parser
|
|
2
|
+
* Expression parser, ported from the React form engine and grown arithmetic
|
|
3
|
+
* and functions.
|
|
3
4
|
*
|
|
4
5
|
* Recursive descent parser that converts tokens into an Abstract Syntax Tree (AST).
|
|
5
6
|
* Implements Python-like operator precedence:
|
|
@@ -7,13 +8,16 @@
|
|
|
7
8
|
* 2. AND
|
|
8
9
|
* 3. NOT
|
|
9
10
|
* 4. Comparison operators (==, !=, <, >, <=, >=, in, not in)
|
|
10
|
-
* 5.
|
|
11
|
+
* 5. + and -
|
|
12
|
+
* 6. *, / and %
|
|
13
|
+
* 7. A minus sign before a value
|
|
14
|
+
* 8. Values, identifiers and function calls (highest precedence)
|
|
11
15
|
*/
|
|
12
16
|
import { type Token } from './tokenizer';
|
|
13
17
|
/**
|
|
14
18
|
* AST Node Types
|
|
15
19
|
*/
|
|
16
|
-
export type ASTNode = BinaryOpNode | UnaryOpNode | LiteralNode | IdentifierNode;
|
|
20
|
+
export type ASTNode = BinaryOpNode | UnaryOpNode | LiteralNode | IdentifierNode | CallNode;
|
|
17
21
|
export interface BinaryOpNode {
|
|
18
22
|
type: 'BinaryOp';
|
|
19
23
|
operator: string;
|
|
@@ -33,6 +37,12 @@ export interface IdentifierNode {
|
|
|
33
37
|
type: 'Identifier';
|
|
34
38
|
name: string;
|
|
35
39
|
}
|
|
40
|
+
/** A function called with its values: `round(price * qty, 2)`. */
|
|
41
|
+
export interface CallNode {
|
|
42
|
+
type: 'Call';
|
|
43
|
+
name: string;
|
|
44
|
+
args: ASTNode[];
|
|
45
|
+
}
|
|
36
46
|
/**
|
|
37
47
|
* Recursive Descent Expression Parser
|
|
38
48
|
*/
|
|
@@ -65,9 +75,29 @@ export declare class ExpressionParser {
|
|
|
65
75
|
* comp_op: '==' | '!=' | '<>' | '<' | '>' | '<=' | '>=' | 'in' | 'not in'
|
|
66
76
|
*/
|
|
67
77
|
private parseComparison;
|
|
78
|
+
/**
|
|
79
|
+
* Adding and taking away, left to right
|
|
80
|
+
* sum: product (('+' | '-') product)*
|
|
81
|
+
*/
|
|
82
|
+
private parseSum;
|
|
83
|
+
/**
|
|
84
|
+
* Multiplying, dividing and the remainder, left to right
|
|
85
|
+
* product: unary (('*' | '/' | '%') unary)*
|
|
86
|
+
*/
|
|
87
|
+
private parseProduct;
|
|
88
|
+
/**
|
|
89
|
+
* A minus sign before a value: -5, -price, -(a + b)
|
|
90
|
+
* unary: '-' unary | value
|
|
91
|
+
*/
|
|
92
|
+
private parseUnary;
|
|
93
|
+
/**
|
|
94
|
+
* A function's name, then its values in parentheses, separated by commas.
|
|
95
|
+
* call: name '(' (or_expr (',' or_expr)*)? ')'
|
|
96
|
+
*/
|
|
97
|
+
private parseCall;
|
|
68
98
|
/**
|
|
69
99
|
* Parse value expressions (highest precedence)
|
|
70
|
-
* value: '(' or_expr ')' | literal | identifier
|
|
100
|
+
* value: '(' or_expr ')' | literal | call | identifier
|
|
71
101
|
*/
|
|
72
102
|
private parseValue;
|
|
73
103
|
/**
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* Expression parser
|
|
3
|
+
* Expression parser, ported from the React form engine and grown arithmetic
|
|
4
|
+
* and functions.
|
|
4
5
|
*
|
|
5
6
|
* Recursive descent parser that converts tokens into an Abstract Syntax Tree (AST).
|
|
6
7
|
* Implements Python-like operator precedence:
|
|
@@ -8,11 +9,15 @@
|
|
|
8
9
|
* 2. AND
|
|
9
10
|
* 3. NOT
|
|
10
11
|
* 4. Comparison operators (==, !=, <, >, <=, >=, in, not in)
|
|
11
|
-
* 5.
|
|
12
|
+
* 5. + and -
|
|
13
|
+
* 6. *, / and %
|
|
14
|
+
* 7. A minus sign before a value
|
|
15
|
+
* 8. Values, identifiers and function calls (highest precedence)
|
|
12
16
|
*/
|
|
13
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
18
|
exports.ExpressionParser = void 0;
|
|
15
19
|
const tokenizer_1 = require("./tokenizer");
|
|
20
|
+
const functions_1 = require("./functions");
|
|
16
21
|
/**
|
|
17
22
|
* Recursive Descent Expression Parser
|
|
18
23
|
*/
|
|
@@ -94,11 +99,11 @@ class ExpressionParser {
|
|
|
94
99
|
* comp_op: '==' | '!=' | '<>' | '<' | '>' | '<=' | '>=' | 'in' | 'not in'
|
|
95
100
|
*/
|
|
96
101
|
parseComparison() {
|
|
97
|
-
const left = this.
|
|
102
|
+
const left = this.parseSum();
|
|
98
103
|
const compOperators = ['==', '!=', '<>', '<', '>', '<=', '>=', 'in', 'not in'];
|
|
99
104
|
if (this.matchOperator(...compOperators)) {
|
|
100
105
|
const operator = this.previous().value;
|
|
101
|
-
const right = this.
|
|
106
|
+
const right = this.parseSum();
|
|
102
107
|
return {
|
|
103
108
|
type: 'BinaryOp',
|
|
104
109
|
operator: operator.toLowerCase(),
|
|
@@ -109,9 +114,67 @@ class ExpressionParser {
|
|
|
109
114
|
// If no comparison operator, return value as-is (truthiness check)
|
|
110
115
|
return left;
|
|
111
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Adding and taking away, left to right
|
|
119
|
+
* sum: product (('+' | '-') product)*
|
|
120
|
+
*/
|
|
121
|
+
parseSum() {
|
|
122
|
+
let left = this.parseProduct();
|
|
123
|
+
while (this.match('ARITHMETIC', '+', '-')) {
|
|
124
|
+
const operator = this.previous().value;
|
|
125
|
+
left = { type: 'BinaryOp', operator, left, right: this.parseProduct() };
|
|
126
|
+
}
|
|
127
|
+
return left;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Multiplying, dividing and the remainder, left to right
|
|
131
|
+
* product: unary (('*' | '/' | '%') unary)*
|
|
132
|
+
*/
|
|
133
|
+
parseProduct() {
|
|
134
|
+
let left = this.parseUnary();
|
|
135
|
+
while (this.match('ARITHMETIC', '*', '/', '%')) {
|
|
136
|
+
const operator = this.previous().value;
|
|
137
|
+
left = { type: 'BinaryOp', operator, left, right: this.parseUnary() };
|
|
138
|
+
}
|
|
139
|
+
return left;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* A minus sign before a value: -5, -price, -(a + b)
|
|
143
|
+
* unary: '-' unary | value
|
|
144
|
+
*/
|
|
145
|
+
parseUnary() {
|
|
146
|
+
if (this.match('ARITHMETIC', '-')) {
|
|
147
|
+
return { type: 'UnaryOp', operator: '-', operand: this.parseUnary() };
|
|
148
|
+
}
|
|
149
|
+
return this.parseValue();
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* A function's name, then its values in parentheses, separated by commas.
|
|
153
|
+
* call: name '(' (or_expr (',' or_expr)*)? ')'
|
|
154
|
+
*/
|
|
155
|
+
parseCall(name) {
|
|
156
|
+
const fn = functions_1.FUNCTIONS.get(name);
|
|
157
|
+
if (!fn)
|
|
158
|
+
throw new Error(`no function "${name}": the functions are ${[...functions_1.FUNCTIONS.keys()].join(', ')}`);
|
|
159
|
+
this.advance(); // (
|
|
160
|
+
const args = [];
|
|
161
|
+
if (!this.match('PAREN', ')')) {
|
|
162
|
+
do {
|
|
163
|
+
args.push(this.parseOr());
|
|
164
|
+
} while (this.match('COMMA'));
|
|
165
|
+
this.consume('PAREN', ')', `Expected "," or ")" after a value of ${name}(…)`);
|
|
166
|
+
}
|
|
167
|
+
const [least, most] = fn.takes;
|
|
168
|
+
if (args.length < least || args.length > most)
|
|
169
|
+
throw new Error((0, functions_1.takesInWords)(name, fn.takes));
|
|
170
|
+
const problem = fn.check?.(args);
|
|
171
|
+
if (problem)
|
|
172
|
+
throw new Error(problem);
|
|
173
|
+
return { type: 'Call', name, args };
|
|
174
|
+
}
|
|
112
175
|
/**
|
|
113
176
|
* Parse value expressions (highest precedence)
|
|
114
|
-
* value: '(' or_expr ')' | literal | identifier
|
|
177
|
+
* value: '(' or_expr ')' | literal | call | identifier
|
|
115
178
|
*/
|
|
116
179
|
parseValue() {
|
|
117
180
|
// Parenthesized expression
|
|
@@ -143,9 +206,12 @@ class ExpressionParser {
|
|
|
143
206
|
const value = parseListLiteral(token.value);
|
|
144
207
|
return { type: 'Literal', value };
|
|
145
208
|
}
|
|
146
|
-
//
|
|
209
|
+
// A function call, or an identifier
|
|
147
210
|
if (this.check('IDENTIFIER')) {
|
|
148
211
|
const token = this.advance();
|
|
212
|
+
const next = this.peek();
|
|
213
|
+
if (next?.type === 'PAREN' && next.value === '(')
|
|
214
|
+
return this.parseCall(token.value);
|
|
149
215
|
return { type: 'Identifier', name: token.value };
|
|
150
216
|
}
|
|
151
217
|
throw new Error(`Unexpected token: ${this.peek()?.value || 'EOF'}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/parser.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Expression parser
|
|
2
|
+
* Expression parser, ported from the React form engine and grown arithmetic
|
|
3
|
+
* and functions.
|
|
3
4
|
*
|
|
4
5
|
* Recursive descent parser that converts tokens into an Abstract Syntax Tree (AST).
|
|
5
6
|
* Implements Python-like operator precedence:
|
|
@@ -7,9 +8,13 @@
|
|
|
7
8
|
* 2. AND
|
|
8
9
|
* 3. NOT
|
|
9
10
|
* 4. Comparison operators (==, !=, <, >, <=, >=, in, not in)
|
|
10
|
-
* 5.
|
|
11
|
+
* 5. + and -
|
|
12
|
+
* 6. *, / and %
|
|
13
|
+
* 7. A minus sign before a value
|
|
14
|
+
* 8. Values, identifiers and function calls (highest precedence)
|
|
11
15
|
*/
|
|
12
16
|
import { CONSTANTS } from './tokenizer.mjs';
|
|
17
|
+
import { FUNCTIONS, takesInWords } from './functions.mjs';
|
|
13
18
|
/**
|
|
14
19
|
* Recursive Descent Expression Parser
|
|
15
20
|
*/
|
|
@@ -91,11 +96,11 @@ export class ExpressionParser {
|
|
|
91
96
|
* comp_op: '==' | '!=' | '<>' | '<' | '>' | '<=' | '>=' | 'in' | 'not in'
|
|
92
97
|
*/
|
|
93
98
|
parseComparison() {
|
|
94
|
-
const left = this.
|
|
99
|
+
const left = this.parseSum();
|
|
95
100
|
const compOperators = ['==', '!=', '<>', '<', '>', '<=', '>=', 'in', 'not in'];
|
|
96
101
|
if (this.matchOperator(...compOperators)) {
|
|
97
102
|
const operator = this.previous().value;
|
|
98
|
-
const right = this.
|
|
103
|
+
const right = this.parseSum();
|
|
99
104
|
return {
|
|
100
105
|
type: 'BinaryOp',
|
|
101
106
|
operator: operator.toLowerCase(),
|
|
@@ -106,9 +111,67 @@ export class ExpressionParser {
|
|
|
106
111
|
// If no comparison operator, return value as-is (truthiness check)
|
|
107
112
|
return left;
|
|
108
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Adding and taking away, left to right
|
|
116
|
+
* sum: product (('+' | '-') product)*
|
|
117
|
+
*/
|
|
118
|
+
parseSum() {
|
|
119
|
+
let left = this.parseProduct();
|
|
120
|
+
while (this.match('ARITHMETIC', '+', '-')) {
|
|
121
|
+
const operator = this.previous().value;
|
|
122
|
+
left = { type: 'BinaryOp', operator, left, right: this.parseProduct() };
|
|
123
|
+
}
|
|
124
|
+
return left;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Multiplying, dividing and the remainder, left to right
|
|
128
|
+
* product: unary (('*' | '/' | '%') unary)*
|
|
129
|
+
*/
|
|
130
|
+
parseProduct() {
|
|
131
|
+
let left = this.parseUnary();
|
|
132
|
+
while (this.match('ARITHMETIC', '*', '/', '%')) {
|
|
133
|
+
const operator = this.previous().value;
|
|
134
|
+
left = { type: 'BinaryOp', operator, left, right: this.parseUnary() };
|
|
135
|
+
}
|
|
136
|
+
return left;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* A minus sign before a value: -5, -price, -(a + b)
|
|
140
|
+
* unary: '-' unary | value
|
|
141
|
+
*/
|
|
142
|
+
parseUnary() {
|
|
143
|
+
if (this.match('ARITHMETIC', '-')) {
|
|
144
|
+
return { type: 'UnaryOp', operator: '-', operand: this.parseUnary() };
|
|
145
|
+
}
|
|
146
|
+
return this.parseValue();
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* A function's name, then its values in parentheses, separated by commas.
|
|
150
|
+
* call: name '(' (or_expr (',' or_expr)*)? ')'
|
|
151
|
+
*/
|
|
152
|
+
parseCall(name) {
|
|
153
|
+
const fn = FUNCTIONS.get(name);
|
|
154
|
+
if (!fn)
|
|
155
|
+
throw new Error(`no function "${name}": the functions are ${[...FUNCTIONS.keys()].join(', ')}`);
|
|
156
|
+
this.advance(); // (
|
|
157
|
+
const args = [];
|
|
158
|
+
if (!this.match('PAREN', ')')) {
|
|
159
|
+
do {
|
|
160
|
+
args.push(this.parseOr());
|
|
161
|
+
} while (this.match('COMMA'));
|
|
162
|
+
this.consume('PAREN', ')', `Expected "," or ")" after a value of ${name}(…)`);
|
|
163
|
+
}
|
|
164
|
+
const [least, most] = fn.takes;
|
|
165
|
+
if (args.length < least || args.length > most)
|
|
166
|
+
throw new Error(takesInWords(name, fn.takes));
|
|
167
|
+
const problem = fn.check?.(args);
|
|
168
|
+
if (problem)
|
|
169
|
+
throw new Error(problem);
|
|
170
|
+
return { type: 'Call', name, args };
|
|
171
|
+
}
|
|
109
172
|
/**
|
|
110
173
|
* Parse value expressions (highest precedence)
|
|
111
|
-
* value: '(' or_expr ')' | literal | identifier
|
|
174
|
+
* value: '(' or_expr ')' | literal | call | identifier
|
|
112
175
|
*/
|
|
113
176
|
parseValue() {
|
|
114
177
|
// Parenthesized expression
|
|
@@ -140,9 +203,12 @@ export class ExpressionParser {
|
|
|
140
203
|
const value = parseListLiteral(token.value);
|
|
141
204
|
return { type: 'Literal', value };
|
|
142
205
|
}
|
|
143
|
-
//
|
|
206
|
+
// A function call, or an identifier
|
|
144
207
|
if (this.check('IDENTIFIER')) {
|
|
145
208
|
const token = this.advance();
|
|
209
|
+
const next = this.peek();
|
|
210
|
+
if (next?.type === 'PAREN' && next.value === '(')
|
|
211
|
+
return this.parseCall(token.value);
|
|
146
212
|
return { type: 'Identifier', name: token.value };
|
|
147
213
|
}
|
|
148
214
|
throw new Error(`Unexpected token: ${this.peek()?.value || 'EOF'}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.mjs","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/parser.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"parser.mjs","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ASTNode } from './parser.mjs';
|
|
2
|
+
/** The fields an expression reads, by their first name, once each, in order of appearance. Functions are not fields. */
|
|
3
|
+
export declare function fieldsRead(ast: ASTNode): string[];
|
|
4
|
+
/** The line fields an expression adds up, as `sum(lines, 'subtotal')` names them. */
|
|
5
|
+
export declare function sumsRead(ast: ASTNode): {
|
|
6
|
+
lines: string;
|
|
7
|
+
field: string;
|
|
8
|
+
}[];
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ASTNode } from './parser';
|
|
2
|
+
/** The fields an expression reads, by their first name, once each, in order of appearance. Functions are not fields. */
|
|
3
|
+
export declare function fieldsRead(ast: ASTNode): string[];
|
|
4
|
+
/** The line fields an expression adds up, as `sum(lines, 'subtotal')` names them. */
|
|
5
|
+
export declare function sumsRead(ast: ASTNode): {
|
|
6
|
+
lines: string;
|
|
7
|
+
field: string;
|
|
8
|
+
}[];
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fieldsRead = fieldsRead;
|
|
4
|
+
exports.sumsRead = sumsRead;
|
|
5
|
+
/** Every node of an expression, each visited once, the outer before the inner. */
|
|
6
|
+
function walk(ast, visit) {
|
|
7
|
+
visit(ast);
|
|
8
|
+
switch (ast.type) {
|
|
9
|
+
case 'BinaryOp':
|
|
10
|
+
walk(ast.left, visit);
|
|
11
|
+
walk(ast.right, visit);
|
|
12
|
+
return;
|
|
13
|
+
case 'UnaryOp':
|
|
14
|
+
walk(ast.operand, visit);
|
|
15
|
+
return;
|
|
16
|
+
case 'Call':
|
|
17
|
+
for (const arg of ast.args)
|
|
18
|
+
walk(arg, visit);
|
|
19
|
+
return;
|
|
20
|
+
default:
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/** The fields an expression reads, by their first name, once each, in order of appearance. Functions are not fields. */
|
|
25
|
+
function fieldsRead(ast) {
|
|
26
|
+
const names = [];
|
|
27
|
+
walk(ast, (node) => {
|
|
28
|
+
if (node.type !== 'Identifier')
|
|
29
|
+
return;
|
|
30
|
+
const root = node.name.split('.')[0];
|
|
31
|
+
if (!names.includes(root))
|
|
32
|
+
names.push(root);
|
|
33
|
+
});
|
|
34
|
+
return names;
|
|
35
|
+
}
|
|
36
|
+
/** The line fields an expression adds up, as `sum(lines, 'subtotal')` names them. */
|
|
37
|
+
function sumsRead(ast) {
|
|
38
|
+
const sums = [];
|
|
39
|
+
walk(ast, (node) => {
|
|
40
|
+
if (node.type !== 'Call' || node.name !== 'sum')
|
|
41
|
+
return;
|
|
42
|
+
const [lines, field] = node.args;
|
|
43
|
+
if (lines.type === 'Identifier' && field?.type === 'Literal')
|
|
44
|
+
sums.push({ lines: lines.name, field: field.value });
|
|
45
|
+
});
|
|
46
|
+
return sums;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=reads.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reads.js","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/reads.ts"],"names":[],"mappings":";;AAsBA,gCAQC;AAGD,4BAQC;AAvCD,kFAAkF;AAClF,SAAS,IAAI,CAAC,GAAY,EAAE,KAA8B;IACxD,KAAK,CAAC,GAAG,CAAC,CAAC;IACX,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;QACjB,KAAK,UAAU;YACb,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YACtB,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YACvB,OAAO;QACT,KAAK,SAAS;YACZ,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACzB,OAAO;QACT,KAAK,MAAM;YACT,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI;gBAAE,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAC7C,OAAO;QACT;YACE,OAAO;IACX,CAAC;AACH,CAAC;AAED,wHAAwH;AACxH,SAAgB,UAAU,CAAC,GAAY;IACrC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE;QACjB,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY;YAAE,OAAO;QACvC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACf,CAAC;AAED,qFAAqF;AACrF,SAAgB,QAAQ,CAAC,GAAY;IACnC,MAAM,IAAI,GAAuC,EAAE,CAAC;IACpD,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE;QACjB,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK;YAAE,OAAO;QACxD,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC;QACjC,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,IAAI,KAAK,EAAE,IAAI,KAAK,SAAS;YAAE,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAe,EAAE,CAAC,CAAC;IAC/H,CAAC,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AACd,CAAC"}
|