@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.
Files changed (208) hide show
  1. package/package.json +1 -1
  2. package/schema/page.schema.json +1128 -89
  3. package/src/lib/expression/evaluator.d.mts +6 -5
  4. package/src/lib/expression/evaluator.d.ts +6 -5
  5. package/src/lib/expression/evaluator.js +37 -22
  6. package/src/lib/expression/evaluator.js.map +1 -1
  7. package/src/lib/expression/evaluator.mjs +32 -18
  8. package/src/lib/expression/evaluator.mjs.map +1 -1
  9. package/src/lib/expression/expression.d.mts +21 -0
  10. package/src/lib/expression/expression.d.ts +21 -0
  11. package/src/lib/expression/expression.js +29 -0
  12. package/src/lib/expression/expression.js.map +1 -0
  13. package/src/lib/expression/expression.mjs +26 -0
  14. package/src/lib/expression/expression.mjs.map +1 -0
  15. package/src/lib/expression/extractFieldNames.js +6 -1
  16. package/src/lib/expression/extractFieldNames.js.map +1 -1
  17. package/src/lib/expression/extractFieldNames.mjs +6 -1
  18. package/src/lib/expression/extractFieldNames.mjs.map +1 -1
  19. package/src/lib/expression/functions.d.mts +35 -0
  20. package/src/lib/expression/functions.d.ts +35 -0
  21. package/src/lib/expression/functions.js +129 -0
  22. package/src/lib/expression/functions.js.map +1 -0
  23. package/src/lib/expression/functions.mjs +124 -0
  24. package/src/lib/expression/functions.mjs.map +1 -0
  25. package/src/lib/expression/modifier.d.mts +3 -1
  26. package/src/lib/expression/modifier.d.ts +3 -1
  27. package/src/lib/expression/modifier.js +4 -27
  28. package/src/lib/expression/modifier.js.map +1 -1
  29. package/src/lib/expression/modifier.mjs +3 -26
  30. package/src/lib/expression/modifier.mjs.map +1 -1
  31. package/src/lib/expression/operations.d.mts +25 -0
  32. package/src/lib/expression/operations.d.ts +25 -0
  33. package/src/lib/expression/operations.js +81 -0
  34. package/src/lib/expression/operations.js.map +1 -0
  35. package/src/lib/expression/operations.mjs +72 -0
  36. package/src/lib/expression/operations.mjs.map +1 -0
  37. package/src/lib/expression/order.d.mts +11 -0
  38. package/src/lib/expression/order.d.ts +11 -0
  39. package/src/lib/expression/order.js +36 -0
  40. package/src/lib/expression/order.js.map +1 -0
  41. package/src/lib/expression/order.mjs +33 -0
  42. package/src/lib/expression/order.mjs.map +1 -0
  43. package/src/lib/expression/parser.d.mts +34 -4
  44. package/src/lib/expression/parser.d.ts +34 -4
  45. package/src/lib/expression/parser.js +72 -6
  46. package/src/lib/expression/parser.js.map +1 -1
  47. package/src/lib/expression/parser.mjs +72 -6
  48. package/src/lib/expression/parser.mjs.map +1 -1
  49. package/src/lib/expression/reads.d.mts +8 -0
  50. package/src/lib/expression/reads.d.ts +8 -0
  51. package/src/lib/expression/reads.js +48 -0
  52. package/src/lib/expression/reads.js.map +1 -0
  53. package/src/lib/expression/reads.mjs +44 -0
  54. package/src/lib/expression/reads.mjs.map +1 -0
  55. package/src/lib/expression/tokenizer.d.mts +7 -6
  56. package/src/lib/expression/tokenizer.d.ts +7 -6
  57. package/src/lib/expression/tokenizer.js +28 -18
  58. package/src/lib/expression/tokenizer.js.map +1 -1
  59. package/src/lib/expression/tokenizer.mjs +28 -18
  60. package/src/lib/expression/tokenizer.mjs.map +1 -1
  61. package/src/lib/format/field.d.mts +686 -5
  62. package/src/lib/format/field.d.ts +686 -5
  63. package/src/lib/format/field.js +115 -13
  64. package/src/lib/format/field.js.map +1 -1
  65. package/src/lib/format/field.mjs +114 -12
  66. package/src/lib/format/field.mjs.map +1 -1
  67. package/src/lib/format/layout.d.mts +388 -10
  68. package/src/lib/format/layout.d.ts +388 -10
  69. package/src/lib/format/layout.js +50 -3
  70. package/src/lib/format/layout.js.map +1 -1
  71. package/src/lib/format/layout.mjs +49 -2
  72. package/src/lib/format/layout.mjs.map +1 -1
  73. package/src/lib/format/names.d.mts +1 -1
  74. package/src/lib/format/names.d.ts +1 -1
  75. package/src/lib/format/names.js +1 -0
  76. package/src/lib/format/names.js.map +1 -1
  77. package/src/lib/format/names.mjs +1 -0
  78. package/src/lib/format/names.mjs.map +1 -1
  79. package/src/lib/format/page.d.mts +391 -4
  80. package/src/lib/format/page.d.ts +391 -4
  81. package/src/lib/format/page.js +13 -0
  82. package/src/lib/format/page.js.map +1 -1
  83. package/src/lib/format/page.mjs +13 -0
  84. package/src/lib/format/page.mjs.map +1 -1
  85. package/src/lib/format/references.d.mts +14 -1
  86. package/src/lib/format/references.d.ts +14 -1
  87. package/src/lib/format/references.js +96 -8
  88. package/src/lib/format/references.js.map +1 -1
  89. package/src/lib/format/references.mjs +96 -8
  90. package/src/lib/format/references.mjs.map +1 -1
  91. package/src/lib/format/translate.d.mts +20 -0
  92. package/src/lib/format/translate.d.ts +20 -0
  93. package/src/lib/format/translate.js +79 -21
  94. package/src/lib/format/translate.js.map +1 -1
  95. package/src/lib/format/translate.mjs +76 -21
  96. package/src/lib/format/translate.mjs.map +1 -1
  97. package/src/lib/record/check.d.mts +19 -1
  98. package/src/lib/record/check.d.ts +19 -1
  99. package/src/lib/record/check.js +84 -21
  100. package/src/lib/record/check.js.map +1 -1
  101. package/src/lib/record/check.mjs +82 -21
  102. package/src/lib/record/check.mjs.map +1 -1
  103. package/src/lib/record/compute.d.mts +24 -0
  104. package/src/lib/record/compute.d.ts +24 -0
  105. package/src/lib/record/compute.js +107 -0
  106. package/src/lib/record/compute.js.map +1 -0
  107. package/src/lib/record/compute.mjs +103 -0
  108. package/src/lib/record/compute.mjs.map +1 -0
  109. package/src/lib/record/data-source.d.mts +9 -1
  110. package/src/lib/record/data-source.d.ts +9 -1
  111. package/src/lib/record/data-source.js.map +1 -1
  112. package/src/lib/record/data-source.mjs.map +1 -1
  113. package/src/lib/record/env.d.mts +9 -0
  114. package/src/lib/record/env.d.ts +9 -0
  115. package/src/lib/record/env.js +28 -0
  116. package/src/lib/record/env.js.map +1 -0
  117. package/src/lib/record/env.mjs +25 -0
  118. package/src/lib/record/env.mjs.map +1 -0
  119. package/src/lib/record/form.d.mts +24 -0
  120. package/src/lib/record/form.d.ts +24 -0
  121. package/src/lib/record/form.js +160 -32
  122. package/src/lib/record/form.js.map +1 -1
  123. package/src/lib/record/form.mjs +160 -32
  124. package/src/lib/record/form.mjs.map +1 -1
  125. package/src/lib/record/inputs.d.mts +5 -0
  126. package/src/lib/record/inputs.d.ts +5 -0
  127. package/src/lib/record/inputs.js +47 -0
  128. package/src/lib/record/inputs.js.map +1 -0
  129. package/src/lib/record/inputs.mjs +44 -0
  130. package/src/lib/record/inputs.mjs.map +1 -0
  131. package/src/lib/record/limits.d.mts +13 -0
  132. package/src/lib/record/limits.d.ts +13 -0
  133. package/src/lib/record/limits.js +45 -0
  134. package/src/lib/record/limits.js.map +1 -0
  135. package/src/lib/record/limits.mjs +41 -0
  136. package/src/lib/record/limits.mjs.map +1 -0
  137. package/src/lib/record/locales/all.d.mts +7 -0
  138. package/src/lib/record/locales/all.d.ts +7 -0
  139. package/src/lib/record/locales/all.js +13 -0
  140. package/src/lib/record/locales/all.js.map +1 -0
  141. package/src/lib/record/locales/all.mjs +10 -0
  142. package/src/lib/record/locales/all.mjs.map +1 -0
  143. package/src/lib/record/locales/ar.d.mts +3 -0
  144. package/src/lib/record/locales/ar.d.ts +3 -0
  145. package/src/lib/record/locales/ar.js +55 -0
  146. package/src/lib/record/locales/ar.js.map +1 -0
  147. package/src/lib/record/locales/ar.mjs +52 -0
  148. package/src/lib/record/locales/ar.mjs.map +1 -0
  149. package/src/lib/record/locales/de.d.mts +3 -0
  150. package/src/lib/record/locales/de.d.ts +3 -0
  151. package/src/lib/record/locales/de.js +55 -0
  152. package/src/lib/record/locales/de.js.map +1 -0
  153. package/src/lib/record/locales/de.mjs +52 -0
  154. package/src/lib/record/locales/de.mjs.map +1 -0
  155. package/src/lib/record/locales/fr.d.mts +3 -0
  156. package/src/lib/record/locales/fr.d.ts +3 -0
  157. package/src/lib/record/locales/fr.js +55 -0
  158. package/src/lib/record/locales/fr.js.map +1 -0
  159. package/src/lib/record/locales/fr.mjs +52 -0
  160. package/src/lib/record/locales/fr.mjs.map +1 -0
  161. package/src/lib/record/memory-data-source.d.mts +3 -0
  162. package/src/lib/record/memory-data-source.d.ts +3 -0
  163. package/src/lib/record/memory-data-source.js +8 -0
  164. package/src/lib/record/memory-data-source.js.map +1 -1
  165. package/src/lib/record/memory-data-source.mjs +8 -0
  166. package/src/lib/record/memory-data-source.mjs.map +1 -1
  167. package/src/lib/record/messages.d.mts +46 -0
  168. package/src/lib/record/messages.d.ts +46 -0
  169. package/src/lib/record/messages.js +58 -101
  170. package/src/lib/record/messages.js.map +1 -1
  171. package/src/lib/record/messages.mjs +58 -101
  172. package/src/lib/record/messages.mjs.map +1 -1
  173. package/src/lib/record/rules.d.mts +33 -0
  174. package/src/lib/record/rules.d.ts +33 -0
  175. package/src/lib/record/rules.js +83 -0
  176. package/src/lib/record/rules.js.map +1 -0
  177. package/src/lib/record/rules.mjs +79 -0
  178. package/src/lib/record/rules.mjs.map +1 -0
  179. package/src/lib/record/score.d.mts +16 -0
  180. package/src/lib/record/score.d.ts +16 -0
  181. package/src/lib/record/score.js +35 -0
  182. package/src/lib/record/score.js.map +1 -0
  183. package/src/lib/record/score.mjs +32 -0
  184. package/src/lib/record/score.mjs.map +1 -0
  185. package/src/lib/record/set-when.d.mts +24 -0
  186. package/src/lib/record/set-when.d.ts +24 -0
  187. package/src/lib/record/set-when.js +68 -0
  188. package/src/lib/record/set-when.js.map +1 -0
  189. package/src/lib/record/set-when.mjs +65 -0
  190. package/src/lib/record/set-when.mjs.map +1 -0
  191. package/src/lib/record/structures.d.mts +14 -0
  192. package/src/lib/record/structures.d.ts +14 -0
  193. package/src/lib/record/structures.js +32 -0
  194. package/src/lib/record/structures.js.map +1 -0
  195. package/src/lib/record/structures.mjs +28 -0
  196. package/src/lib/record/structures.mjs.map +1 -0
  197. package/src/lib/record/values.d.mts +10 -5
  198. package/src/lib/record/values.d.ts +10 -5
  199. package/src/lib/record/values.js +20 -6
  200. package/src/lib/record/values.js.map +1 -1
  201. package/src/lib/record/values.mjs +19 -6
  202. package/src/lib/record/values.mjs.map +1 -1
  203. package/src/runtime.d.mts +10 -7
  204. package/src/runtime.d.ts +10 -7
  205. package/src/runtime.js +12 -1
  206. package/src/runtime.js.map +1 -1
  207. package/src/runtime.mjs +5 -2
  208. package/src/runtime.mjs.map +1 -1
