@atomic-ehr/fhirpath 0.0.1-canary.0c6931e.20250727185306

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 (85) hide show
  1. package/README.md +473 -0
  2. package/dist/index.d.ts +462 -0
  3. package/dist/index.js +10307 -0
  4. package/dist/index.js.map +1 -0
  5. package/package.json +58 -0
  6. package/src/analyzer/analyzer.ts +499 -0
  7. package/src/analyzer/model-provider.ts +244 -0
  8. package/src/analyzer/schemas/index.ts +2 -0
  9. package/src/analyzer/schemas/types.ts +40 -0
  10. package/src/analyzer/types.ts +142 -0
  11. package/src/api/builder.ts +157 -0
  12. package/src/api/errors.ts +145 -0
  13. package/src/api/expression.ts +156 -0
  14. package/src/api/index.ts +122 -0
  15. package/src/api/inspect.ts +99 -0
  16. package/src/api/registry.ts +128 -0
  17. package/src/api/types.ts +210 -0
  18. package/src/compiler/compiler.ts +546 -0
  19. package/src/compiler/index.ts +2 -0
  20. package/src/compiler/prototype-context-adapter.ts +99 -0
  21. package/src/compiler/types.ts +24 -0
  22. package/src/index.ts +107 -0
  23. package/src/interpreter/README.md +78 -0
  24. package/src/interpreter/interpreter.ts +475 -0
  25. package/src/interpreter/types.ts +108 -0
  26. package/src/lexer/char-tables.ts +37 -0
  27. package/src/lexer/errors.ts +31 -0
  28. package/src/lexer/index.ts +5 -0
  29. package/src/lexer/lexer.ts +745 -0
  30. package/src/lexer/token.ts +104 -0
  31. package/src/lexer2/index.md +232 -0
  32. package/src/lexer2/index.perf.test.ts +68 -0
  33. package/src/lexer2/index.test.ts +549 -0
  34. package/src/lexer2/index.ts +1251 -0
  35. package/src/lexer2/notes.md +173 -0
  36. package/src/lexer2/optimization-summary.md +718 -0
  37. package/src/parser/ast-factory.ts +220 -0
  38. package/src/parser/ast.ts +144 -0
  39. package/src/parser/collection-parser.ts +89 -0
  40. package/src/parser/diagnostic-messages.ts +216 -0
  41. package/src/parser/diagnostics.ts +85 -0
  42. package/src/parser/error-reporter.ts +230 -0
  43. package/src/parser/index.ts +3 -0
  44. package/src/parser/literal-parser.ts +103 -0
  45. package/src/parser/parse-error.ts +16 -0
  46. package/src/parser/parser-error-factory.ts +141 -0
  47. package/src/parser/parser-state.ts +134 -0
  48. package/src/parser/parser.ts +1272 -0
  49. package/src/parser/pprint.ts +169 -0
  50. package/src/parser/precedence-manager.ts +64 -0
  51. package/src/parser/source-mapper.ts +248 -0
  52. package/src/parser/special-constructs.ts +142 -0
  53. package/src/parser/token-navigator.ts +110 -0
  54. package/src/parser/types.ts +60 -0
  55. package/src/parser2/index.md +177 -0
  56. package/src/parser2/index.perf.test.ts +184 -0
  57. package/src/parser2/index.test.ts +305 -0
  58. package/src/parser2/index.ts +578 -0
  59. package/src/parser2/optimization-summary.md +176 -0
  60. package/src/registry/default-analyzers.ts +257 -0
  61. package/src/registry/default-compilers.ts +31 -0
  62. package/src/registry/index.ts +96 -0
  63. package/src/registry/operations/arithmetic.ts +506 -0
  64. package/src/registry/operations/collection.ts +425 -0
  65. package/src/registry/operations/comparison.ts +432 -0
  66. package/src/registry/operations/existence.ts +703 -0
  67. package/src/registry/operations/filtering.ts +358 -0
  68. package/src/registry/operations/literals.ts +341 -0
  69. package/src/registry/operations/logical.ts +439 -0
  70. package/src/registry/operations/math.ts +128 -0
  71. package/src/registry/operations/membership.ts +132 -0
  72. package/src/registry/operations/navigation.ts +52 -0
  73. package/src/registry/operations/string.ts +507 -0
  74. package/src/registry/operations/subsetting.ts +174 -0
  75. package/src/registry/operations/type-checking.ts +162 -0
  76. package/src/registry/operations/type-conversion.ts +404 -0
  77. package/src/registry/operations/type-operators.ts +308 -0
  78. package/src/registry/operations/utility.ts +644 -0
  79. package/src/registry/registry.ts +146 -0
  80. package/src/registry/types.ts +161 -0
  81. package/src/registry/utils/evaluation-helpers.ts +93 -0
  82. package/src/registry/utils/index.ts +3 -0
  83. package/src/registry/utils/type-system.ts +173 -0
  84. package/src/runtime/context.ts +158 -0
  85. package/src/runtime/debug-context.ts +135 -0
