@fieldia/core 0.1.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 (130) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +31 -0
  3. package/package.json +40 -0
  4. package/schema/page.schema.json +2142 -0
  5. package/src/index.d.mts +15 -0
  6. package/src/index.d.ts +15 -0
  7. package/src/index.js +46 -0
  8. package/src/index.js.map +1 -0
  9. package/src/index.mjs +14 -0
  10. package/src/index.mjs.map +1 -0
  11. package/src/lib/expression/evaluateModifier.d.mts +55 -0
  12. package/src/lib/expression/evaluateModifier.d.ts +55 -0
  13. package/src/lib/expression/evaluateModifier.js +121 -0
  14. package/src/lib/expression/evaluateModifier.js.map +1 -0
  15. package/src/lib/expression/evaluateModifier.mjs +117 -0
  16. package/src/lib/expression/evaluateModifier.mjs.map +1 -0
  17. package/src/lib/expression/evaluator.d.mts +23 -0
  18. package/src/lib/expression/evaluator.d.ts +23 -0
  19. package/src/lib/expression/evaluator.js +122 -0
  20. package/src/lib/expression/evaluator.js.map +1 -0
  21. package/src/lib/expression/evaluator.mjs +118 -0
  22. package/src/lib/expression/evaluator.mjs.map +1 -0
  23. package/src/lib/expression/extractFieldNames.d.mts +41 -0
  24. package/src/lib/expression/extractFieldNames.d.ts +41 -0
  25. package/src/lib/expression/extractFieldNames.js +97 -0
  26. package/src/lib/expression/extractFieldNames.js.map +1 -0
  27. package/src/lib/expression/extractFieldNames.mjs +93 -0
  28. package/src/lib/expression/extractFieldNames.mjs.map +1 -0
  29. package/src/lib/expression/modifier.d.mts +14 -0
  30. package/src/lib/expression/modifier.d.ts +14 -0
  31. package/src/lib/expression/modifier.js +55 -0
  32. package/src/lib/expression/modifier.js.map +1 -0
  33. package/src/lib/expression/modifier.mjs +52 -0
  34. package/src/lib/expression/modifier.mjs.map +1 -0
  35. package/src/lib/expression/parser.d.mts +109 -0
  36. package/src/lib/expression/parser.d.ts +109 -0
  37. package/src/lib/expression/parser.js +317 -0
  38. package/src/lib/expression/parser.js.map +1 -0
  39. package/src/lib/expression/parser.mjs +313 -0
  40. package/src/lib/expression/parser.mjs.map +1 -0
  41. package/src/lib/expression/tokenizer.d.mts +31 -0
  42. package/src/lib/expression/tokenizer.d.ts +31 -0
  43. package/src/lib/expression/tokenizer.js +100 -0
  44. package/src/lib/expression/tokenizer.js.map +1 -0
  45. package/src/lib/expression/tokenizer.mjs +96 -0
  46. package/src/lib/expression/tokenizer.mjs.map +1 -0
  47. package/src/lib/format/field.d.mts +967 -0
  48. package/src/lib/format/field.d.ts +967 -0
  49. package/src/lib/format/field.js +147 -0
  50. package/src/lib/format/field.js.map +1 -0
  51. package/src/lib/format/field.mjs +144 -0
  52. package/src/lib/format/field.mjs.map +1 -0
  53. package/src/lib/format/json-schema.d.mts +6 -0
  54. package/src/lib/format/json-schema.d.ts +6 -0
  55. package/src/lib/format/json-schema.js +14 -0
  56. package/src/lib/format/json-schema.js.map +1 -0
  57. package/src/lib/format/json-schema.mjs +11 -0
  58. package/src/lib/format/json-schema.mjs.map +1 -0
  59. package/src/lib/format/json.d.mts +7 -0
  60. package/src/lib/format/json.d.ts +7 -0
  61. package/src/lib/format/json.js +7 -0
  62. package/src/lib/format/json.js.map +1 -0
  63. package/src/lib/format/json.mjs +4 -0
  64. package/src/lib/format/json.mjs.map +1 -0
  65. package/src/lib/format/layout.d.mts +521 -0
  66. package/src/lib/format/layout.d.ts +521 -0
  67. package/src/lib/format/layout.js +150 -0
  68. package/src/lib/format/layout.js.map +1 -0
  69. package/src/lib/format/layout.mjs +147 -0
  70. package/src/lib/format/layout.mjs.map +1 -0
  71. package/src/lib/format/layout.types.d.mts +22 -0
  72. package/src/lib/format/layout.types.d.ts +22 -0
  73. package/src/lib/format/layout.types.js +3 -0
  74. package/src/lib/format/layout.types.js.map +1 -0
  75. package/src/lib/format/layout.types.mjs +2 -0
  76. package/src/lib/format/layout.types.mjs.map +1 -0
  77. package/src/lib/format/page.d.mts +511 -0
  78. package/src/lib/format/page.d.ts +511 -0
  79. package/src/lib/format/page.js +27 -0
  80. package/src/lib/format/page.js.map +1 -0
  81. package/src/lib/format/page.mjs +24 -0
  82. package/src/lib/format/page.mjs.map +1 -0
  83. package/src/lib/format/validate.d.mts +23 -0
  84. package/src/lib/format/validate.d.ts +23 -0
  85. package/src/lib/format/validate.js +210 -0
  86. package/src/lib/format/validate.js.map +1 -0
  87. package/src/lib/format/validate.mjs +207 -0
  88. package/src/lib/format/validate.mjs.map +1 -0
  89. package/src/lib/record/check.d.mts +14 -0
  90. package/src/lib/record/check.d.ts +14 -0
  91. package/src/lib/record/check.js +167 -0
  92. package/src/lib/record/check.js.map +1 -0
  93. package/src/lib/record/check.mjs +163 -0
  94. package/src/lib/record/check.mjs.map +1 -0
  95. package/src/lib/record/data-source.d.mts +109 -0
  96. package/src/lib/record/data-source.d.ts +109 -0
  97. package/src/lib/record/data-source.js +3 -0
  98. package/src/lib/record/data-source.js.map +1 -0
  99. package/src/lib/record/data-source.mjs +2 -0
  100. package/src/lib/record/data-source.mjs.map +1 -0
  101. package/src/lib/record/form.d.mts +106 -0
  102. package/src/lib/record/form.d.ts +106 -0
  103. package/src/lib/record/form.js +545 -0
  104. package/src/lib/record/form.js.map +1 -0
  105. package/src/lib/record/form.mjs +542 -0
  106. package/src/lib/record/form.mjs.map +1 -0
  107. package/src/lib/record/memory-data-source.d.mts +28 -0
  108. package/src/lib/record/memory-data-source.d.ts +28 -0
  109. package/src/lib/record/memory-data-source.js +132 -0
  110. package/src/lib/record/memory-data-source.js.map +1 -0
  111. package/src/lib/record/memory-data-source.mjs +129 -0
  112. package/src/lib/record/memory-data-source.mjs.map +1 -0
  113. package/src/lib/record/messages.d.mts +35 -0
  114. package/src/lib/record/messages.d.ts +35 -0
  115. package/src/lib/record/messages.js +111 -0
  116. package/src/lib/record/messages.js.map +1 -0
  117. package/src/lib/record/messages.mjs +107 -0
  118. package/src/lib/record/messages.mjs.map +1 -0
  119. package/src/lib/record/scheduler.d.mts +12 -0
  120. package/src/lib/record/scheduler.d.ts +12 -0
  121. package/src/lib/record/scheduler.js +16 -0
  122. package/src/lib/record/scheduler.js.map +1 -0
  123. package/src/lib/record/scheduler.mjs +12 -0
  124. package/src/lib/record/scheduler.mjs.map +1 -0
  125. package/src/lib/record/values.d.mts +54 -0
  126. package/src/lib/record/values.d.ts +54 -0
  127. package/src/lib/record/values.js +78 -0
  128. package/src/lib/record/values.js.map +1 -0
  129. package/src/lib/record/values.mjs +71 -0
  130. package/src/lib/record/values.mjs.map +1 -0
