@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,507 @@
1
+ import type { Function } from '../types';
2
+ import { defaultFunctionAnalyze } from '../default-analyzers';
3
+ import { defaultFunctionCompile } from '../default-compilers';
4
+
5
+ export const containsFunction: Function = {
6
+ name: 'contains',
7
+ kind: 'function',
8
+
9
+ syntax: {
10
+ notation: 'contains(substring)'
11
+ },
12
+
13
+ signature: {
14
+ input: {
15
+ types: { kind: 'primitive', types: ['String'] },
16
+ cardinality: 'singleton'
17
+ },
18
+ parameters: [
19
+ {
20
+ name: 'substring',
21
+ kind: 'value',
22
+ types: { kind: 'primitive', types: ['String'] },
23
+ cardinality: 'singleton',
24
+ optional: false
25
+ }
26
+ ],
27
+ output: {
28
+ type: 'Boolean',
29
+ cardinality: 'singleton'
30
+ },
31
+ propagatesEmpty: true,
32
+ deterministic: true
33
+ },
34
+
35
+ analyze: defaultFunctionAnalyze,
36
+
37
+ evaluate: (interpreter, context, input, substring) => {
38
+ const str = input[0];
39
+ return { value: [str.includes(substring)], context };
40
+ },
41
+
42
+ compile: defaultFunctionCompile
43
+ };
44
+
45
+ export const lengthFunction: Function = {
46
+ name: 'length',
47
+ kind: 'function',
48
+
49
+ syntax: {
50
+ notation: 'length()'
51
+ },
52
+
53
+ signature: {
54
+ input: {
55
+ types: { kind: 'primitive', types: ['String'] },
56
+ cardinality: 'singleton'
57
+ },
58
+ parameters: [],
59
+ output: {
60
+ type: 'Integer',
61
+ cardinality: 'singleton'
62
+ },
63
+ propagatesEmpty: true,
64
+ deterministic: true
65
+ },
66
+
67
+ analyze: defaultFunctionAnalyze,
68
+
69
+ evaluate: (interpreter, context, input) => {
70
+ const str = input[0];
71
+ return { value: [str.length], context };
72
+ },
73
+
74
+ compile: defaultFunctionCompile
75
+ };
76
+
77
+ export const substringFunction: Function = {
78
+ name: 'substring',
79
+ kind: 'function',
80
+
81
+ syntax: {
82
+ notation: 'substring(start, length)'
83
+ },
84
+
85
+ signature: {
86
+ input: {
87
+ types: { kind: 'primitive', types: ['String'] },
88
+ cardinality: 'singleton'
89
+ },
90
+ parameters: [
91
+ {
92
+ name: 'start',
93
+ kind: 'value',
94
+ types: { kind: 'primitive', types: ['Integer'] },
95
+ cardinality: 'singleton',
96
+ optional: false
97
+ },
98
+ {
99
+ name: 'length',
100
+ kind: 'value',
101
+ types: { kind: 'primitive', types: ['Integer'] },
102
+ cardinality: 'singleton',
103
+ optional: true
104
+ }
105
+ ],
106
+ output: {
107
+ type: 'String',
108
+ cardinality: 'singleton'
109
+ },
110
+ propagatesEmpty: true,
111
+ deterministic: true
112
+ },
113
+
114
+ analyze: defaultFunctionAnalyze,
115
+
116
+ evaluate: (interpreter, context, input, start, length) => {
117
+ const str = input[0];
118
+
119
+ if (start >= str.length) {
120
+ return { value: [''], context };
121
+ }
122
+
123
+ const result = length !== undefined
124
+ ? str.substring(start, start + length)
125
+ : str.substring(start);
126
+
127
+ return { value: [result], context };
128
+ },
129
+
130
+ compile: defaultFunctionCompile
131
+ };
132
+
133
+ export const startsWithFunction: Function = {
134
+ name: 'startsWith',
135
+ kind: 'function',
136
+
137
+ syntax: {
138
+ notation: 'startsWith(prefix)'
139
+ },
140
+
141
+ signature: {
142
+ input: {
143
+ types: { kind: 'primitive', types: ['String'] },
144
+ cardinality: 'singleton'
145
+ },
146
+ parameters: [
147
+ {
148
+ name: 'prefix',
149
+ kind: 'value',
150
+ types: { kind: 'primitive', types: ['String'] },
151
+ cardinality: 'singleton',
152
+ optional: false
153
+ }
154
+ ],
155
+ output: {
156
+ type: 'Boolean',
157
+ cardinality: 'singleton'
158
+ },
159
+ propagatesEmpty: true,
160
+ deterministic: true
161
+ },
162
+
163
+ analyze: defaultFunctionAnalyze,
164
+
165
+ evaluate: (interpreter, context, input, prefix) => {
166
+ const str = input[0];
167
+ return { value: [str.startsWith(prefix)], context };
168
+ },
169
+
170
+ compile: defaultFunctionCompile
171
+ };
172
+
173
+ export const endsWithFunction: Function = {
174
+ name: 'endsWith',
175
+ kind: 'function',
176
+
177
+ syntax: {
178
+ notation: 'endsWith(suffix)'
179
+ },
180
+
181
+ signature: {
182
+ input: {
183
+ types: { kind: 'primitive', types: ['String'] },
184
+ cardinality: 'singleton'
185
+ },
186
+ parameters: [
187
+ {
188
+ name: 'suffix',
189
+ kind: 'value',
190
+ types: { kind: 'primitive', types: ['String'] },
191
+ cardinality: 'singleton',
192
+ optional: false
193
+ }
194
+ ],
195
+ output: {
196
+ type: 'Boolean',
197
+ cardinality: 'singleton'
198
+ },
199
+ propagatesEmpty: true,
200
+ deterministic: true
201
+ },
202
+
203
+ analyze: defaultFunctionAnalyze,
204
+
205
+ evaluate: (interpreter, context, input, suffix) => {
206
+ const str = input[0];
207
+ return { value: [str.endsWith(suffix)], context };
208
+ },
209
+
210
+ compile: defaultFunctionCompile
211
+ };
212
+
213
+ export const upperFunction: Function = {
214
+ name: 'upper',
215
+ kind: 'function',
216
+
217
+ syntax: {
218
+ notation: 'upper()'
219
+ },
220
+
221
+ signature: {
222
+ input: {
223
+ types: { kind: 'primitive', types: ['String'] },
224
+ cardinality: 'singleton'
225
+ },
226
+ parameters: [],
227
+ output: {
228
+ type: 'String',
229
+ cardinality: 'singleton'
230
+ },
231
+ propagatesEmpty: true,
232
+ deterministic: true
233
+ },
234
+
235
+ analyze: defaultFunctionAnalyze,
236
+
237
+ evaluate: (interpreter, context, input) => {
238
+ const str = input[0];
239
+ return { value: [str.toUpperCase()], context };
240
+ },
241
+
242
+ compile: defaultFunctionCompile
243
+ };
244
+
245
+ export const lowerFunction: Function = {
246
+ name: 'lower',
247
+ kind: 'function',
248
+
249
+ syntax: {
250
+ notation: 'lower()'
251
+ },
252
+
253
+ signature: {
254
+ input: {
255
+ types: { kind: 'primitive', types: ['String'] },
256
+ cardinality: 'singleton'
257
+ },
258
+ parameters: [],
259
+ output: {
260
+ type: 'String',
261
+ cardinality: 'singleton'
262
+ },
263
+ propagatesEmpty: true,
264
+ deterministic: true
265
+ },
266
+
267
+ analyze: defaultFunctionAnalyze,
268
+
269
+ evaluate: (interpreter, context, input) => {
270
+ const str = input[0];
271
+ return { value: [str.toLowerCase()], context };
272
+ },
273
+
274
+ compile: defaultFunctionCompile
275
+ };
276
+
277
+ export const indexOfFunction: Function = {
278
+ name: 'indexOf',
279
+ kind: 'function',
280
+
281
+ syntax: {
282
+ notation: 'indexOf(substring)'
283
+ },
284
+
285
+ signature: {
286
+ input: {
287
+ types: { kind: 'primitive', types: ['String'] },
288
+ cardinality: 'singleton'
289
+ },
290
+ parameters: [
291
+ {
292
+ name: 'substring',
293
+ kind: 'value',
294
+ types: { kind: 'primitive', types: ['String'] },
295
+ cardinality: 'singleton',
296
+ optional: false
297
+ }
298
+ ],
299
+ output: {
300
+ type: 'Integer',
301
+ cardinality: 'singleton'
302
+ },
303
+ propagatesEmpty: true,
304
+ deterministic: true
305
+ },
306
+
307
+ analyze: defaultFunctionAnalyze,
308
+
309
+ evaluate: (interpreter, context, input, substring) => {
310
+ const str = input[0];
311
+ const index = str.indexOf(substring);
312
+ return { value: index === -1 ? [] : [index], context };
313
+ },
314
+
315
+ compile: defaultFunctionCompile
316
+ };
317
+
318
+ export const replaceFunction: Function = {
319
+ name: 'replace',
320
+ kind: 'function',
321
+
322
+ syntax: {
323
+ notation: 'replace(pattern, substitution)'
324
+ },
325
+
326
+ signature: {
327
+ input: {
328
+ types: { kind: 'primitive', types: ['String'] },
329
+ cardinality: 'singleton'
330
+ },
331
+ parameters: [
332
+ {
333
+ name: 'pattern',
334
+ kind: 'value',
335
+ types: { kind: 'primitive', types: ['String'] },
336
+ cardinality: 'singleton',
337
+ optional: false
338
+ },
339
+ {
340
+ name: 'substitution',
341
+ kind: 'value',
342
+ types: { kind: 'primitive', types: ['String'] },
343
+ cardinality: 'singleton',
344
+ optional: false
345
+ }
346
+ ],
347
+ output: {
348
+ type: 'String',
349
+ cardinality: 'singleton'
350
+ },
351
+ propagatesEmpty: true,
352
+ deterministic: true
353
+ },
354
+
355
+ analyze: defaultFunctionAnalyze,
356
+
357
+ evaluate: (interpreter, context, input, pattern, substitution) => {
358
+ const str = input[0];
359
+ // Replace all occurrences
360
+ return { value: [str.split(pattern).join(substitution)], context };
361
+ },
362
+
363
+ compile: defaultFunctionCompile
364
+ };
365
+
366
+ export const splitFunction: Function = {
367
+ name: 'split',
368
+ kind: 'function',
369
+
370
+ syntax: {
371
+ notation: 'split(separator)'
372
+ },
373
+
374
+ signature: {
375
+ input: {
376
+ types: { kind: 'primitive', types: ['String'] },
377
+ cardinality: 'singleton'
378
+ },
379
+ parameters: [
380
+ {
381
+ name: 'separator',
382
+ kind: 'value',
383
+ types: { kind: 'primitive', types: ['String'] },
384
+ cardinality: 'singleton',
385
+ optional: false
386
+ }
387
+ ],
388
+ output: {
389
+ type: 'String',
390
+ cardinality: 'collection'
391
+ },
392
+ propagatesEmpty: true,
393
+ deterministic: true
394
+ },
395
+
396
+ analyze: defaultFunctionAnalyze,
397
+
398
+ evaluate: (interpreter, context, input, separator) => {
399
+ const str = input[0];
400
+ return { value: str.split(separator), context };
401
+ },
402
+
403
+ compile: defaultFunctionCompile
404
+ };
405
+
406
+ export const joinFunction: Function = {
407
+ name: 'join',
408
+ kind: 'function',
409
+
410
+ syntax: {
411
+ notation: 'join(separator)'
412
+ },
413
+
414
+ signature: {
415
+ input: {
416
+ types: { kind: 'any' },
417
+ cardinality: 'collection'
418
+ },
419
+ parameters: [
420
+ {
421
+ name: 'separator',
422
+ kind: 'value',
423
+ types: { kind: 'primitive', types: ['String'] },
424
+ cardinality: 'singleton',
425
+ optional: false
426
+ }
427
+ ],
428
+ output: {
429
+ type: 'String',
430
+ cardinality: 'singleton'
431
+ },
432
+ propagatesEmpty: true,
433
+ deterministic: true
434
+ },
435
+
436
+ analyze: defaultFunctionAnalyze,
437
+
438
+ evaluate: (interpreter, context, input, separator) => {
439
+ return { value: [input.join(separator)], context };
440
+ },
441
+
442
+ compile: defaultFunctionCompile
443
+ };
444
+
445
+ export const trimFunction: Function = {
446
+ name: 'trim',
447
+ kind: 'function',
448
+
449
+ syntax: {
450
+ notation: 'trim()'
451
+ },
452
+
453
+ signature: {
454
+ input: {
455
+ types: { kind: 'primitive', types: ['String'] },
456
+ cardinality: 'singleton'
457
+ },
458
+ parameters: [],
459
+ output: {
460
+ type: 'String',
461
+ cardinality: 'singleton'
462
+ },
463
+ propagatesEmpty: true,
464
+ deterministic: true
465
+ },
466
+
467
+ analyze: defaultFunctionAnalyze,
468
+
469
+ evaluate: (interpreter, context, input) => {
470
+ const str = input[0];
471
+ return { value: [str.trim()], context };
472
+ },
473
+
474
+ compile: defaultFunctionCompile
475
+ };
476
+
477
+ export const toCharsFunction: Function = {
478
+ name: 'toChars',
479
+ kind: 'function',
480
+
481
+ syntax: {
482
+ notation: 'toChars()'
483
+ },
484
+
485
+ signature: {
486
+ input: {
487
+ types: { kind: 'primitive', types: ['String'] },
488
+ cardinality: 'singleton'
489
+ },
490
+ parameters: [],
491
+ output: {
492
+ type: 'String',
493
+ cardinality: 'collection'
494
+ },
495
+ propagatesEmpty: true,
496
+ deterministic: true
497
+ },
498
+
499
+ analyze: defaultFunctionAnalyze,
500
+
501
+ evaluate: (interpreter, context, input) => {
502
+ const str = input[0];
503
+ return { value: Array.from(str), context };
504
+ },
505
+
506
+ compile: defaultFunctionCompile
507
+ };
@@ -0,0 +1,174 @@
1
+ import type { Function } from '../types';
2
+ import { defaultFunctionAnalyze } from '../default-analyzers';
3
+ import { defaultFunctionCompile } from '../default-compilers';
4
+
5
+ export const tailFunction: Function = {
6
+ name: 'tail',
7
+ kind: 'function',
8
+
9
+ syntax: {
10
+ notation: 'tail()'
11
+ },
12
+
13
+ signature: {
14
+ input: {
15
+ types: { kind: 'any' },
16
+ cardinality: 'any'
17
+ },
18
+ parameters: [],
19
+ output: {
20
+ type: 'preserve-input',
21
+ cardinality: 'collection'
22
+ },
23
+ propagatesEmpty: true,
24
+ deterministic: true
25
+ },
26
+
27
+ analyze: defaultFunctionAnalyze,
28
+
29
+ evaluate: (interpreter, context, input) => {
30
+ return { value: input.slice(1), context };
31
+ },
32
+
33
+ compile: (compiler, input, args) => {
34
+ return {
35
+ fn: (ctx) => {
36
+ const inputVal = input.fn(ctx);
37
+ return inputVal.slice(1);
38
+ },
39
+ type: input.type,
40
+ isSingleton: false,
41
+ source: `${input.source || ''}.tail()`
42
+ };
43
+ }
44
+ };
45
+
46
+ export const skipFunction: Function = {
47
+ name: 'skip',
48
+ kind: 'function',
49
+
50
+ syntax: {
51
+ notation: 'skip(count)'
52
+ },
53
+
54
+ signature: {
55
+ input: {
56
+ types: { kind: 'any' },
57
+ cardinality: 'any'
58
+ },
59
+ parameters: [
60
+ {
61
+ name: 'count',
62
+ kind: 'value',
63
+ types: { kind: 'primitive', types: ['Integer'] },
64
+ cardinality: 'singleton',
65
+ optional: false
66
+ }
67
+ ],
68
+ output: {
69
+ type: 'preserve-input',
70
+ cardinality: 'collection'
71
+ },
72
+ propagatesEmpty: true,
73
+ deterministic: true
74
+ },
75
+
76
+ analyze: defaultFunctionAnalyze,
77
+
78
+ evaluate: (interpreter, context, input, count) => {
79
+ return { value: input.slice(count), context };
80
+ },
81
+
82
+ compile: (compiler, input, args) => {
83
+ const countExpr = args[0];
84
+ if (!countExpr) {
85
+ throw new Error('skip() requires a count parameter');
86
+ }
87
+
88
+ return {
89
+ fn: (ctx) => {
90
+ const inputVal = input.fn(ctx);
91
+ const countResult = countExpr.fn(ctx);
92
+
93
+ if (countResult.length === 0) {
94
+ return inputVal;
95
+ }
96
+
97
+ const count = countResult[0];
98
+ if (typeof count !== 'number' || !Number.isInteger(count)) {
99
+ throw new Error('skip() count must be an integer');
100
+ }
101
+
102
+ return inputVal.slice(count);
103
+ },
104
+ type: input.type,
105
+ isSingleton: false,
106
+ source: `${input.source || ''}.skip(${countExpr.source || ''})`
107
+ };
108
+ }
109
+ };
110
+
111
+ export const takeFunction: Function = {
112
+ name: 'take',
113
+ kind: 'function',
114
+
115
+ syntax: {
116
+ notation: 'take(count)'
117
+ },
118
+
119
+ signature: {
120
+ input: {
121
+ types: { kind: 'any' },
122
+ cardinality: 'any'
123
+ },
124
+ parameters: [
125
+ {
126
+ name: 'count',
127
+ kind: 'value',
128
+ types: { kind: 'primitive', types: ['Integer'] },
129
+ cardinality: 'singleton',
130
+ optional: false
131
+ }
132
+ ],
133
+ output: {
134
+ type: 'preserve-input',
135
+ cardinality: 'collection'
136
+ },
137
+ propagatesEmpty: true,
138
+ deterministic: true
139
+ },
140
+
141
+ analyze: defaultFunctionAnalyze,
142
+
143
+ evaluate: (interpreter, context, input, count) => {
144
+ return { value: input.slice(0, count), context };
145
+ },
146
+
147
+ compile: (compiler, input, args) => {
148
+ const countExpr = args[0];
149
+ if (!countExpr) {
150
+ throw new Error('take() requires a count parameter');
151
+ }
152
+
153
+ return {
154
+ fn: (ctx) => {
155
+ const inputVal = input.fn(ctx);
156
+ const countResult = countExpr.fn(ctx);
157
+
158
+ if (countResult.length === 0) {
159
+ return [];
160
+ }
161
+
162
+ const count = countResult[0];
163
+ if (typeof count !== 'number' || !Number.isInteger(count)) {
164
+ throw new Error('take() count must be an integer');
165
+ }
166
+
167
+ return inputVal.slice(0, count);
168
+ },
169
+ type: input.type,
170
+ isSingleton: false,
171
+ source: `${input.source || ''}.take(${countExpr.source || ''})`
172
+ };
173
+ }
174
+ };