@@ -1,11 +1,14 @@
1
1
  /**
2
- * AST evaluator for modifiers, ported from the React form engine.
2
+ * AST evaluator for expressions, ported from the React form engine.
3
3
  *
4
4
  * Python semantics where the React version used JavaScript's: an empty list
5
5
  * or string is false, and an empty value is never smaller or larger than
6
- * anything — modifiers come from backends that think in Python.
6
+ * anything — modifiers come from backends that think in Python. Arithmetic
7
+ * and functions give null for what they cannot work out, never an error.
7
8
  */
8
9
  import type { ASTNode } from './parser.mjs';
10
+ import { type ExpressionEnv } from './functions.mjs';
11
+ export { truthy } from './operations.mjs';
9
12
  /**
10
13
  * Evaluate an AST node against a context object
11
14
  *
@@ -18,6 +21,4 @@ import type { ASTNode } from './parser.mjs';
18
21
  * const context = { state: 'draft', amount: 100 };
19
22
  * evaluate(ast, context); // Returns boolean result
20
23
  */
21
- export declare function evaluate(ast: ASTNode, context: Record<string, unknown>): unknown;
22
- /** Python's truth test: empty lists, strings and objects, 0 and None are false. */
23
- export declare function truthy(value: unknown): boolean;
24
+ export declare function evaluate(ast: ASTNode, context: Record<string, unknown>, env?: ExpressionEnv): unknown;
@@ -1,11 +1,14 @@
1
1
  /**
2
- * AST evaluator for modifiers, ported from the React form engine.
2
+ * AST evaluator for expressions, ported from the React form engine.
3
3
  *
4
4
  * Python semantics where the React version used JavaScript's: an empty list
5
5
  * or string is false, and an empty value is never smaller or larger than
6
- * anything — modifiers come from backends that think in Python.
6
+ * anything — modifiers come from backends that think in Python. Arithmetic
7
+ * and functions give null for what they cannot work out, never an error.
7
8
  */
