@atomic-ehr/fhirpath 0.0.1-canary.35b105d.20250724165800

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +307 -0
  2. package/dist/index.d.ts +225 -0
  3. package/dist/index.js +8185 -0
  4. package/dist/index.js.map +1 -0
  5. package/package.json +51 -0
  6. package/src/analyzer/analyzer.ts +486 -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 +148 -0
  12. package/src/api/errors.ts +134 -0
  13. package/src/api/expression.ts +152 -0
  14. package/src/api/index.ts +57 -0
  15. package/src/api/registry.ts +128 -0
  16. package/src/api/types.ts +154 -0
  17. package/src/compiler/compiler.ts +579 -0
  18. package/src/compiler/index.ts +2 -0
  19. package/src/compiler/prototype-context-adapter.ts +99 -0
  20. package/src/compiler/types.ts +23 -0
  21. package/src/index.ts +52 -0
  22. package/src/interpreter/README.md +78 -0
  23. package/src/interpreter/interpreter.ts +485 -0
  24. package/src/interpreter/types.ts +110 -0
  25. package/src/lexer/char-tables.ts +37 -0
  26. package/src/lexer/errors.ts +31 -0
  27. package/src/lexer/index.ts +5 -0
  28. package/src/lexer/lexer.ts +745 -0
  29. package/src/lexer/token.ts +104 -0
  30. package/src/parser/ast.ts +123 -0
  31. package/src/parser/index.ts +3 -0
  32. package/src/parser/parser.ts +701 -0
  33. package/src/parser/pprint.ts +169 -0
  34. package/src/registry/default-analyzers.ts +257 -0
  35. package/src/registry/default-compilers.ts +31 -0
  36. package/src/registry/index.ts +93 -0
  37. package/src/registry/operations/arithmetic.ts +506 -0
  38. package/src/registry/operations/collection.ts +425 -0
  39. package/src/registry/operations/comparison.ts +432 -0
  40. package/src/registry/operations/existence.ts +703 -0
  41. package/src/registry/operations/filtering.ts +358 -0
  42. package/src/registry/operations/literals.ts +341 -0
  43. package/src/registry/operations/logical.ts +402 -0
  44. package/src/registry/operations/math.ts +128 -0
  45. package/src/registry/operations/membership.ts +132 -0
  46. package/src/registry/operations/string.ts +507 -0
  47. package/src/registry/operations/subsetting.ts +174 -0
  48. package/src/registry/operations/type-checking.ts +162 -0
  49. package/src/registry/operations/type-conversion.ts +404 -0
  50. package/src/registry/operations/type-operators.ts +307 -0
  51. package/src/registry/operations/utility.ts +542 -0
  52. package/src/registry/registry.ts +146 -0
  53. package/src/registry/types.ts +161 -0
  54. package/src/registry/utils/evaluation-helpers.ts +93 -0
  55. package/src/registry/utils/index.ts +3 -0
  56. package/src/registry/utils/type-system.ts +173 -0
  57. package/src/runtime/context.ts +179 -0