@@ -0,0 +1,313 @@
1
+ /**
2
+ * Expression parser for modifiers, ported from the React form engine.
3
+ *
4
+ * Recursive descent parser that converts tokens into an Abstract Syntax Tree (AST).
5
+ * Implements Python-like operator precedence:
6
+ * 1. OR (lowest precedence)
7
+ * 2. AND
8
+ * 3. NOT
9
+ * 4. Comparison operators (==, !=, <, >, <=, >=, in, not in)
10
+ * 5. Values/Identifiers (highest precedence)
11
+ */
12
+ import { CONSTANTS } from './tokenizer.mjs';
13
+ /**
14
+ * Recursive Descent Expression Parser
15
+ */
16
+ export class ExpressionParser {
17
+ tokens;
18
+ position = 0;
19
+ constructor(tokens) {
20
+ this.tokens = tokens;
21
+ }
22
+ /**
23
+ * Parse tokens into an AST
24
+ */
25
+ parse() {
26
+ if (this.tokens.length === 0) {
27
+ throw new Error('Cannot parse empty expression');
28
+ }
29
+ const ast = this.parseOr();
30
+ // Ensure all tokens were consumed
31
+ if (!this.isAtEnd()) {
32
+ throw new Error(`Unexpected token at position ${this.position}: ${this.peek()?.value}`);
33
+ }
34
+ return ast;
35
+ }
36
+ /**
37
+ * Parse OR expressions (lowest precedence)
38
+ * or_expr: and_expr ('or' and_expr)*
39
+ */
40
+ parseOr() {
41
+ let left = this.parseAnd();
42
+ while (this.matchLogical('or')) {
43
+ const operator = this.previous().value;
44
+ const right = this.parseAnd();
45
+ left = {
46
+ type: 'BinaryOp',
47
+ operator: operator.toLowerCase(),
48
+ left,
49
+ right,
50
+ };
51
+ }
52
+ return left;
53
+ }
54
+ /**
55
+ * Parse AND expressions
56
+ * and_expr: not_expr ('and' not_expr)*
57
+ */
58
+ parseAnd() {
59
+ let left = this.parseNot();
60
+ while (this.matchLogical('and')) {
61
+ const operator = this.previous().value;
62
+ const right = this.parseNot();
63
+ left = {
64
+ type: 'BinaryOp',
65
+ operator: operator.toLowerCase(),
66
+ left,
67
+ right,
68
+ };
69
+ }
70
+ return left;
71
+ }
72
+ /**
73
+ * Parse NOT expressions
74
+ * not_expr: 'not' comparison | comparison
75
+ */
76
+ parseNot() {
77
+ if (this.matchLogical('not')) {
78
+ const operator = this.previous().value;
79
+ const operand = this.parseComparison();
80
+ return {
81
+ type: 'UnaryOp',
82
+ operator: operator.toLowerCase(),
83
+ operand,
84
+ };
85
+ }
86
+ return this.parseComparison();
87
+ }
88
+ /**
89
+ * Parse comparison expressions
90
+ * comparison: value (comp_op value)?
91
+ * comp_op: '==' | '!=' | '<>' | '<' | '>' | '<=' | '>=' | 'in' | 'not in'
92
+ */
93
+ parseComparison() {
94
+ const left = this.parseValue();
95
+ const compOperators = ['==', '!=', '<>', '<', '>', '<=', '>=', 'in', 'not in'];
96
+ if (this.matchOperator(...compOperators)) {
97
+ const operator = this.previous().value;
98
+ const right = this.parseValue();
99
+ return {
100
+ type: 'BinaryOp',
101
+ operator: operator.toLowerCase(),
102
+ left,
103
+ right,
104
+ };
105
+ }
106
+ // If no comparison operator, return value as-is (truthiness check)
107
+ return left;
108
+ }
109
+ /**
110
+ * Parse value expressions (highest precedence)
111
+ * value: '(' or_expr ')' | literal | identifier
112
+ */
113
+ parseValue() {
114
+ // Parenthesized expression
115
+ if (this.match('PAREN', '(')) {
116
+ const expr = this.parseOr();
117
+ this.consume('PAREN', ')', 'Expected closing parenthesis');
118
+ return expr;
119
+ }
120
+ // String literal
121
+ if (this.check('STRING')) {
122
+ const token = this.advance();
123
+ // Remove quotes
124
+ const value = token.value.slice(1, -1);
125
+ return { type: 'Literal', value };
126
+ }
127
+ // True, False, None
128
+ if (this.check('CONSTANT')) {
129
+ const token = this.advance();
130
+ return { type: 'Literal', value: CONSTANTS.get(token.value) ?? null };
131
+ }
132
+ // Number literal
133
+ if (this.check('NUMBER')) {
134
+ const token = this.advance();
135
+ return { type: 'Literal', value: Number(token.value) };
136
+ }
137
+ // List literal
138
+ if (this.check('LIST')) {
139
+ const token = this.advance();
140
+ const value = parseListLiteral(token.value);
141
+ return { type: 'Literal', value };
142
+ }
143
+ // Identifier
144
+ if (this.check('IDENTIFIER')) {
145
+ const token = this.advance();
146
+ return { type: 'Identifier', name: token.value };
147
+ }
148
+ throw new Error(`Unexpected token: ${this.peek()?.value || 'EOF'}`);
149
+ }
150
+ // ========== Helper Methods ==========
151
+ /**
152
+ * Check if current token matches any of the given types/values
153
+ */
154
+ match(type, ...values) {
155
+ if (this.check(type)) {
156
+ if (values.length === 0) {
157
+ this.advance();
158
+ return true;
159
+ }
160
+ const token = this.peek();
161
+ if (token && values.includes(token.value)) {
162
+ this.advance();
163
+ return true;
164
+ }
165
+ }
166
+ return false;
167
+ }
168
+ /**
169
+ * Match logical operators (case-insensitive)
170
+ */
171
+ matchLogical(...operators) {
172
+ const token = this.peek();
173
+ if (token && token.type === 'LOGICAL') {
174
+ const lowerValue = token.value.toLowerCase();
175
+ if (operators.map(op => op.toLowerCase()).includes(lowerValue)) {
176
+ this.advance();
177
+ return true;
178
+ }
179
+ }
180
+ return false;
181
+ }
182
+ /**
183
+ * Match comparison operators (case-insensitive)
184
+ */
185
+ matchOperator(...operators) {
186
+ const token = this.peek();
187
+ if (token && token.type === 'OPERATOR') {
188
+ const lowerValue = token.value.toLowerCase();
189
+ if (operators.map(op => op.toLowerCase()).includes(lowerValue)) {
190
+ this.advance();
191
+ return true;
192
+ }
193
+ }
194
+ return false;
195
+ }
196
+ /**
197
+ * Check if current token has given type
198
+ */
199
+ check(type) {
200
+ const token = this.peek();
201
+ return token?.type === type;
202
+ }
203
+ /**
204
+ * Consume current token and advance
205
+ */
206
+ advance() {
207
+ if (!this.isAtEnd()) {
208
+ this.position++;
209
+ }
210
+ return this.previous();
211
+ }
212
+ /**
213
+ * Get current token without advancing
214
+ */
215
+ peek() {
216
+ if (this.isAtEnd()) {
217
+ return null;
218
+ }
219
+ return this.tokens[this.position];
220
+ }
221
+ /**
222
+ * Get previous token
223
+ */
224
+ previous() {
225
+ return this.tokens[this.position - 1];
226
+ }
227
+ /**
228
+ * Check if we've consumed all tokens
229
+ */
230
+ isAtEnd() {
231
+ return this.position >= this.tokens.length;
232
+ }
233
+ /**
234
+ * Consume a token of specific type/value or throw error
235
+ */
236
+ consume(type, value, message) {
237
+ if (this.check(type)) {
238
+ const token = this.peek();
239
+ if (token && token.value === value) {
240
+ return this.advance();
241
+ }
242
+ }
243
+ throw new Error(message);
244
+ }
245
+ }
246
+ /**
247
+ * Parse a list literal string into an array
248
+ * Example: "['draft', 'sent']" -> ['draft', 'sent']
249
+ */
250
+ function parseListLiteral(listStr) {
251
+ try {
252
+ // Remove brackets
253
+ const content = listStr.slice(1, -1).trim();
254
+ if (!content) {
255
+ return [];
256
+ }
257
+ // Split by comma and parse each element
258
+ const elements = [];
259
+ let current = '';
260
+ let inString = false;
261
+ let stringChar = '';
262
+ for (let i = 0; i < content.length; i++) {
263
+ const char = content[i];
264
+ if ((char === "'" || char === '"') && (i === 0 || content[i - 1] !== '\\')) {
265
+ if (!inString) {
266
+ inString = true;
267
+ stringChar = char;
268
+ }
269
+ else if (char === stringChar) {
270
+ inString = false;
271
+ stringChar = '';
272
+ }
273
+ }
274
+ if (char === ',' && !inString) {
275
+ elements.push(parseElement(current.trim()));
276
+ current = '';
277
+ }
278
+ else {
279
+ current += char;
280
+ }
281
+ }
282
+ if (current.trim()) {
283
+ elements.push(parseElement(current.trim()));
284
+ }
285
+ return elements;
286
+ }
287
+ catch (error) {
288
+ // A list that cannot be read is a syntax error, not an empty list.
289
+ throw new Error(`Cannot read the list ${listStr}`, { cause: error });
290
+ }
291
+ }
292
+ /**
293
+ * Parse a single element from a list
294
+ */
295
+ function parseElement(element) {
296
+ // String
297
+ if ((element.startsWith("'") && element.endsWith("'")) ||
298
+ (element.startsWith('"') && element.endsWith('"'))) {
299
+ return element.slice(1, -1);
300
+ }
301
+ // Number
302
+ if (!isNaN(Number(element))) {
303
+ return Number(element);
304
+ }
305
+ // Boolean
306
+ if (element.toLowerCase() === 'true')
307
+ return true;
308
+ if (element.toLowerCase() === 'false')
309
+ return false;
310
+ // Default to string
311
+ return element;
312
+ }
313
+ //# sourceMappingURL=parser.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.mjs","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Tokenizer for modifier expressions.
3
+ *
4
+ * Ported from the React form engine, with one change in behaviour: a
5
+ * character the language does not know is an error, not something to skip.
6
+ * The React version dropped it silently, so `amount > -5` read as
7
+ * `amount > 5` and `a && b` read as `a b`.
8
+ */
9
+ export type TokenType = 'IDENTIFIER' | 'NUMBER' | 'STRING' | 'LIST' | 'OPERATOR' | 'LOGICAL' | 'CONSTANT' | 'PAREN';
10
+ export interface Token {
11
+ type: TokenType;
12
+ value: string;
13
+ position: number;
14
+ }
15
+ /**
16
+ * Tokenizes a Flectra modifier expression.
17
+ *
18
+ * @param expr - The expression string to tokenize
19
+ * @returns Array of tokens
20
+ *
21
+ * @example
22
+ * tokenize("state == 'draft'")
23
+ * // Returns: [
24
+ * // { type: 'IDENTIFIER', value: 'state', position: 0 },
25
+ * // { type: 'OPERATOR', value: '==', position: 1 },
26
+ * // { type: 'STRING', value: "'draft'", position: 2 }
27
+ * // ]
28
+ */
29
+ /** The words that are values, not field names. */
30
+ export declare const CONSTANTS: ReadonlyMap<string, boolean | null>;
31
+ export declare function tokenize(expr: string): Token[];
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Tokenizer for modifier expressions.
3
+ *
4
+ * Ported from the React form engine, with one change in behaviour: a
5
+ * character the language does not know is an error, not something to skip.
6
+ * The React version dropped it silently, so `amount > -5` read as
7
+ * `amount > 5` and `a && b` read as `a b`.
8
+ */
9
+ export type TokenType = 'IDENTIFIER' | 'NUMBER' | 'STRING' | 'LIST' | 'OPERATOR' | 'LOGICAL' | 'CONSTANT' | 'PAREN';
10
+ export interface Token {
11
+ type: TokenType;
12
+ value: string;
13
+ position: number;
14
+ }
15
+ /**
16
+ * Tokenizes a Flectra modifier expression.
17
+ *
18
+ * @param expr - The expression string to tokenize
19
+ * @returns Array of tokens
20
+ *
21
+ * @example
22
+ * tokenize("state == 'draft'")
23
+ * // Returns: [
24
+ * // { type: 'IDENTIFIER', value: 'state', position: 0 },
25
+ * // { type: 'OPERATOR', value: '==', position: 1 },
26
+ * // { type: 'STRING', value: "'draft'", position: 2 }
27
+ * // ]
28
+ */
29
+ /** The words that are values, not field names. */
30
+ export declare const CONSTANTS: ReadonlyMap<string, boolean | null>;
31
+ export declare function tokenize(expr: string): Token[];
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ /**
3
+ * Tokenizer for modifier expressions.
4
+ *
5
+ * Ported from the React form engine, with one change in behaviour: a
6
+ * character the language does not know is an error, not something to skip.
7
+ * The React version dropped it silently, so `amount > -5` read as
8
+ * `amount > 5` and `a && b` read as `a b`.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.CONSTANTS = void 0;
12
+ exports.tokenize = tokenize;
13
+ /**
14
+ * Tokenizes a Flectra modifier expression.
15
+ *
16
+ * @param expr - The expression string to tokenize
17
+ * @returns Array of tokens
18
+ *
19
+ * @example
20
+ * tokenize("state == 'draft'")
21
+ * // Returns: [
22
+ * // { type: 'IDENTIFIER', value: 'state', position: 0 },
23
+ * // { type: 'OPERATOR', value: '==', position: 1 },
24
+ * // { type: 'STRING', value: "'draft'", position: 2 }
25
+ * // ]
26
+ */
27
+ /** The words that are values, not field names. */
28
+ exports.CONSTANTS = new Map([
29
+ ['True', true],
30
+ ['False', false],
31
+ ['None', null],
32
+ ['true', true],
33
+ ['false', false],
34
+ ['null', null],
35
+ ]);
36
+ function tokenize(expr) {
37
+ const tokens = [];
38
+ if (!expr)
39
+ return tokens;
40
+ // Alternatives in priority order: "not in" before "not", operators of two
41
+ // characters before one, a signed number before anything else that could
42
+ // start with a digit. Sticky (`y`), so a position nothing matches is an
43
+ // error instead of a gap.
44
+ const token = /(\(|\)|==|!=|<=|>=|<>|<|>|not\s+in\b|in\b|and\b|or\b|not\b|\[[^\]]*\]|'[^']*'|"[^"]*"|-?\d+\.?\d*|\w+(?:\.\w+)*)/iy;
45
+ const space = /\s*/y;
46
+ let at = 0;
47
+ for (;;) {
48
+ space.lastIndex = at;
49
+ space.exec(expr);
50
+ at = space.lastIndex;
51
+ if (at >= expr.length)
52
+ return tokens;
53
+ token.lastIndex = at;
54
+ const match = token.exec(expr);
55
+ if (!match) {
56
+ throw new Error(`Unexpected "${expr[at]}" at character ${at + 1} of: ${expr}`);
57
+ }
58
+ tokens.push({ type: getTokenType(match[0]), value: match[0], position: tokens.length });
59
+ at = token.lastIndex;
60
+ }
61
+ }
62
+ /**
63
+ * Determines the type of a token based on its text value.
64
+ */
65
+ function getTokenType(text) {
66
+ const lowerText = text.toLowerCase().trim();
67
+ // Python's constants, and their JSON spellings
68
+ if (exports.CONSTANTS.has(text)) {
69
+ return 'CONSTANT';
70
+ }
71
+ // Logical operators (case-insensitive)
72
+ if (lowerText === 'and' || lowerText === 'or' || lowerText === 'not') {
73
+ return 'LOGICAL';
74
+ }
75
+ // Comparison operators (case-insensitive for word operators)
76
+ if (['==', '!=', '<>', '<', '>', '<=', '>='].includes(text) ||
77
+ lowerText === 'in' ||
78
+ lowerText === 'not in') {
79
+ return 'OPERATOR';
80
+ }
81
+ // Parentheses
82
+ if (text === '(' || text === ')') {
83
+ return 'PAREN';
84
+ }
85
+ // Lists (start with '[')
86
+ if (text.startsWith('[')) {
87
+ return 'LIST';
88
+ }
89
+ // Strings (start with ' or ")
90
+ if (text.startsWith("'") || text.startsWith('"')) {
91
+ return 'STRING';
92
+ }
93
+ // Numbers (matches integer or float, either sign)
94
+ if (/^-?\d+\.?\d*$/.test(text)) {
95
+ return 'NUMBER';
96
+ }
97
+ // Default to identifier
98
+ return 'IDENTIFIER';
99
+ }
100
+ //# sourceMappingURL=tokenizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenizer.js","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/tokenizer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Tokenizer for modifier expressions.
3
+ *
4
+ * Ported from the React form engine, with one change in behaviour: a
5
+ * character the language does not know is an error, not something to skip.
6
+ * The React version dropped it silently, so `amount > -5` read as
7
+ * `amount > 5` and `a && b` read as `a b`.
8
+ */
9
+ /**
10
+ * Tokenizes a Flectra modifier expression.
11
+ *
12
+ * @param expr - The expression string to tokenize
13
+ * @returns Array of tokens
14
+ *
15
+ * @example
16
+ * tokenize("state == 'draft'")
17
+ * // Returns: [
18
+ * // { type: 'IDENTIFIER', value: 'state', position: 0 },
19
+ * // { type: 'OPERATOR', value: '==', position: 1 },
20
+ * // { type: 'STRING', value: "'draft'", position: 2 }
21
+ * // ]
22
+ */
23
+ /** The words that are values, not field names. */
24
+ export const CONSTANTS = new Map([
25
+ ['True', true],
26
+ ['False', false],
27
+ ['None', null],
28
+ ['true', true],
29
+ ['false', false],
30
+ ['null', null],
31
+ ]);
32
+ export function tokenize(expr) {
33
+ const tokens = [];
34
+ if (!expr)
35
+ return tokens;
36
+ // Alternatives in priority order: "not in" before "not", operators of two
37
+ // characters before one, a signed number before anything else that could
38
+ // start with a digit. Sticky (`y`), so a position nothing matches is an
39
+ // error instead of a gap.
40
+ const token = /(\(|\)|==|!=|<=|>=|<>|<|>|not\s+in\b|in\b|and\b|or\b|not\b|\[[^\]]*\]|'[^']*'|"[^"]*"|-?\d+\.?\d*|\w+(?:\.\w+)*)/iy;
41
+ const space = /\s*/y;
42
+ let at = 0;
43
+ for (;;) {
44
+ space.lastIndex = at;
45
+ space.exec(expr);
46
+ at = space.lastIndex;
47
+ if (at >= expr.length)
48
+ return tokens;
49
+ token.lastIndex = at;
50
+ const match = token.exec(expr);
51
+ if (!match) {
52
+ throw new Error(`Unexpected "${expr[at]}" at character ${at + 1} of: ${expr}`);
53
+ }
54
+ tokens.push({ type: getTokenType(match[0]), value: match[0], position: tokens.length });
55
+ at = token.lastIndex;
56
+ }
57
+ }
58
+ /**
59
+ * Determines the type of a token based on its text value.
60
+ */
61
+ function getTokenType(text) {
62
+ const lowerText = text.toLowerCase().trim();
63
+ // Python's constants, and their JSON spellings
64
+ if (CONSTANTS.has(text)) {
65
+ return 'CONSTANT';
66
+ }
67
+ // Logical operators (case-insensitive)
68
+ if (lowerText === 'and' || lowerText === 'or' || lowerText === 'not') {
69
+ return 'LOGICAL';
70
+ }
71
+ // Comparison operators (case-insensitive for word operators)
72
+ if (['==', '!=', '<>', '<', '>', '<=', '>='].includes(text) ||
73
+ lowerText === 'in' ||
74
+ lowerText === 'not in') {
75
+ return 'OPERATOR';
76
+ }
77
+ // Parentheses
78
+ if (text === '(' || text === ')') {
79
+ return 'PAREN';
80
+ }
81
+ // Lists (start with '[')
82
+ if (text.startsWith('[')) {
83
+ return 'LIST';
84
+ }
85
+ // Strings (start with ' or ")
86
+ if (text.startsWith("'") || text.startsWith('"')) {
87
+ return 'STRING';
88
+ }
89
+ // Numbers (matches integer or float, either sign)
90
+ if (/^-?\d+\.?\d*$/.test(text)) {
91
+ return 'NUMBER';
92
+ }
93
+ // Default to identifier
94
+ return 'IDENTIFIER';
95
+ }
96
+ //# sourceMappingURL=tokenizer.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenizer.mjs","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/tokenizer.ts"],"names":[],"mappings":"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"}