8
9
  import type { ASTNode } from './parser';
10
+ import { type ExpressionEnv } from './functions';
11
+ export { truthy } from './operations';
9
12
  /**
10
13
  * Evaluate an AST node against a context object
11
14
  *
@@ -18,6 +21,4 @@ import type { ASTNode } from './parser';
18
21
  * const context = { state: 'draft', amount: 100 };
19
22
  * evaluate(ast, context); // Returns boolean result
20
23
  */
21
- export declare function evaluate(ast: ASTNode, context: Record<string, unknown>): unknown;
22
- /** Python's truth test: empty lists, strings and objects, 0 and None are false. */
23
- export declare function truthy(value: unknown): boolean;
24
+ export declare function evaluate(ast: ASTNode, context: Record<string, unknown>, env?: ExpressionEnv): unknown;
@@ -1,14 +1,19 @@
1
1
  "use strict";
2
2
  /**
3
- * AST evaluator for modifiers, ported from the React form engine.
3
+ * AST evaluator for expressions, ported from the React form engine.
4
4
  *
5
5
  * Python semantics where the React version used JavaScript's: an empty list
6
6
  * or string is false, and an empty value is never smaller or larger than
7
- * anything — modifiers come from backends that think in Python.
7
+ * anything — modifiers come from backends that think in Python. Arithmetic
8
+ * and functions give null for what they cannot work out, never an error.
8
9
  */