@@ -0,0 +1,308 @@
1
+ import { TokenType } from '../../lexer/token';
2
+ import type { Operator } from '../types';
3
+ import type { Analyzer, TypeInfo } from '../types';
4
+ import { EvaluationError } from '../../interpreter/types';
5
+ import type { EvaluationResult } from '../../interpreter/types';
6
+ import type { CompiledExpression } from '../../compiler/types';
7
+ import { RuntimeContextManager } from '../../runtime/context';
8
+
9
+ // Type operators (is, as) need special handling in the parser
10
+ // They are included here for precedence lookup and keyword registration
11
+
12
+ export const isOperator: Operator = {
13
+ name: 'is',
14
+ kind: 'operator',
15
+ syntax: {
16
+ form: 'infix',
17
+ token: TokenType.IS,
18
+ precedence: 8, // TYPE precedence
19
+ associativity: 'left',
20
+ notation: 'a is Type',
21
+ special: true // Requires special parsing
22
+ },
23
+ signature: {
24
+ parameters: [{ name: 'left' }, { name: 'right' }],
25
+ output: {
26
+ type: 'Boolean',
27
+ cardinality: 'singleton'
28
+ },
29
+ propagatesEmpty: false
30
+ },
31
+ analyze: (analyzer: Analyzer, input: TypeInfo, args: TypeInfo[]): TypeInfo => {
32
+ // Always returns boolean
33
+ return {
34
+ type: analyzer.resolveType('Boolean'),
35
+ isSingleton: input.isSingleton
36
+ };
37
+ },
38
+ evaluate: (interpreter, context, input, leftValue, rightNode) => {
39
+ // For 'is' operator, the right side should be a type name
40
+ // It might come as a TypeOrIdentifierNode or as an array with the type name
41
+ let typeName: string;
42
+
43
+ if (typeof rightNode === 'string') {
44
+ typeName = rightNode;
45
+ } else if (Array.isArray(rightNode) && rightNode.length === 1) {
46
+ typeName = rightNode[0];
47
+ } else if (rightNode && typeof rightNode === 'object' && 'name' in rightNode) {
48
+ // TypeOrIdentifier node
49
+ typeName = rightNode.name;
50
+ } else {
51
+ throw new Error('is operator requires a type name');
52
+ }
53
+
54
+ // Import TypeSystem locally to avoid circular dependency
55
+ const { TypeSystem } = require('../utils/type-system');
56
+
57
+ if (leftValue.length === 0) {
58
+ return { value: [], context };
59
+ }
60
+
61
+ // Check if all values in the collection match the type
62
+ for (const item of leftValue) {
63
+ if (!TypeSystem.isType(item, typeName)) {
64
+ return { value: [false], context };
65
+ }
66
+ }
67
+
68
+ return { value: [true], context };
69
+ },
70
+ compile: (compiler, input, args) => {
71
+ // For operators, input is the left expression and args contains [left, right]
72
+ const leftExpr = input;
73
+ const rightExpr = args?.[1];
74
+
75
+ if (!leftExpr) {
76
+ throw new Error('is operator requires left operand');
77
+ }
78
+
79
+ if (!rightExpr) {
80
+ throw new Error('is operator requires right operand (type name)');
81
+ }
82
+
83
+ // Import TypeSystem locally to avoid circular dependency
84
+ const { TypeSystem } = require('../utils/type-system');
85
+
86
+ // The right side of 'is' should be a type identifier
87
+ // Since type identifiers don't evaluate to values, we need to handle this specially
88
+
89
+ // Try to determine the type name at compile time
90
+ let staticTypeName: string | undefined;
91
+
92
+ // Check various possible structures for the type name
93
+ // Check if it has source that looks like a type name
94
+ if ((rightExpr as any).source && /^[A-Z][a-zA-Z]*$/.test((rightExpr as any).source)) {
95
+ staticTypeName = (rightExpr as any).source;
96
+ }
97
+ // If it evaluates to a constant type name
98
+ else {
99
+ // Try to execute it with empty context to see if it returns a type name
100
+ try {
101
+ const result = rightExpr.fn(RuntimeContextManager.create([]));
102
+ if (result.length === 1 && typeof result[0] === 'string' && /^[A-Z]/.test(result[0])) {
103
+ staticTypeName = result[0];
104
+ }
105
+ } catch (e) {
106
+ // Ignore errors, fall through to runtime handling
107
+ }
108
+ }
109
+
110
+ if (staticTypeName) {
111
+ // We know the type name at compile time
112
+ return {
113
+ fn: (ctx) => {
114
+ const left = leftExpr.fn(ctx);
115
+
116
+ if (left.length === 0) return [];
117
+
118
+ // Check if all values in the collection match the type
119
+ for (const item of left) {
120
+ if (!TypeSystem.isType(item, staticTypeName)) {
121
+ return [false];
122
+ }
123
+ }
124
+
125
+ return [true];
126
+ },
127
+ type: compiler.resolveType('Boolean'),
128
+ isSingleton: true
129
+ };
130
+ }
131
+
132
+ // Fallback: evaluate type name at runtime
133
+ return {
134
+ fn: (ctx) => {
135
+ const left = leftExpr.fn(ctx);
136
+
137
+ if (left.length === 0) return [];
138
+
139
+ // Try to evaluate the right expression to get the type name
140
+ let typeName: string;
141
+ try {
142
+ const rightResult = rightExpr.fn(ctx);
143
+ if (rightResult.length === 1 && typeof rightResult[0] === 'string') {
144
+ typeName = rightResult[0];
145
+ } else {
146
+ throw new Error('Type name must be a string');
147
+ }
148
+ } catch (e) {
149
+ // If evaluation fails, it might be because TypeOrIdentifier
150
+ // is trying to access a non-existent property
151
+ // In that case, assume the identifier name is the type name
152
+ const source = (rightExpr as any).source;
153
+ if (source && /^[A-Z]/.test(source)) {
154
+ typeName = source;
155
+ } else {
156
+ throw new Error(`Cannot determine type name: ${(e as Error).message}`);
157
+ }
158
+ }
159
+
160
+ // Check if all values in the collection match the type
161
+ for (const item of left) {
162
+ if (!TypeSystem.isType(item, typeName)) {
163
+ return [false];
164
+ }
165
+ }
166
+
167
+ return [true];
168
+ },
169
+ type: compiler.resolveType('Boolean'),
170
+ isSingleton: true
171
+ };
172
+ }
173
+ };
174
+
175
+ export const asOperator: Operator = {
176
+ name: 'as',
177
+ kind: 'operator',
178
+ syntax: {
179
+ form: 'infix',
180
+ token: TokenType.AS,
181
+ precedence: 8, // TYPE precedence
182
+ associativity: 'left',
183
+ notation: 'a as Type',
184
+ special: true // Requires special parsing
185
+ },
186
+ signature: {
187
+ parameters: [{ name: 'left' }, { name: 'right' }],
188
+ output: {
189
+ type: 'preserve-input',
190
+ cardinality: 'preserve-input'
191
+ },
192
+ propagatesEmpty: true
193
+ },
194
+ analyze: (analyzer: Analyzer, input: TypeInfo, args: TypeInfo[]): TypeInfo => {
195
+ // Returns the target type (determined by parser)
196
+ // This is a placeholder - actual type is set by parser
197
+ return {
198
+ type: analyzer.resolveType('Any'),
199
+ isSingleton: input.isSingleton
200
+ };
201
+ },
202
+ evaluate: (interpreter, context, input, leftValue, rightNode) => {
203
+ // For 'as' operator, the right side should be a type name
204
+ let typeName: string;
205
+
206
+ if (typeof rightNode === 'string') {
207
+ typeName = rightNode;
208
+ } else if (Array.isArray(rightNode) && rightNode.length === 1) {
209
+ typeName = rightNode[0];
210
+ } else if (rightNode && typeof rightNode === 'object' && 'name' in rightNode) {
211
+ // TypeOrIdentifier node
212
+ typeName = rightNode.name;
213
+ } else {
214
+ throw new Error('as operator requires a type name');
215
+ }
216
+
217
+ // Import TypeSystem locally to avoid circular dependency
218
+ const { TypeSystem } = require('../utils/type-system');
219
+
220
+ // Filter values that match the type
221
+ const results: any[] = [];
222
+ for (const item of leftValue) {
223
+ if (TypeSystem.isType(item, typeName)) {
224
+ results.push(item);
225
+ }
226
+ }
227
+
228
+ return { value: results, context };
229
+ },
230
+ compile: (compiler, input, args) => {
231
+ // For operators, input is the left expression and args contains [left, right]
232
+ const leftExpr = input;
233
+ const rightExpr = args?.[1];
234
+
235
+ if (!leftExpr || !rightExpr) {
236
+ throw new Error('as operator requires two arguments');
237
+ }
238
+
239
+ // Similar to 'is', extract type name
240
+ let typeName: string | undefined;
241
+
242
+ if ((rightExpr as any).typeName) {
243
+ typeName = (rightExpr as any).typeName;
244
+ } else if ((rightExpr as any).source && (rightExpr as any).source.match(/^[A-Z]\w*$/)) {
245
+ typeName = (rightExpr as any).source;
246
+ }
247
+
248
+ if (typeName) {
249
+ // Import TypeSystem locally to avoid circular dependency
250
+ const { TypeSystem } = require('../utils/type-system');
251
+
252
+ return {
253
+ fn: (ctx) => {
254
+ const left = leftExpr.fn(ctx);
255
+
256
+ // Filter values that match the type
257
+ const results: any[] = [];
258
+ for (const item of left) {
259
+ if (TypeSystem.isType(item, typeName)) {
260
+ results.push(item);
261
+ }
262
+ }
263
+
264
+ return results;
265
+ },
266
+ type: compiler.resolveType(typeName),
267
+ isSingleton: false
268
+ };
269
+ }
270
+
271
+ // Fallback: dynamic type checking
272
+ return {
273
+ fn: (ctx) => {
274
+ const left = leftExpr.fn(ctx);
275
+ const right = rightExpr.fn(ctx);
276
+
277
+ // Extract type name from right result
278
+ let typeNameValue: string;
279
+ if (right.length === 1 && typeof right[0] === 'string') {
280
+ typeNameValue = right[0];
281
+ } else {
282
+ throw new Error('as operator requires a type name');
283
+ }
284
+
285
+ // Import TypeSystem locally to avoid circular dependency
286
+ const { TypeSystem } = require('../utils/type-system');
287
+
288
+ // Filter values that match the type
289
+ const results: any[] = [];
290
+ for (const item of left) {
291
+ if (TypeSystem.isType(item, typeNameValue)) {
292
+ results.push(item);
293
+ }
294
+ }
295
+
296
+ return results;
297
+ },
298
+ type: leftExpr.type,
299
+ isSingleton: false
300
+ };
301
+ }
302
+ };
303
+
304
+ // Export type operators
305
+ export const typeOperators = [
306
+ isOperator,
307
+ asOperator
308
+ ];