@@ -0,0 +1,162 @@
1
+ import type { Function } from '../types';
2
+ import { defaultFunctionAnalyze } from '../default-analyzers';
3
+ import { defaultFunctionCompile } from '../default-compilers';
4
+ import { TypeSystem } from '../utils/type-system';
5
+
6
+ export const typeFunction: Function = {
7
+ name: 'type',
8
+ kind: 'function',
9
+
10
+ syntax: {
11
+ notation: 'type()'
12
+ },
13
+
14
+ signature: {
15
+ input: {
16
+ types: { kind: 'any' },
17
+ cardinality: 'any'
18
+ },
19
+ parameters: [],
20
+ output: {
21
+ type: 'String',
22
+ cardinality: 'collection'
23
+ },
24
+ propagatesEmpty: true,
25
+ deterministic: true
26
+ },
27
+
28
+ analyze: defaultFunctionAnalyze,
29
+
30
+ evaluate: (interpreter, context, input) => {
31
+ const types = new Set<string>();
32
+
33
+ for (const item of input) {
34
+ types.add(TypeSystem.getType(item).name);
35
+ }
36
+
37
+ return { value: Array.from(types), context };
38
+ },
39
+
40
+ compile: defaultFunctionCompile
41
+ };
42
+
43
+ export const isFunction: Function = {
44
+ name: 'is',
45
+ kind: 'function',
46
+
47
+ syntax: {
48
+ notation: 'is(type)'
49
+ },
50
+
51
+ signature: {
52
+ input: {
53
+ types: { kind: 'any' },
54
+ cardinality: 'any'
55
+ },
56
+ parameters: [
57
+ {
58
+ name: 'type',
59
+ kind: 'value',
60
+ types: { kind: 'primitive', types: ['String'] },
61
+ cardinality: 'singleton',
62
+ optional: false
63
+ }
64
+ ],
65
+ output: {
66
+ type: 'Boolean',
67
+ cardinality: 'singleton'
68
+ },
69
+ propagatesEmpty: true,
70
+ deterministic: true
71
+ },
72
+
73
+ analyze: defaultFunctionAnalyze,
74
+
75
+ evaluate: (interpreter, context, input, typeNameOrNode) => {
76
+ if (input.length === 0) {
77
+ return { value: [], context };
78
+ }
79
+
80
+ // Handle case where type is passed as an AST node (e.g., is(String))
81
+ let typeName: string;
82
+ if (typeof typeNameOrNode === 'string') {
83
+ typeName = typeNameOrNode;
84
+ } else if (Array.isArray(typeNameOrNode) && typeNameOrNode.length === 1) {
85
+ typeName = typeNameOrNode[0];
86
+ } else if (typeNameOrNode && typeof typeNameOrNode === 'object' && 'name' in typeNameOrNode) {
87
+ // TypeOrIdentifier node
88
+ typeName = typeNameOrNode.name;
89
+ } else {
90
+ throw new Error('is() requires a type name');
91
+ }
92
+
93
+ for (const item of input) {
94
+ if (!TypeSystem.isType(item, typeName)) {
95
+ return { value: [false], context };
96
+ }
97
+ }
98
+
99
+ return { value: [true], context };
100
+ },
101
+
102
+ compile: defaultFunctionCompile
103
+ };
104
+
105
+ export const asFunction: Function = {
106
+ name: 'as',
107
+ kind: 'function',
108
+
109
+ syntax: {
110
+ notation: 'as(type)'
111
+ },
112
+
113
+ signature: {
114
+ input: {
115
+ types: { kind: 'any' },
116
+ cardinality: 'any'
117
+ },
118
+ parameters: [
119
+ {
120
+ name: 'type',
121
+ kind: 'value',
122
+ types: { kind: 'primitive', types: ['String'] },
123
+ cardinality: 'singleton',
124
+ optional: false
125
+ }
126
+ ],
127
+ output: {
128
+ type: 'preserve-input',
129
+ cardinality: 'collection'
130
+ },
131
+ propagatesEmpty: true,
132
+ deterministic: true
133
+ },
134
+
135
+ analyze: defaultFunctionAnalyze,
136
+
137
+ evaluate: (interpreter, context, input, typeNameOrNode) => {
138
+ // Handle case where type is passed as an AST node (e.g., as(String))
139
+ let typeName: string;
140
+ if (typeof typeNameOrNode === 'string') {
141
+ typeName = typeNameOrNode;
142
+ } else if (Array.isArray(typeNameOrNode) && typeNameOrNode.length === 1) {
143
+ typeName = typeNameOrNode[0];
144
+ } else if (typeNameOrNode && typeof typeNameOrNode === 'object' && 'name' in typeNameOrNode) {
145
+ // TypeOrIdentifier node
146
+ typeName = typeNameOrNode.name;
147
+ } else {
148
+ throw new Error('as() requires a type name');
149
+ }
150
+
151
+ const results: any[] = [];
152
+ for (const item of input) {
153
+ if (TypeSystem.isType(item, typeName)) {
154
+ results.push(item);
155
+ }
156
+ }
157
+
158
+ return { value: results, context };
159
+ },
160
+
161
+ compile: defaultFunctionCompile
162
+ };
@@ -0,0 +1,404 @@
1
+ import type { Function } from '../types';
2
+ import { defaultFunctionAnalyze } from '../default-analyzers';
3
+ import { defaultFunctionCompile } from '../default-compilers';
4
+ import { CollectionUtils } from '../../interpreter/types';
5
+
6
+ export const toStringFunction: Function = {
7
+ name: 'toString',
8
+ kind: 'function',
9
+
10
+ syntax: {
11
+ notation: 'toString()'
12
+ },
13
+
14
+ signature: {
15
+ input: {
16
+ types: { kind: 'any' },
17
+ cardinality: 'singleton'
18
+ },
19
+ parameters: [],
20
+ output: {
21
+ type: 'String',
22
+ cardinality: 'singleton'
23
+ },
24
+ propagatesEmpty: true,
25
+ deterministic: true
26
+ },
27
+
28
+ analyze: defaultFunctionAnalyze,
29
+
30
+ evaluate: (interpreter, context, input) => {
31
+ if (input.length === 0) {
32
+ return { value: [], context };
33
+ }
34
+
35
+ const value = CollectionUtils.toSingleton(input);
36
+
37
+ if (value === null || value === undefined) {
38
+ return { value: [], context };
39
+ }
40
+
41
+ if (typeof value === 'boolean') {
42
+ return { value: [value ? 'true' : 'false'], context };
43
+ }
44
+
45
+ return { value: [String(value)], context };
46
+ },
47
+
48
+ compile: (compiler, input, args) => {
49
+ return {
50
+ fn: (ctx) => {
51
+ const inputValue = input.fn(ctx);
52
+
53
+ if (inputValue.length === 0) {
54
+ return [];
55
+ }
56
+
57
+ const value = inputValue[0]; // toSingleton
58
+
59
+ if (value === null || value === undefined) {
60
+ return [];
61
+ }
62
+
63
+ if (typeof value === 'boolean') {
64
+ return [value ? 'true' : 'false'];
65
+ }
66
+
67
+ return [String(value)];
68
+ },
69
+ type: compiler.resolveType('String'),
70
+ isSingleton: true
71
+ };
72
+ }
73
+ };
74
+
75
+ export const toIntegerFunction: Function = {
76
+ name: 'toInteger',
77
+ kind: 'function',
78
+
79
+ syntax: {
80
+ notation: 'toInteger()'
81
+ },
82
+
83
+ signature: {
84
+ input: {
85
+ types: { kind: 'any' },
86
+ cardinality: 'singleton'
87
+ },
88
+ parameters: [],
89
+ output: {
90
+ type: 'Integer',
91
+ cardinality: 'singleton'
92
+ },
93
+ propagatesEmpty: true,
94
+ deterministic: true
95
+ },
96
+
97
+ analyze: defaultFunctionAnalyze,
98
+
99
+ evaluate: (interpreter, context, input) => {
100
+ if (input.length === 0) {
101
+ return { value: [], context };
102
+ }
103
+
104
+ const value = CollectionUtils.toSingleton(input);
105
+
106
+ if (typeof value === 'number') {
107
+ if (Number.isInteger(value)) {
108
+ return { value: [value], context };
109
+ }
110
+ return { value: [Math.trunc(value)], context };
111
+ }
112
+
113
+ if (typeof value === 'boolean') {
114
+ return { value: [value ? 1 : 0], context };
115
+ }
116
+
117
+ if (typeof value === 'string') {
118
+ const num = parseInt(value, 10);
119
+ if (!isNaN(num)) {
120
+ return { value: [num], context };
121
+ }
122
+ }
123
+
124
+ return { value: [], context };
125
+ },
126
+
127
+ compile: (compiler, input, args) => {
128
+ return {
129
+ fn: (ctx) => {
130
+ const inputValue = input.fn(ctx);
131
+
132
+ if (inputValue.length === 0) {
133
+ return [];
134
+ }
135
+
136
+ const value = inputValue[0]; // toSingleton
137
+
138
+ if (typeof value === 'number') {
139
+ if (Number.isInteger(value)) {
140
+ return [value];
141
+ }
142
+ return [Math.trunc(value)];
143
+ }
144
+
145
+ if (typeof value === 'boolean') {
146
+ return [value ? 1 : 0];
147
+ }
148
+
149
+ if (typeof value === 'string') {
150
+ const num = parseInt(value, 10);
151
+ if (!isNaN(num)) {
152
+ return [num];
153
+ }
154
+ }
155
+
156
+ return [];
157
+ },
158
+ type: compiler.resolveType('Integer'),
159
+ isSingleton: true
160
+ };
161
+ }
162
+ };
163
+
164
+ export const toDecimalFunction: Function = {
165
+ name: 'toDecimal',
166
+ kind: 'function',
167
+
168
+ syntax: {
169
+ notation: 'toDecimal()'
170
+ },
171
+
172
+ signature: {
173
+ input: {
174
+ types: { kind: 'any' },
175
+ cardinality: 'singleton'
176
+ },
177
+ parameters: [],
178
+ output: {
179
+ type: 'Decimal',
180
+ cardinality: 'singleton'
181
+ },
182
+ propagatesEmpty: true,
183
+ deterministic: true
184
+ },
185
+
186
+ analyze: defaultFunctionAnalyze,
187
+
188
+ evaluate: (interpreter, context, input) => {
189
+ if (input.length === 0) {
190
+ return { value: [], context };
191
+ }
192
+
193
+ const value = CollectionUtils.toSingleton(input);
194
+
195
+ if (typeof value === 'number') {
196
+ return { value: [value], context };
197
+ }
198
+
199
+ if (typeof value === 'boolean') {
200
+ return { value: [value ? 1.0 : 0.0], context };
201
+ }
202
+
203
+ if (typeof value === 'string') {
204
+ const num = parseFloat(value);
205
+ if (!isNaN(num)) {
206
+ return { value: [num], context };
207
+ }
208
+ }
209
+
210
+ return { value: [], context };
211
+ },
212
+
213
+ compile: (compiler, input, args) => {
214
+ return {
215
+ fn: (ctx) => {
216
+ const inputValue = input.fn(ctx);
217
+
218
+ if (inputValue.length === 0) {
219
+ return [];
220
+ }
221
+
222
+ const value = inputValue[0]; // toSingleton
223
+
224
+ if (typeof value === 'number') {
225
+ return [value];
226
+ }
227
+
228
+ if (typeof value === 'boolean') {
229
+ return [value ? 1.0 : 0.0];
230
+ }
231
+
232
+ if (typeof value === 'string') {
233
+ const num = parseFloat(value);
234
+ if (!isNaN(num)) {
235
+ return [num];
236
+ }
237
+ }
238
+
239
+ return [];
240
+ },
241
+ type: compiler.resolveType('Decimal'),
242
+ isSingleton: true
243
+ };
244
+ }
245
+ };
246
+
247
+ export const toBooleanFunction: Function = {
248
+ name: 'toBoolean',
249
+ kind: 'function',
250
+
251
+ syntax: {
252
+ notation: 'toBoolean()'
253
+ },
254
+
255
+ signature: {
256
+ input: {
257
+ types: { kind: 'any' },
258
+ cardinality: 'singleton'
259
+ },
260
+ parameters: [],
261
+ output: {
262
+ type: 'Boolean',
263
+ cardinality: 'singleton'
264
+ },
265
+ propagatesEmpty: true,
266
+ deterministic: true
267
+ },
268
+
269
+ analyze: defaultFunctionAnalyze,
270
+
271
+ evaluate: (interpreter, context, input) => {
272
+ if (input.length === 0) {
273
+ return { value: [], context };
274
+ }
275
+
276
+ const value = CollectionUtils.toSingleton(input);
277
+
278
+ if (typeof value === 'boolean') {
279
+ return { value: [value], context };
280
+ }
281
+
282
+ if (typeof value === 'string') {
283
+ const lower = value.toLowerCase();
284
+ if (lower === 'true' || lower === 't' || lower === 'yes' || lower === 'y' || lower === '1') {
285
+ return { value: [true], context };
286
+ }
287
+ if (lower === 'false' || lower === 'f' || lower === 'no' || lower === 'n' || lower === '0') {
288
+ return { value: [false], context };
289
+ }
290
+ }
291
+
292
+ if (typeof value === 'number') {
293
+ if (value === 1) return { value: [true], context };
294
+ if (value === 0) return { value: [false], context };
295
+ }
296
+
297
+ return { value: [], context };
298
+ },
299
+
300
+ compile: (compiler, input, args) => {
301
+ return {
302
+ fn: (ctx) => {
303
+ const inputValue = input.fn(ctx);
304
+
305
+ if (inputValue.length === 0) {
306
+ return [];
307
+ }
308
+
309
+ const value = inputValue[0]; // toSingleton
310
+
311
+ if (typeof value === 'boolean') {
312
+ return [value];
313
+ }
314
+
315
+ if (typeof value === 'string') {
316
+ const lower = value.toLowerCase();
317
+ if (lower === 'true' || lower === 't' || lower === 'yes' || lower === 'y' || lower === '1') {
318
+ return [true];
319
+ }
320
+ if (lower === 'false' || lower === 'f' || lower === 'no' || lower === 'n' || lower === '0') {
321
+ return [false];
322
+ }
323
+ }
324
+
325
+ if (typeof value === 'number') {
326
+ if (value === 1) return [true];
327
+ if (value === 0) return [false];
328
+ }
329
+
330
+ return [];
331
+ },
332
+ type: compiler.resolveType('Boolean'),
333
+ isSingleton: true
334
+ };
335
+ }
336
+ };
337
+
338
+ export const toQuantityFunction: Function = {
339
+ name: 'toQuantity',
340
+ kind: 'function',
341
+
342
+ syntax: {
343
+ notation: 'toQuantity(unit)'
344
+ },
345
+
346
+ signature: {
347
+ input: {
348
+ types: { kind: 'union', types: ['Integer', 'Decimal', 'String'] },
349
+ cardinality: 'singleton'
350
+ },
351
+ parameters: [
352
+ {
353
+ name: 'unit',
354
+ kind: 'value',
355
+ types: { kind: 'primitive', types: ['String'] },
356
+ cardinality: 'singleton',
357
+ optional: true
358
+ }
359
+ ],
360
+ output: {
361
+ type: 'Quantity',
362
+ cardinality: 'singleton'
363
+ },
364
+ propagatesEmpty: true,
365
+ deterministic: true
366
+ },
367
+
368
+ analyze: defaultFunctionAnalyze,
369
+
370
+ evaluate: (interpreter, context, input, unit) => {
371
+ if (input.length === 0) {
372
+ return { value: [], context };
373
+ }
374
+
375
+ const value = CollectionUtils.toSingleton(input);
376
+
377
+ if (typeof value === 'number') {
378
+ const quantity = {
379
+ value: value,
380
+ unit: unit || '1',
381
+ system: 'http://unitsofmeasure.org',
382
+ code: unit || '1'
383
+ };
384
+ return { value: [quantity], context };
385
+ }
386
+
387
+ if (typeof value === 'string') {
388
+ const num = parseFloat(value);
389
+ if (!isNaN(num)) {
390
+ const quantity = {
391
+ value: num,
392
+ unit: unit || '1',
393
+ system: 'http://unitsofmeasure.org',
394
+ code: unit || '1'
395
+ };
396
+ return { value: [quantity], context };
397
+ }
398
+ }
399
+
400
+ return { value: [], context };
401
+ },
402
+
403
+ compile: defaultFunctionCompile
404
+ };