9
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.truthy = void 0;
10
12
  exports.evaluate = evaluate;
11
- exports.truthy = truthy;
13
+ const functions_1 = require("./functions");
14
+ const operations_1 = require("./operations");
15
+ var operations_2 = require("./operations");
16
+ Object.defineProperty(exports, "truthy", { enumerable: true, get: function () { return operations_2.truthy; } });
12
17
  /**
13
18
  * Evaluate an AST node against a context object
14
19
  *
@@ -21,12 +26,14 @@ exports.truthy = truthy;
21
26
  * const context = { state: 'draft', amount: 100 };
22
27
  * evaluate(ast, context); // Returns boolean result
23
28
  */
24
- function evaluate(ast, context) {
29
+ function evaluate(ast, context, env = {}) {
25
30
  switch (ast.type) {
26
31
  case 'BinaryOp':
27
- return evaluateBinaryOp(ast, context);
32
+ return evaluateBinaryOp(ast, context, env);
28
33
  case 'UnaryOp':
29
- return evaluateUnaryOp(ast, context);
34
+ return evaluateUnaryOp(ast, context, env);
35
+ case 'Call':
36
+ return evaluateCall(ast, context, env);
30
37
  case 'Literal':
31
38
  return ast.value;
32
39
  case 'Identifier':
@@ -38,9 +45,9 @@ function evaluate(ast, context) {
38
45
  /**
39
46
  * Evaluate binary operations
40
47
  */
41
- function evaluateBinaryOp(node, context) {
42
- const left = normalize(evaluate(node.left, context));
43
- const right = normalize(evaluate(node.right, context));
48
+ function evaluateBinaryOp(node, context, env) {
49
+ const left = normalize(evaluate(node.left, context, env));
50
+ const right = normalize(evaluate(node.right, context, env));
44
51
  const operator = node.operator.toLowerCase();
45
52
  const ordered = left !== null && right !== null;
46
53
  switch (operator) {
@@ -63,11 +70,18 @@ function evaluateBinaryOp(node, context) {
63
70
  return Array.isArray(right) && right.includes(left);
64
71
  case 'not in':
65
72
  return Array.isArray(right) && !right.includes(left);
73
+ // Arithmetic, and + joining text
74
+ case '+':
75
+ case '-':
76
+ case '*':
77
+ case '/':
78
+ case '%':
79
+ return (0, operations_1.arithmetic)(operator, left, right);
66
80
  // Logical operators (use truthiness)
67
81
  case 'and':
68
- return truthy(left) && truthy(right);
82
+ return (0, operations_1.truthy)(left) && (0, operations_1.truthy)(right);
69
83
  case 'or':
70
- return truthy(left) || truthy(right);
84
+ return (0, operations_1.truthy)(left) || (0, operations_1.truthy)(right);
71
85
  default:
72
86
  throw new Error(`Unknown binary operator: ${node.operator}`);
73
87
  }
@@ -75,28 +89,29 @@ function evaluateBinaryOp(node, context) {
75
89
  /**
76
90
  * Evaluate unary operations
77
91
  */
78
- function evaluateUnaryOp(node, context) {
79
- const operand = evaluate(node.operand, context);
92
+ function evaluateUnaryOp(node, context, env) {
93
+ const operand = evaluate(node.operand, context, env);
80
94
  const operator = node.operator.toLowerCase();
81
95
  switch (operator) {
82
96
  case 'not':
83
- return !truthy(operand);
97
+ return !(0, operations_1.truthy)(operand);
98
+ case '-':
99
+ return (0, operations_1.negate)(operand);
84
100
  default:
85
101
  throw new Error(`Unknown unary operator: ${node.operator}`);
86
102
  }
87
103
  }
104
+ /** A function called with its values, each read only when the function asks for it. */
105
+ function evaluateCall(node, context, env) {
106
+ const fn = functions_1.FUNCTIONS.get(node.name);
107
+ if (!fn)
108
+ throw new Error(`Unknown function: ${node.name}`);
109
+ return fn.call({ args: node.args, value: (arg) => evaluate(arg, context, env), env });
110
+ }
88
111
  /** A missing value compares like None. */
89
112
  function normalize(value) {
90
113
  return value === undefined ? null : value;
91
114
  }
92
- /** Python's truth test: empty lists, strings and objects, 0 and None are false. */
93
- function truthy(value) {
94
- if (Array.isArray(value))
95
- return value.length > 0;
96
- if (value !== null && typeof value === 'object')
97
- return Object.keys(value).length > 0;
98
- return Boolean(value);
99
- }
100
115
  /**
101
116
  * Get a nested value from an object using dot notation
102
117
  *
@@ -1 +1 @@
1
- {"version":3,"file":"evaluator.js","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/evaluator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"evaluator.js","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/evaluator.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,14 @@
1
1
  /**
2
- * AST evaluator for modifiers, ported from the React form engine.
2
+ * AST evaluator for expressions, ported from the React form engine.
3
3
  *
4
4
  * Python semantics where the React version used JavaScript's: an empty list
5
5
  * or string is false, and an empty value is never smaller or larger than
6
- * anything — modifiers come from backends that think in Python.
6
+ * anything — modifiers come from backends that think in Python. Arithmetic
7
+ * and functions give null for what they cannot work out, never an error.
7
8
  */
9
+ import { FUNCTIONS } from './functions.mjs';
10
+ import { arithmetic, negate, truthy } from './operations.mjs';
11
+ export { truthy } from './operations.mjs';
8
12
  /**
9
13
  * Evaluate an AST node against a context object
10
14
  *
@@ -17,12 +21,14 @@
17
21
  * const context = { state: 'draft', amount: 100 };
18
22
  * evaluate(ast, context); // Returns boolean result
19
23
  */
20
- export function evaluate(ast, context) {
24
+ export function evaluate(ast, context, env = {}) {
21
25
  switch (ast.type) {
22
26
  case 'BinaryOp':
23
- return evaluateBinaryOp(ast, context);
27
+ return evaluateBinaryOp(ast, context, env);
24
28
  case 'UnaryOp':
25
- return evaluateUnaryOp(ast, context);
29
+ return evaluateUnaryOp(ast, context, env);
30
+ case 'Call':
31
+ return evaluateCall(ast, context, env);
26
32
  case 'Literal':
27
33
  return ast.value;
28
34
  case 'Identifier':
@@ -34,9 +40,9 @@ export function evaluate(ast, context) {
34
40
  /**
35
41
  * Evaluate binary operations
36
42
  */
37
- function evaluateBinaryOp(node, context) {
38
- const left = normalize(evaluate(node.left, context));
39
- const right = normalize(evaluate(node.right, context));
43
+ function evaluateBinaryOp(node, context, env) {
44
+ const left = normalize(evaluate(node.left, context, env));
45
+ const right = normalize(evaluate(node.right, context, env));
40
46
  const operator = node.operator.toLowerCase();
41
47
  const ordered = left !== null && right !== null;
42
48
  switch (operator) {
@@ -59,6 +65,13 @@ function evaluateBinaryOp(node, context) {
59
65
  return Array.isArray(right) && right.includes(left);
60
66
  case 'not in':
61
67
  return Array.isArray(right) && !right.includes(left);
68
+ // Arithmetic, and + joining text
69
+ case '+':
70
+ case '-':
71
+ case '*':
72
+ case '/':
73
+ case '%':
74
+ return arithmetic(operator, left, right);
62
75
  // Logical operators (use truthiness)
63
76
  case 'and':
64
77
  return truthy(left) && truthy(right);
@@ -71,28 +84,29 @@ function evaluateBinaryOp(node, context) {
71
84
  /**
72
85
  * Evaluate unary operations
73
86
  */
74
- function evaluateUnaryOp(node, context) {
75
- const operand = evaluate(node.operand, context);
87
+ function evaluateUnaryOp(node, context, env) {
88
+ const operand = evaluate(node.operand, context, env);
76
89
  const operator = node.operator.toLowerCase();
77
90
  switch (operator) {
78
91
  case 'not':
79
92
  return !truthy(operand);
93
+ case '-':
94
+ return negate(operand);
80
95
  default:
81
96
  throw new Error(`Unknown unary operator: ${node.operator}`);
82
97
  }
83
98
  }
99
+ /** A function called with its values, each read only when the function asks for it. */
100
+ function evaluateCall(node, context, env) {
101
+ const fn = FUNCTIONS.get(node.name);
102
+ if (!fn)
103
+ throw new Error(`Unknown function: ${node.name}`);
104
+ return fn.call({ args: node.args, value: (arg) => evaluate(arg, context, env), env });
105
+ }
84
106
  /** A missing value compares like None. */
85
107
  function normalize(value) {
86
108
  return value === undefined ? null : value;
87
109
  }
88
- /** Python's truth test: empty lists, strings and objects, 0 and None are false. */
89
- export function truthy(value) {
90
- if (Array.isArray(value))
91
- return value.length > 0;
92
- if (value !== null && typeof value === 'object')
93
- return Object.keys(value).length > 0;
94
- return Boolean(value);
95
- }
96
110
  /**
97
111
  * Get a nested value from an object using dot notation
98
112
  *
@@ -1 +1 @@
1
- {"version":3,"file":"evaluator.mjs","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/evaluator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"evaluator.mjs","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/evaluator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { ExpressionEnv } from './functions.mjs';
2
+ export type { ExpressionEnv } from './functions.mjs';
3
+ /** An expression read once, ready to work out a value from a record's values many times. */
4
+ export interface CompiledExpression {
5
+ readonly source: string;
6
+ /** The fields it reads, by their first name, in order of appearance. */
7
+ readonly fields: readonly string[];
8
+ /** The line fields it adds up, as `sum(lines, 'subtotal')` names them. */
9
+ readonly sums: readonly {
10
+ lines: string;
11
+ field: string;
12
+ }[];
13
+ /** The value, or null when it cannot be worked out. Never throws. */
14
+ evaluate(values: Readonly<Record<string, unknown>>, env?: ExpressionEnv): unknown;
15
+ }
16
+ /**
17
+ * Read an expression for a value, such as `price * qty` or
18
+ * `if(total > 1000, 10, 0)`. It is parsed now, so a mistake surfaces when the
19
+ * page is read and not on the first keystroke: throws when it cannot be read.
20
+ */
21
+ export declare function compileExpression(source: string): CompiledExpression;
@@ -0,0 +1,21 @@
1
+ import type { ExpressionEnv } from './functions';
2
+ export type { ExpressionEnv } from './functions';
3
+ /** An expression read once, ready to work out a value from a record's values many times. */
4
+ export interface CompiledExpression {
5
+ readonly source: string;
6
+ /** The fields it reads, by their first name, in order of appearance. */
7
+ readonly fields: readonly string[];
8
+ /** The line fields it adds up, as `sum(lines, 'subtotal')` names them. */
9
+ readonly sums: readonly {
10
+ lines: string;
11
+ field: string;
12
+ }[];
13
+ /** The value, or null when it cannot be worked out. Never throws. */
14
+ evaluate(values: Readonly<Record<string, unknown>>, env?: ExpressionEnv): unknown;
15
+ }
16
+ /**
17
+ * Read an expression for a value, such as `price * qty` or
18
+ * `if(total > 1000, 10, 0)`. It is parsed now, so a mistake surfaces when the
19
+ * page is read and not on the first keystroke: throws when it cannot be read.
20
+ */
21
+ export declare function compileExpression(source: string): CompiledExpression;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.compileExpression = compileExpression;
4
+ const evaluator_1 = require("./evaluator");
5
+ const parser_1 = require("./parser");
6
+ const reads_1 = require("./reads");
7
+ const tokenizer_1 = require("./tokenizer");
8
+ /**
9
+ * Read an expression for a value, such as `price * qty` or
10
+ * `if(total > 1000, 10, 0)`. It is parsed now, so a mistake surfaces when the
11
+ * page is read and not on the first keystroke: throws when it cannot be read.
12
+ */
13
+ function compileExpression(source) {
14
+ const ast = new parser_1.ExpressionParser((0, tokenizer_1.tokenize)(source)).parse();
15
+ return {
16
+ source,
17
+ fields: (0, reads_1.fieldsRead)(ast),
18
+ sums: (0, reads_1.sumsRead)(ast),
19
+ evaluate(values, env = {}) {
20
+ try {
21
+ return (0, evaluator_1.evaluate)(ast, values, env) ?? null;
22
+ }
23
+ catch {
24
+ return null;
25
+ }
26
+ },
27
+ };
28
+ }
29
+ //# sourceMappingURL=expression.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expression.js","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/expression.ts"],"names":[],"mappings":";;AAwBA,8CAcC;AAtCD,2CAAuC;AAEvC,qCAA4C;AAC5C,mCAA+C;AAC/C,2CAAuC;AAevC;;;;GAIG;AACH,SAAgB,iBAAiB,CAAC,MAAc;IAC9C,MAAM,GAAG,GAAG,IAAI,yBAAgB,CAAC,IAAA,oBAAQ,EAAC,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;IAC3D,OAAO;QACL,MAAM;QACN,MAAM,EAAE,IAAA,kBAAU,EAAC,GAAG,CAAC;QACvB,IAAI,EAAE,IAAA,gBAAQ,EAAC,GAAG,CAAC;QACnB,QAAQ,CAAC,MAAM,EAAE,GAAG,GAAG,EAAE;YACvB,IAAI,CAAC;gBACH,OAAO,IAAA,oBAAQ,EAAC,GAAG,EAAE,MAAiC,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC;YACvE,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { evaluate } from './evaluator.mjs';
2
+ import { ExpressionParser } from './parser.mjs';
3
+ import { fieldsRead, sumsRead } from './reads.mjs';
4
+ import { tokenize } from './tokenizer.mjs';
5
+ /**
6
+ * Read an expression for a value, such as `price * qty` or
7
+ * `if(total > 1000, 10, 0)`. It is parsed now, so a mistake surfaces when the
8
+ * page is read and not on the first keystroke: throws when it cannot be read.
9
+ */
10
+ export function compileExpression(source) {
11
+ const ast = new ExpressionParser(tokenize(source)).parse();
12
+ return {
13
+ source,
14
+ fields: fieldsRead(ast),
15
+ sums: sumsRead(ast),
16
+ evaluate(values, env = {}) {
17
+ try {
18
+ return evaluate(ast, values, env) ?? null;
19
+ }
20
+ catch {
21
+ return null;
22
+ }
23
+ },
24
+ };
25
+ }
26
+ //# sourceMappingURL=expression.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expression.mjs","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/expression.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAevC;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,MAAM,GAAG,GAAG,IAAI,gBAAgB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;IAC3D,OAAO;QACL,MAAM;QACN,MAAM,EAAE,UAAU,CAAC,GAAG,CAAC;QACvB,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC;QACnB,QAAQ,CAAC,MAAM,EAAE,GAAG,GAAG,EAAE;YACvB,IAAI,CAAC;gBACH,OAAO,QAAQ,CAAC,GAAG,EAAE,MAAiC,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC;YACvE,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -34,12 +34,17 @@ function extractFieldNames(expression) {
34
34
  const fields = new Set();
35
35
  // Keywords that look like identifiers but aren't field names
36
36
  const keywords = new Set(['null', 'true', 'false', 'True', 'False', 'None']);
37
- tokens.forEach(token => {
37
+ tokens.forEach((token, i) => {
38
38
  if (token.type === 'IDENTIFIER') {
39
39
  // Skip literal keywords
40
40
  if (keywords.has(token.value)) {
41
41
  return;
42
42
  }
43
+ // A name followed by "(" is a function called, not a field: round(x)
44
+ const next = tokens[i + 1];
45
+ if (next?.type === 'PAREN' && next.value === '(') {
46
+ return;
47
+ }
43
48
  // For nested fields like 'partner_id.country_id.name',
44
49
  // we only need to watch the root field 'partner_id'
45
50
  const rootField = token.value.split('.')[0];
@@ -1 +1 @@
1
- {"version":3,"file":"extractFieldNames.js","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/extractFieldNames.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;AAUH,8CAiCC;AAuBD,wEA0BC;AA1FD,2CAAuC;AAEvC;;;;;GAKG;AACH,SAAgB,iBAAiB,CAAC,UAAwC;IACxE,gDAAgD;IAChD,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAC/D,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAA,oBAAQ,EAAC,UAAU,CAAC,CAAC;QACpC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;QAEjC,6DAA6D;QAC7D,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QAE7E,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YACrB,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBAChC,wBAAwB;gBACxB,IAAI,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC9B,OAAO;gBACT,CAAC;gBAED,uDAAuD;gBACvD,oDAAoD;gBACpD,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC5C,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACxB,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,0EAA0E;QAC1E,qDAAqD;QACrD,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,6EAA6E;AAC7E,6EAA6E;AAC7E,MAAM,eAAe,GAAG,IAAI,OAAO,EAAoB,CAAC;AAExD,6DAA6D;AAC7D,MAAM,kBAAkB,GAAa,MAAM,CAAC,MAAM,CAAC,EAAE,CAAwB,CAAC;AAE9E;;;;;;;;;;;;;GAaG;AACH,SAAgB,8BAA8B,CAC5C,SAAoJ;IAEpJ,yCAAyC;IACzC,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC9C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IAEpC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;QAC5C,MAAM,MAAM,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;QAC7C,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,yCAAyC;IACzC,IAAI,SAAS,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACzB,eAAe,CAAC,GAAG,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC;QACnD,OAAO,kBAAkB,CAAC;IAC5B,CAAC;IAED,iDAAiD;IACjD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAa,CAAC;IAChE,eAAe,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACvC,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"extractFieldNames.js","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/extractFieldNames.ts"],"names":[],"mappings":"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"}
@@ -30,12 +30,17 @@ export function extractFieldNames(expression) {
30
30
  const fields = new Set();
31
31
  // Keywords that look like identifiers but aren't field names
32
32
  const keywords = new Set(['null', 'true', 'false', 'True', 'False', 'None']);
33
- tokens.forEach(token => {
33
+ tokens.forEach((token, i) => {
34
34
  if (token.type === 'IDENTIFIER') {
35
35
  // Skip literal keywords
36
36
  if (keywords.has(token.value)) {
37
37
  return;
38
38
  }
39
+ // A name followed by "(" is a function called, not a field: round(x)
40
+ const next = tokens[i + 1];
41
+ if (next?.type === 'PAREN' && next.value === '(') {
42
+ return;
43
+ }
39
44
  // For nested fields like 'partner_id.country_id.name',
40
45
  // we only need to watch the root field 'partner_id'
41
46
  const rootField = token.value.split('.')[0];
@@ -1 +1 @@
1
- {"version":3,"file":"extractFieldNames.mjs","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/extractFieldNames.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAAwC;IACxE,gDAAgD;IAChD,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAC/D,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;QACpC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;QAEjC,6DAA6D;QAC7D,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QAE7E,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YACrB,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBAChC,wBAAwB;gBACxB,IAAI,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC9B,OAAO;gBACT,CAAC;gBAED,uDAAuD;gBACvD,oDAAoD;gBACpD,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC5C,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACxB,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,0EAA0E;QAC1E,qDAAqD;QACrD,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,6EAA6E;AAC7E,6EAA6E;AAC7E,MAAM,eAAe,GAAG,IAAI,OAAO,EAAoB,CAAC;AAExD,6DAA6D;AAC7D,MAAM,kBAAkB,GAAa,MAAM,CAAC,MAAM,CAAC,EAAE,CAAwB,CAAC;AAE9E;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,8BAA8B,CAC5C,SAAoJ;IAEpJ,yCAAyC;IACzC,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC9C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IAEpC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;QAC5C,MAAM,MAAM,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;QAC7C,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,yCAAyC;IACzC,IAAI,SAAS,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACzB,eAAe,CAAC,GAAG,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC;QACnD,OAAO,kBAAkB,CAAC;IAC5B,CAAC;IAED,iDAAiD;IACjD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAa,CAAC;IAChE,eAAe,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACvC,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"extractFieldNames.mjs","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/extractFieldNames.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { ASTNode } from './parser.mjs';
2
+ /**
3
+ * The functions an expression may call. Each says how many values it takes,
4
+ * so a call with too many or too few is refused when the page is read; and
5
+ * each gives null rather than failing when what it is handed does not fit.
6
+ */
7
+ /** What an expression is worked out with, besides the record's values. */
8
+ export interface ExpressionEnv {
9
+ /**
10
+ * The lines of a one2many, as rows of their values, for `sum` and `count`:
11
+ * the values hold only the lines' keys. Sections and notes are left out.
12
+ */
13
+ lines?(field: string): readonly Readonly<Record<string, unknown>>[] | undefined;
14
+ /** Today, as YYYY-MM-DD. The computer's own clock when left out. */
15
+ today?(): string;
16
+ }
17
+ /** One call, as a function sees it: its values unread, a way to read each, and the env. */
18
+ interface Call {
19
+ args: readonly ASTNode[];
20
+ value(node: ASTNode): unknown;
21
+ env: ExpressionEnv;
22
+ }
23
+ interface ExpressionFunction {
24
+ /** How many values it takes: at least, at most. */
25
+ readonly takes: readonly [number, number];
26
+ /** What is wrong with the values it was given, found as the expression is read. */
27
+ check?(args: readonly ASTNode[]): string | undefined;
28
+ call(call: Call): unknown;
29
+ }
30
+ /** A day as YYYY-MM-DD, in the computer's own time zone. */
31
+ export declare function localDay(date: Date): string;
32
+ export declare const FUNCTIONS: ReadonlyMap<string, ExpressionFunction>;
33
+ /** How many values a function takes, in words: "round takes 1 or 2 values". */
34
+ export declare function takesInWords(name: string, [least, most]: readonly [number, number]): string;
35
+ export {};
@@ -0,0 +1,35 @@
1
+ import type { ASTNode } from './parser';
2
+ /**
3
+ * The functions an expression may call. Each says how many values it takes,
4
+ * so a call with too many or too few is refused when the page is read; and
5
+ * each gives null rather than failing when what it is handed does not fit.
6
+ */
7
+ /** What an expression is worked out with, besides the record's values. */
8
+ export interface ExpressionEnv {
9
+ /**
10
+ * The lines of a one2many, as rows of their values, for `sum` and `count`:
11
+ * the values hold only the lines' keys. Sections and notes are left out.
12
+ */
13
+ lines?(field: string): readonly Readonly<Record<string, unknown>>[] | undefined;
14
+ /** Today, as YYYY-MM-DD. The computer's own clock when left out. */
15
+ today?(): string;
16
+ }
17
+ /** One call, as a function sees it: its values unread, a way to read each, and the env. */
18
+ interface Call {
19
+ args: readonly ASTNode[];
20
+ value(node: ASTNode): unknown;
21
+ env: ExpressionEnv;
22
+ }
23
+ interface ExpressionFunction {
24
+ /** How many values it takes: at least, at most. */
25
+ readonly takes: readonly [number, number];
26
+ /** What is wrong with the values it was given, found as the expression is read. */
27
+ check?(args: readonly ASTNode[]): string | undefined;
28
+ call(call: Call): unknown;
29
+ }
30
+ /** A day as YYYY-MM-DD, in the computer's own time zone. */
31
+ export declare function localDay(date: Date): string;
32
+ export declare const FUNCTIONS: ReadonlyMap<string, ExpressionFunction>;
33
+ /** How many values a function takes, in words: "round takes 1 or 2 values". */
34
+ export declare function takesInWords(name: string, [least, most]: readonly [number, number]): string;
35
+ export {};