@medplum/core 2.0.21 → 2.0.23

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 (58) hide show
  1. package/dist/cjs/index.cjs +720 -494
  2. package/dist/cjs/index.cjs.map +1 -1
  3. package/dist/cjs/index.min.cjs +1 -1
  4. package/dist/esm/client.mjs +197 -114
  5. package/dist/esm/client.mjs.map +1 -1
  6. package/dist/esm/crypto.mjs +3 -1
  7. package/dist/esm/crypto.mjs.map +1 -1
  8. package/dist/esm/fhirlexer/parse.mjs.map +1 -1
  9. package/dist/esm/fhirlexer/tokenize.mjs +2 -2
  10. package/dist/esm/fhirlexer/tokenize.mjs.map +1 -1
  11. package/dist/esm/fhirpath/atoms.mjs +63 -56
  12. package/dist/esm/fhirpath/atoms.mjs.map +1 -1
  13. package/dist/esm/fhirpath/functions.mjs +370 -252
  14. package/dist/esm/fhirpath/functions.mjs.map +1 -1
  15. package/dist/esm/fhirpath/parse.mjs +4 -2
  16. package/dist/esm/fhirpath/parse.mjs.map +1 -1
  17. package/dist/esm/format.mjs +6 -4
  18. package/dist/esm/format.mjs.map +1 -1
  19. package/dist/esm/hl7.mjs +1 -1
  20. package/dist/esm/hl7.mjs.map +1 -1
  21. package/dist/esm/index.min.mjs +1 -1
  22. package/dist/esm/index.mjs +2 -1
  23. package/dist/esm/index.mjs.map +1 -1
  24. package/dist/esm/jwt.mjs +4 -2
  25. package/dist/esm/jwt.mjs.map +1 -1
  26. package/dist/esm/outcomes.mjs +14 -11
  27. package/dist/esm/outcomes.mjs.map +1 -1
  28. package/dist/esm/schema.mjs +4 -10
  29. package/dist/esm/schema.mjs.map +1 -1
  30. package/dist/esm/search/details.mjs +4 -5
  31. package/dist/esm/search/details.mjs.map +1 -1
  32. package/dist/esm/search/match.mjs +1 -0
  33. package/dist/esm/search/match.mjs.map +1 -1
  34. package/dist/esm/search/search.mjs +1 -1
  35. package/dist/esm/search/search.mjs.map +1 -1
  36. package/dist/esm/storage.mjs +8 -0
  37. package/dist/esm/storage.mjs.map +1 -1
  38. package/dist/esm/types.mjs +1 -0
  39. package/dist/esm/types.mjs.map +1 -1
  40. package/dist/esm/utils.mjs +8 -7
  41. package/dist/esm/utils.mjs.map +1 -1
  42. package/dist/types/client.d.ts +128 -69
  43. package/dist/types/crypto.d.ts +3 -1
  44. package/dist/types/fhirlexer/parse.d.ts +7 -3
  45. package/dist/types/fhirpath/atoms.d.ts +21 -21
  46. package/dist/types/fhirpath/functions.d.ts +2 -2
  47. package/dist/types/fhirpath/parse.d.ts +2 -1
  48. package/dist/types/hl7.d.ts +1 -1
  49. package/dist/types/index.d.ts +1 -0
  50. package/dist/types/jwt.d.ts +2 -1
  51. package/dist/types/outcomes.d.ts +7 -1
  52. package/dist/types/schema.d.ts +4 -10
  53. package/dist/types/search/details.d.ts +0 -1
  54. package/dist/types/search/search.d.ts +1 -1
  55. package/dist/types/storage.d.ts +8 -0
  56. package/dist/types/typeschema/types.d.ts +0 -1
  57. package/dist/types/utils.d.ts +5 -12
  58. package/package.json +1 -1
@@ -6,6 +6,7 @@ import { booleanToTypedValue, toJsBoolean, removeDuplicates, isQuantity, fhirPat
6
6
 
7
7
  /**
8
8
  * Temporary placholder for unimplemented methods.
9
+ * @returns Empty array.
9
10
  */
10
11
  const stub = () => [];
11
12
  const functions = {
@@ -17,11 +18,11 @@ const functions = {
17
18
  * Returns true if the input collection is empty ({ }) and false otherwise.
18
19
  *
19
20
  * See: https://hl7.org/fhirpath/#empty-boolean
20
- *
21
+ * @param _context The evaluation context.
21
22
  * @param input The input collection.
22
23
  * @returns True if the input collection is empty ({ }) and false otherwise.
23
24
  */
24
- empty: (input) => {
25
+ empty: (_context, input) => {
25
26
  return booleanToTypedValue(input.length === 0);
26
27
  },
27
28
  /**
@@ -34,14 +35,14 @@ const functions = {
34
35
  * for where(criteria).exists().
35
36
  *
36
37
  * See: https://hl7.org/fhirpath/#existscriteria-expression-boolean
37
- *
38
- * @param input
39
- * @param criteria
38
+ * @param context The evaluation context.
39
+ * @param input The input collection.
40
+ * @param criteria The evaluation criteria.
40
41
  * @returns True if the collection has unknown elements, and false otherwise.
41
42
  */
42
- exists: (input, criteria) => {
43
+ exists: (context, input, criteria) => {
43
44
  if (criteria) {
44
- return booleanToTypedValue(input.filter((e) => toJsBoolean(criteria.eval([e]))).length > 0);
45
+ return booleanToTypedValue(input.filter((e) => toJsBoolean(criteria.eval(context, [e]))).length > 0);
45
46
  }
46
47
  else {
47
48
  return booleanToTypedValue(input.length > 0);
@@ -54,13 +55,13 @@ const functions = {
54
55
  * If the input collection is empty ({ }), the result is true.
55
56
  *
56
57
  * See: https://hl7.org/fhirpath/#allcriteria-expression-boolean
57
- *
58
+ * @param context The evaluation context.
58
59
  * @param input The input collection.
59
60
  * @param criteria The evaluation criteria.
60
61
  * @returns True if for every element in the input collection, criteria evaluates to true.
61
62
  */
62
- all: (input, criteria) => {
63
- return booleanToTypedValue(input.every((e) => toJsBoolean(criteria.eval([e]))));
63
+ all: (context, input, criteria) => {
64
+ return booleanToTypedValue(input.every((e) => toJsBoolean(criteria.eval(context, [e]))));
64
65
  },
65
66
  /**
66
67
  * Takes a collection of Boolean values and returns true if all the items are true.
@@ -68,12 +69,11 @@ const functions = {
68
69
  * If the input is empty ({ }), the result is true.
69
70
  *
70
71
  * See: https://hl7.org/fhirpath/#alltrue-boolean
71
- *
72
+ * @param _context The evaluation context.
72
73
  * @param input The input collection.
73
- * @param criteria The evaluation criteria.
74
74
  * @returns True if all the items are true.
75
75
  */
76
- allTrue: (input) => {
76
+ allTrue: (_context, input) => {
77
77
  for (const value of input) {
78
78
  if (!value.value) {
79
79
  return booleanToTypedValue(false);
@@ -86,12 +86,11 @@ const functions = {
86
86
  * If all the items are false, or if the input is empty ({ }), the result is false.
87
87
  *
88
88
  * See: https://hl7.org/fhirpath/#anytrue-boolean
89
- *
89
+ * @param _context The evaluation context.
90
90
  * @param input The input collection.
91
- * @param criteria The evaluation criteria.
92
91
  * @returns True if unknown of the items are true.
93
92
  */
94
- anyTrue: (input) => {
93
+ anyTrue: (_context, input) => {
95
94
  for (const value of input) {
96
95
  if (value.value) {
97
96
  return booleanToTypedValue(true);
@@ -105,12 +104,11 @@ const functions = {
105
104
  * If the input is empty ({ }), the result is true.
106
105
  *
107
106
  * See: https://hl7.org/fhirpath/#allfalse-boolean
108
- *
107
+ * @param _context The evaluation context.
109
108
  * @param input The input collection.
110
- * @param criteria The evaluation criteria.
111
109
  * @returns True if all the items are false.
112
110
  */
113
- allFalse: (input) => {
111
+ allFalse: (_context, input) => {
114
112
  for (const value of input) {
115
113
  if (value.value) {
116
114
  return booleanToTypedValue(false);
@@ -123,12 +121,11 @@ const functions = {
123
121
  * If all the items are true, or if the input is empty ({ }), the result is false.
124
122
  *
125
123
  * See: https://hl7.org/fhirpath/#anyfalse-boolean
126
- *
124
+ * @param _context The evaluation context.
127
125
  * @param input The input collection.
128
- * @param criteria The evaluation criteria.
129
126
  * @returns True if for every element in the input collection, criteria evaluates to true.
130
127
  */
131
- anyFalse: (input) => {
128
+ anyFalse: (_context, input) => {
132
129
  for (const value of input) {
133
130
  if (!value.value) {
134
131
  return booleanToTypedValue(true);
@@ -165,11 +162,11 @@ const functions = {
165
162
  * Returns 0 when the input collection is empty.
166
163
  *
167
164
  * See: https://hl7.org/fhirpath/#count-integer
168
- *
165
+ * @param _context The evaluation context.
169
166
  * @param input The input collection.
170
167
  * @returns The integer count of the number of items in the input collection.
171
168
  */
172
- count: (input) => {
169
+ count: (_context, input) => {
173
170
  return [{ type: PropertyType.integer, value: input.length }];
174
171
  },
175
172
  /**
@@ -183,11 +180,11 @@ const functions = {
183
180
  * preserved in the result.
184
181
  *
185
182
  * See: https://hl7.org/fhirpath/#distinct-collection
186
- *
183
+ * @param _context The evaluation context.
187
184
  * @param input The input collection.
188
185
  * @returns The integer count of the number of items in the input collection.
189
186
  */
190
- distinct: (input) => {
187
+ distinct: (_context, input) => {
191
188
  const result = [];
192
189
  for (const value of input) {
193
190
  if (!result.some((e) => e.value === value.value)) {
@@ -202,12 +199,12 @@ const functions = {
202
199
  * as defined below.
203
200
  *
204
201
  * See: https://hl7.org/fhirpath/#isdistinct-boolean
205
- *
202
+ * @param context The evaluation context.
206
203
  * @param input The input collection.
207
204
  * @returns The integer count of the number of items in the input collection.
208
205
  */
209
- isDistinct: (input) => {
210
- return booleanToTypedValue(input.length === functions.distinct(input).length);
206
+ isDistinct: (context, input) => {
207
+ return booleanToTypedValue(input.length === functions.distinct(context, input).length);
211
208
  },
212
209
  /*
213
210
  * 5.2 Filtering and projection
@@ -225,13 +222,13 @@ const functions = {
225
222
  * consistent with singleton evaluation of collections behavior.
226
223
  *
227
224
  * See: https://hl7.org/fhirpath/#wherecriteria-expression-collection
228
- *
225
+ * @param context The evaluation context.
229
226
  * @param input The input collection.
230
- * @param condition The condition atom.
227
+ * @param criteria The condition atom.
231
228
  * @returns A collection containing only those elements in the input collection for which the stated criteria expression evaluates to true.
232
229
  */
233
- where: (input, criteria) => {
234
- return input.filter((e) => toJsBoolean(criteria.eval([e])));
230
+ where: (context, input, criteria) => {
231
+ return input.filter((e) => toJsBoolean(criteria.eval(context, [e])));
235
232
  },
236
233
  /**
237
234
  * Evaluates the projection expression for each item in the input collection.
@@ -243,9 +240,13 @@ const functions = {
243
240
  * the input collection is empty ({ }), the result is empty as well.
244
241
  *
245
242
  * See: http://hl7.org/fhirpath/#selectprojection-expression-collection
243
+ * @param context The evaluation context.
244
+ * @param input The input collection.
245
+ * @param criteria The condition atom.
246
+ * @returns A collection containing only those elements in the input collection for which the stated criteria expression evaluates to true.
246
247
  */
247
- select: (input, criteria) => {
248
- return input.map((e) => criteria.eval([e])).flat();
248
+ select: (context, input, criteria) => {
249
+ return input.map((e) => criteria.eval(context, [e])).flat();
249
250
  },
250
251
  /**
251
252
  * A version of select that will repeat the projection and add it to the output
@@ -262,8 +263,12 @@ const functions = {
262
263
  * must resolve to the name of a type in a model
263
264
  *
264
265
  * See: http://hl7.org/fhirpath/#oftypetype-type-specifier-collection
266
+ * @param _context The evaluation context.
267
+ * @param input The input collection.
268
+ * @param criteria The condition atom.
269
+ * @returns A collection containing only those elements in the input collection that are of the given type or a subclass thereof.
265
270
  */
266
- ofType: (input, criteria) => {
271
+ ofType: (_context, input, criteria) => {
267
272
  return input.filter((e) => e.type === criteria.name);
268
273
  },
269
274
  /*
@@ -277,11 +282,11 @@ const functions = {
277
282
  * about cardinality is violated at run-time.
278
283
  *
279
284
  * See: https://hl7.org/fhirpath/#single-collection
280
- *
285
+ * @param _context The evaluation context.
281
286
  * @param input The input collection.
282
287
  * @returns The single item in the input if there is just one item.
283
288
  */
284
- single: (input) => {
289
+ single: (_context, input) => {
285
290
  if (input.length > 1) {
286
291
  throw new Error('Expected input length one for single()');
287
292
  }
@@ -292,11 +297,11 @@ const functions = {
292
297
  * This function is equivalent to item[0], so it will return an empty collection if the input collection has no items.
293
298
  *
294
299
  * See: https://hl7.org/fhirpath/#first-collection
295
- *
300
+ * @param context The evaluation context.
296
301
  * @param input The input collection.
297
302
  * @returns A collection containing only the first item in the input collection.
298
303
  */
299
- first: (input) => {
304
+ first: (context, input) => {
300
305
  return input.length === 0 ? [] : input.slice(0, 1);
301
306
  },
302
307
  /**
@@ -304,11 +309,11 @@ const functions = {
304
309
  * Will return an empty collection if the input collection has no items.
305
310
  *
306
311
  * See: https://hl7.org/fhirpath/#last-collection
307
- *
312
+ * @param context The evaluation context.
308
313
  * @param input The input collection.
309
314
  * @returns A collection containing only the last item in the input collection.
310
315
  */
311
- last: (input) => {
316
+ last: (context, input) => {
312
317
  return input.length === 0 ? [] : input.slice(input.length - 1, input.length);
313
318
  },
314
319
  /**
@@ -316,11 +321,11 @@ const functions = {
316
321
  * Will return an empty collection if the input collection has no items, or only one item.
317
322
  *
318
323
  * See: https://hl7.org/fhirpath/#tail-collection
319
- *
324
+ * @param context The evaluation context.
320
325
  * @param input The input collection.
321
326
  * @returns A collection containing all but the first item in the input collection.
322
327
  */
323
- tail: (input) => {
328
+ tail: (context, input) => {
324
329
  return input.length === 0 ? [] : input.slice(1, input.length);
325
330
  },
326
331
  /**
@@ -330,12 +335,13 @@ const functions = {
330
335
  * If num is less than or equal to zero, the input collection is simply returned.
331
336
  *
332
337
  * See: https://hl7.org/fhirpath/#skipnum-integer-collection
333
- *
338
+ * @param context The evaluation context.
334
339
  * @param input The input collection.
340
+ * @param num The atom representing the number of elements to skip.
335
341
  * @returns A collection containing all but the first item in the input collection.
336
342
  */
337
- skip: (input, num) => {
338
- const numValue = num.eval(input)[0]?.value;
343
+ skip: (context, input, num) => {
344
+ const numValue = num.eval(context, input)[0]?.value;
339
345
  if (typeof numValue !== 'number') {
340
346
  throw new Error('Expected a number for skip(num)');
341
347
  }
@@ -354,12 +360,13 @@ const functions = {
354
360
  * take returns an empty collection.
355
361
  *
356
362
  * See: https://hl7.org/fhirpath/#takenum-integer-collection
357
- *
363
+ * @param context The evaluation context.
358
364
  * @param input The input collection.
365
+ * @param num The atom representing the number of elements to take.
359
366
  * @returns A collection containing the first num items in the input collection.
360
367
  */
361
- take: (input, num) => {
362
- const numValue = num.eval(input)[0]?.value;
368
+ take: (context, input, num) => {
369
+ const numValue = num.eval(context, input)[0]?.value;
363
370
  if (typeof numValue !== 'number') {
364
371
  throw new Error('Expected a number for take(num)');
365
372
  }
@@ -377,12 +384,16 @@ const functions = {
377
384
  * Order of items is not guaranteed to be preserved in the result of this function.
378
385
  *
379
386
  * See: http://hl7.org/fhirpath/#intersectother-collection-collection
387
+ * @param context The evaluation context.
388
+ * @param input The input collection.
389
+ * @param other The atom representing the collection of elements to intersect.
390
+ * @returns A collection containing the elements that are in both collections.
380
391
  */
381
- intersect: (input, other) => {
392
+ intersect: (context, input, other) => {
382
393
  if (!other) {
383
394
  return input;
384
395
  }
385
- const otherArray = other.eval(input);
396
+ const otherArray = other.eval(context, input);
386
397
  const result = [];
387
398
  for (const value of input) {
388
399
  if (!result.some((e) => e.value === value.value) && otherArray.some((e) => e.value === value.value)) {
@@ -398,12 +409,16 @@ const functions = {
398
409
  * e.g. (1 | 2 | 3).exclude(2) returns (1 | 3).
399
410
  *
400
411
  * See: http://hl7.org/fhirpath/#excludeother-collection-collection
412
+ * @param context The evaluation context.
413
+ * @param input The input collection.
414
+ * @param other The atom representing the collection of elements to exclude.
415
+ * @returns A collection containing the elements that are in the input collection but not the other collection.
401
416
  */
402
- exclude: (input, other) => {
417
+ exclude: (context, input, other) => {
403
418
  if (!other) {
404
419
  return input;
405
420
  }
406
- const otherArray = other.eval(input);
421
+ const otherArray = other.eval(context, input);
407
422
  const result = [];
408
423
  for (const value of input) {
409
424
  if (!otherArray.some((e) => e.value === value.value)) {
@@ -425,12 +440,16 @@ const functions = {
425
440
  * In other words, this function returns the distinct list of elements from both inputs.
426
441
  *
427
442
  * See: http://hl7.org/fhirpath/#unionother-collection
443
+ * @param context The evaluation context.
444
+ * @param input The input collection.
445
+ * @param other The atom representing the collection of elements to merge.
446
+ * @returns A collection containing the elements that represent the union of both collections.
428
447
  */
429
- union: (input, other) => {
448
+ union: (context, input, other) => {
430
449
  if (!other) {
431
450
  return input;
432
451
  }
433
- const otherArray = other.eval(input);
452
+ const otherArray = other.eval(context, input);
434
453
  return removeDuplicates([...input, ...otherArray]);
435
454
  },
436
455
  /**
@@ -441,12 +460,16 @@ const functions = {
441
460
  * There is no expectation of order in the resulting collection.
442
461
  *
443
462
  * See: http://hl7.org/fhirpath/#combineother-collection-collection
463
+ * @param context The evaluation context.
464
+ * @param input The input collection.
465
+ * @param other The atom representing the collection of elements to merge.
466
+ * @returns A collection containing the elements that represent the combination of both collections including duplicates.
444
467
  */
445
- combine: (input, other) => {
468
+ combine: (context, input, other) => {
446
469
  if (!other) {
447
470
  return input;
448
471
  }
449
- const otherArray = other.eval(input);
472
+ const otherArray = other.eval(context, input);
450
473
  return [...input, ...otherArray];
451
474
  },
452
475
  /*
@@ -469,23 +492,23 @@ const functions = {
469
492
  * true-result should only be evaluated if the criterion evaluates to true,
470
493
  * and otherwise-result should only be evaluated otherwise. For implementations,
471
494
  * this means delaying evaluation of the arguments.
472
- *
473
- * @param input
474
- * @param criterion
475
- * @param trueResult
476
- * @param otherwiseResult
477
- * @returns
495
+ * @param context The evaluation context.
496
+ * @param input The input collection.
497
+ * @param criterion The atom representing the conditional.
498
+ * @param trueResult The atom to be used if the conditional evaluates to true.
499
+ * @param otherwiseResult Optional atom to be used if the conditional evaluates to false.
500
+ * @returns The result of the iif function.
478
501
  */
479
- iif: (input, criterion, trueResult, otherwiseResult) => {
480
- const evalResult = criterion.eval(input);
502
+ iif: (context, input, criterion, trueResult, otherwiseResult) => {
503
+ const evalResult = criterion.eval(context, input);
481
504
  if (evalResult.length > 1 || (evalResult.length === 1 && typeof evalResult[0].value !== 'boolean')) {
482
505
  throw new Error('Expected criterion to evaluate to a Boolean');
483
506
  }
484
507
  if (toJsBoolean(evalResult)) {
485
- return trueResult.eval(input);
508
+ return trueResult.eval(context, input);
486
509
  }
487
510
  if (otherwiseResult) {
488
- return otherwiseResult.eval(input);
511
+ return otherwiseResult.eval(context, input);
489
512
  }
490
513
  return [];
491
514
  },
@@ -501,11 +524,11 @@ const functions = {
501
524
  * If the item is not one the above types, or the item is a String, Integer, or Decimal, but is not equal to one of the possible values convertible to a Boolean, the result is empty.
502
525
  *
503
526
  * See: https://hl7.org/fhirpath/#toboolean-boolean
504
- *
505
- * @param input
506
- * @returns
527
+ * @param _context The evaluation context.
528
+ * @param input The input collection.
529
+ * @returns The input converted to boolean value.
507
530
  */
508
- toBoolean: (input) => {
531
+ toBoolean: (_context, input) => {
509
532
  if (input.length === 0) {
510
533
  return [];
511
534
  }
@@ -545,15 +568,15 @@ const functions = {
545
568
  * If the input collection is empty, the result is empty.
546
569
  *
547
570
  * See: http://hl7.org/fhirpath/#convertstoboolean-boolean
548
- *
549
- * @param input
550
- * @returns
571
+ * @param context The evaluation context.
572
+ * @param input The input collection.
573
+ * @returns True if the input can be converted to boolean.
551
574
  */
552
- convertsToBoolean: (input) => {
575
+ convertsToBoolean: (context, input) => {
553
576
  if (input.length === 0) {
554
577
  return [];
555
578
  }
556
- return booleanToTypedValue(functions.toBoolean(input).length === 1);
579
+ return booleanToTypedValue(functions.toBoolean(context, input).length === 1);
557
580
  },
558
581
  /**
559
582
  * Returns the integer representation of the input.
@@ -572,11 +595,11 @@ const functions = {
572
595
  * If the input collection is empty, the result is empty.
573
596
  *
574
597
  * See: https://hl7.org/fhirpath/#tointeger-integer
575
- *
598
+ * @param _context The evaluation context.
576
599
  * @param input The input collection.
577
600
  * @returns The string representation of the input.
578
601
  */
579
- toInteger: (input) => {
602
+ toInteger: (_context, input) => {
580
603
  if (input.length === 0) {
581
604
  return [];
582
605
  }
@@ -606,15 +629,15 @@ const functions = {
606
629
  * If the input collection is empty, the result is empty.
607
630
  *
608
631
  * See: https://hl7.org/fhirpath/#convertstointeger-boolean
609
- *
632
+ * @param context The evaluation context.
610
633
  * @param input The input collection.
611
- * @returns
634
+ * @returns True if the input can be converted to an integer.
612
635
  */
613
- convertsToInteger: (input) => {
636
+ convertsToInteger: (context, input) => {
614
637
  if (input.length === 0) {
615
638
  return [];
616
639
  }
617
- return booleanToTypedValue(functions.toInteger(input).length === 1);
640
+ return booleanToTypedValue(functions.toInteger(context, input).length === 1);
618
641
  },
619
642
  /**
620
643
  * If the input collection contains a single item, this function will return a single date if:
@@ -631,8 +654,11 @@ const functions = {
631
654
  * If the input collection is empty, the result is empty.
632
655
  *
633
656
  * See: https://hl7.org/fhirpath/#todate-date
657
+ * @param _context The evaluation context.
658
+ * @param input The input collection.
659
+ * @returns The value converted to a date if possible; otherwise empty array.
634
660
  */
635
- toDate: (input) => {
661
+ toDate: (_context, input) => {
636
662
  if (input.length === 0) {
637
663
  return [];
638
664
  }
@@ -657,35 +683,38 @@ const functions = {
657
683
  * If the input collection is empty, the result is empty.
658
684
  *
659
685
  * See: https://hl7.org/fhirpath/#convertstodate-boolean
686
+ * @param context The evaluation context.
687
+ * @param input The input collection.
688
+ * @returns True if the item can be converted to a date.
660
689
  */
661
- convertsToDate: (input) => {
690
+ convertsToDate: (context, input) => {
662
691
  if (input.length === 0) {
663
692
  return [];
664
693
  }
665
- return booleanToTypedValue(functions.toDate(input).length === 1);
666
- },
667
- /**
668
- * If the input collection contains a single item, this function will return a single datetime if:
669
- * 1) the item is a DateTime
670
- * 2) the item is a Date, in which case the result is a DateTime with the year, month, and day of the Date, and the time components empty (not set to zero)
671
- * 3) the item is a String and is convertible to a DateTime
672
- *
673
- * If the item is not one of the above types, the result is empty.
674
- *
675
- * If the item is a String, but the string is not convertible to a DateTime (using the format YYYY-MM-DDThh:mm:ss.fff(+|-)hh:mm), the result is empty.
676
- *
677
- * If the item contains a partial datetime (e.g. '2012-01-01T10:00'), the result is a partial datetime.
678
- *
679
- * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
680
- *
681
- * If the input collection is empty, the result is empty.
682
-
683
- * See: https://hl7.org/fhirpath/#todatetime-datetime
684
- *
685
- * @param input
686
- * @returns
687
- */
688
- toDateTime: (input) => {
694
+ return booleanToTypedValue(functions.toDate(context, input).length === 1);
695
+ },
696
+ /**
697
+ * If the input collection contains a single item, this function will return a single datetime if:
698
+ * 1) the item is a DateTime
699
+ * 2) the item is a Date, in which case the result is a DateTime with the year, month, and day of the Date, and the time components empty (not set to zero)
700
+ * 3) the item is a String and is convertible to a DateTime
701
+ *
702
+ * If the item is not one of the above types, the result is empty.
703
+ *
704
+ * If the item is a String, but the string is not convertible to a DateTime (using the format YYYY-MM-DDThh:mm:ss.fff(+|-)hh:mm), the result is empty.
705
+ *
706
+ * If the item contains a partial datetime (e.g. '2012-01-01T10:00'), the result is a partial datetime.
707
+ *
708
+ * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
709
+ *
710
+ * If the input collection is empty, the result is empty.
711
+ *
712
+ * See: https://hl7.org/fhirpath/#todatetime-datetime
713
+ * @param _context The evaluation context.
714
+ * @param input The input collection.
715
+ * @returns The value converted to a datetime if possible; otherwise empty array.
716
+ */
717
+ toDateTime: (_context, input) => {
689
718
  if (input.length === 0) {
690
719
  return [];
691
720
  }
@@ -708,15 +737,15 @@ const functions = {
708
737
  * If the input collection is empty, the result is empty.
709
738
  *
710
739
  * See: https://hl7.org/fhirpath/#convertstodatetime-boolean
711
- *
712
- * @param input
713
- * @returns
740
+ * @param context The evaluation context.
741
+ * @param input The input collection.
742
+ * @returns True if the item can be converted to a dateTime.
714
743
  */
715
- convertsToDateTime: (input) => {
744
+ convertsToDateTime: (context, input) => {
716
745
  if (input.length === 0) {
717
746
  return [];
718
747
  }
719
- return booleanToTypedValue(functions.toDateTime(input).length === 1);
748
+ return booleanToTypedValue(functions.toDateTime(context, input).length === 1);
720
749
  },
721
750
  /**
722
751
  * If the input collection contains a single item, this function will return a single decimal if:
@@ -732,11 +761,11 @@ const functions = {
732
761
  * If the input collection is empty, the result is empty.
733
762
  *
734
763
  * See: https://hl7.org/fhirpath/#decimal-conversion-functions
735
- *
764
+ * @param _context The evaluation context.
736
765
  * @param input The input collection.
737
- * @returns
766
+ * @returns The value converted to a decimal if possible; otherwise empty array.
738
767
  */
739
- toDecimal: (input) => {
768
+ toDecimal: (_context, input) => {
740
769
  if (input.length === 0) {
741
770
  return [];
742
771
  }
@@ -753,27 +782,27 @@ const functions = {
753
782
  return [];
754
783
  },
755
784
  /**
756
- * If the input collection contains a single item, this function will true if:
757
- * 1) the item is an Integer or Decimal
758
- * 2) the item is a String and is convertible to a Decimal
759
- * 3) the item is a Boolean
760
- *
761
- * If the item is not one of the above types, or is not convertible to a Decimal (using the regex format (\\+|-)?\d+(\.\d+)?), the result is false.
762
- *
763
- * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
764
- *
765
- * If the input collection is empty, the result is empty.
766
-
767
- * See: https://hl7.org/fhirpath/#convertstodecimal-boolean
768
- *
769
- * @param input The input collection.
770
- * @returns
771
- */
772
- convertsToDecimal: (input) => {
785
+ * If the input collection contains a single item, this function will true if:
786
+ * 1) the item is an Integer or Decimal
787
+ * 2) the item is a String and is convertible to a Decimal
788
+ * 3) the item is a Boolean
789
+ *
790
+ * If the item is not one of the above types, or is not convertible to a Decimal (using the regex format (\\+|-)?\d+(\.\d+)?), the result is false.
791
+ *
792
+ * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
793
+ *
794
+ * If the input collection is empty, the result is empty.
795
+ *
796
+ * See: https://hl7.org/fhirpath/#convertstodecimal-boolean
797
+ * @param context The evaluation context.
798
+ * @param input The input collection.
799
+ * @returns The value converted to a decimal if possible; otherwise empty array.
800
+ */
801
+ convertsToDecimal: (context, input) => {
773
802
  if (input.length === 0) {
774
803
  return [];
775
804
  }
776
- return booleanToTypedValue(functions.toDecimal(input).length === 1);
805
+ return booleanToTypedValue(functions.toDecimal(context, input).length === 1);
777
806
  },
778
807
  /**
779
808
  * If the input collection contains a single item, this function will return a single quantity if:
@@ -785,11 +814,11 @@ const functions = {
785
814
  * If the item is not one of the above types, the result is empty.
786
815
  *
787
816
  * See: https://hl7.org/fhirpath/#quantity-conversion-functions
788
- *
817
+ * @param _context The evaluation context.
789
818
  * @param input The input collection.
790
- * @returns
819
+ * @returns The value converted to a quantity if possible; otherwise empty array.
791
820
  */
792
- toQuantity: (input) => {
821
+ toQuantity: (_context, input) => {
793
822
  if (input.length === 0) {
794
823
  return [];
795
824
  }
@@ -827,15 +856,15 @@ const functions = {
827
856
  * If the unit argument is provided, it must be the string representation of a UCUM code (or a FHIRPath calendar duration keyword), and is used to determine whether the input quantity can be converted to the given unit, according to the unit conversion rules specified by UCUM. If the input quantity can be converted, the result is true, otherwise, the result is false.
828
857
  *
829
858
  * See: https://hl7.org/fhirpath/#convertstoquantityunit-string-boolean
830
- *
859
+ * @param context The evaluation context.
831
860
  * @param input The input collection.
832
- * @returns
861
+ * @returns True if the item can be converted to a quantity.
833
862
  */
834
- convertsToQuantity: (input) => {
863
+ convertsToQuantity: (context, input) => {
835
864
  if (input.length === 0) {
836
865
  return [];
837
866
  }
838
- return booleanToTypedValue(functions.toQuantity(input).length === 1);
867
+ return booleanToTypedValue(functions.toQuantity(context, input).length === 1);
839
868
  },
840
869
  /**
841
870
  * Returns the string representation of the input.
@@ -849,11 +878,11 @@ const functions = {
849
878
  * If the item is not one of the above types, the result is false.
850
879
  *
851
880
  * See: https://hl7.org/fhirpath/#tostring-string
852
- *
881
+ * @param _context The evaluation context.
853
882
  * @param input The input collection.
854
883
  * @returns The string representation of the input.
855
884
  */
856
- toString: (input) => {
885
+ toString: (_context, input) => {
857
886
  if (input.length === 0) {
858
887
  return [];
859
888
  }
@@ -882,15 +911,15 @@ const functions = {
882
911
  * If the input collection is empty, the result is empty.
883
912
  *
884
913
  * See: https://hl7.org/fhirpath/#tostring-string
885
- *
914
+ * @param context The evaluation context.
886
915
  * @param input The input collection.
887
- * @returns
916
+ * @returns True if the item can be converted to a string
888
917
  */
889
- convertsToString: (input) => {
918
+ convertsToString: (context, input) => {
890
919
  if (input.length === 0) {
891
920
  return [];
892
921
  }
893
- return booleanToTypedValue(functions.toString(input).length === 1);
922
+ return booleanToTypedValue(functions.toString(context, input).length === 1);
894
923
  },
895
924
  /**
896
925
  * If the input collection contains a single item, this function will return a single time if:
@@ -908,11 +937,11 @@ const functions = {
908
937
  * If the input collection is empty, the result is empty.
909
938
  *
910
939
  * See: https://hl7.org/fhirpath/#totime-time
911
- *
912
- * @param input
913
- * @returns
940
+ * @param _context The evaluation context.
941
+ * @param input The input collection.
942
+ * @returns The value converted to a time if possible; otherwise empty array.
914
943
  */
915
- toTime: (input) => {
944
+ toTime: (_context, input) => {
916
945
  if (input.length === 0) {
917
946
  return [];
918
947
  }
@@ -937,15 +966,15 @@ const functions = {
937
966
  * If the input collection is empty, the result is empty.
938
967
  *
939
968
  * See: https://hl7.org/fhirpath/#convertstotime-boolean
940
- *
941
- * @param input
942
- * @returns
969
+ * @param context The evaluation context.
970
+ * @param input The input collection.
971
+ * @returns True if the item can be converted to a time.
943
972
  */
944
- convertsToTime: (input) => {
973
+ convertsToTime: (context, input) => {
945
974
  if (input.length === 0) {
946
975
  return [];
947
976
  }
948
- return booleanToTypedValue(functions.toTime(input).length === 1);
977
+ return booleanToTypedValue(functions.toTime(context, input).length === 1);
949
978
  },
950
979
  /*
951
980
  * 5.6. String Manipulation.
@@ -962,12 +991,13 @@ const functions = {
962
991
  * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
963
992
  *
964
993
  * See: https://hl7.org/fhirpath/#indexofsubstring-string-integer
965
- *
994
+ * @param context The evaluation context.
966
995
  * @param input The input collection.
996
+ * @param substringAtom The substring to search for.
967
997
  * @returns The index of the substring.
968
998
  */
969
- indexOf: (input, substringAtom) => {
970
- return applyStringFunc((str, substring) => str.indexOf(substring), input, substringAtom);
999
+ indexOf: (context, input, substringAtom) => {
1000
+ return applyStringFunc((str, substring) => str.indexOf(substring), context, input, substringAtom);
971
1001
  },
972
1002
  /**
973
1003
  * Returns the part of the string starting at position start (zero-based). If length is given, will return at most length number of characters from the input string.
@@ -979,98 +1009,172 @@ const functions = {
979
1009
  * If an empty length is provided, the behavior is the same as if length had not been provided.
980
1010
  *
981
1011
  * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
982
- *
1012
+ * @param context The evaluation context.
983
1013
  * @param input The input collection.
984
- * @returns The index of the substring.
1014
+ * @param startAtom The start index atom.
1015
+ * @param lengthAtom Optional length atom.
1016
+ * @returns The substring.
985
1017
  */
986
- substring: (input, startAtom, lengthAtom) => {
1018
+ substring: (context, input, startAtom, lengthAtom) => {
987
1019
  return applyStringFunc((str, start, length) => {
988
1020
  const startIndex = start;
989
1021
  const endIndex = length ? startIndex + length : str.length;
990
1022
  return startIndex < 0 || startIndex >= str.length ? undefined : str.substring(startIndex, endIndex);
991
- }, input, startAtom, lengthAtom);
1023
+ }, context, input, startAtom, lengthAtom);
992
1024
  },
993
1025
  /**
1026
+ * Returns true when the input string starts with the given prefix.
1027
+ *
1028
+ * If prefix is the empty string (''), the result is true.
1029
+ *
1030
+ * If the input collection is empty, the result is empty.
994
1031
  *
1032
+ * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
1033
+ *
1034
+ * See: https://hl7.org/fhirpath/#startswithprefix-string-boolean
1035
+ * @param context The evaluation context.
995
1036
  * @param input The input collection.
996
- * @returns The index of the substring.
1037
+ * @param prefixAtom The prefix substring to test.
1038
+ * @returns True if the input string starts with the given prefix string.
997
1039
  */
998
- startsWith: (input, prefixAtom) => {
999
- return applyStringFunc((str, prefix) => str.startsWith(prefix), input, prefixAtom);
1040
+ startsWith: (context, input, prefixAtom) => {
1041
+ return applyStringFunc((str, prefix) => str.startsWith(prefix), context, input, prefixAtom);
1000
1042
  },
1001
1043
  /**
1044
+ * Returns true when the input string ends with the given suffix.
1045
+ *
1046
+ * If suffix is the empty string (''), the result is true.
1002
1047
  *
1048
+ * If the input collection is empty, the result is empty.
1049
+ *
1050
+ * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
1051
+ *
1052
+ * See: https://hl7.org/fhirpath/#endswithsuffix-string-boolean
1053
+ * @param context The evaluation context.
1003
1054
  * @param input The input collection.
1004
- * @returns The index of the substring.
1055
+ * @param suffixAtom The suffix substring to test.
1056
+ * @returns True if the input string ends with the given suffix string.
1005
1057
  */
1006
- endsWith: (input, suffixAtom) => {
1007
- return applyStringFunc((str, suffix) => str.endsWith(suffix), input, suffixAtom);
1058
+ endsWith: (context, input, suffixAtom) => {
1059
+ return applyStringFunc((str, suffix) => str.endsWith(suffix), context, input, suffixAtom);
1008
1060
  },
1009
1061
  /**
1062
+ * Returns true when the given substring is a substring of the input string.
1010
1063
  *
1064
+ * If substring is the empty string (''), the result is true.
1065
+ *
1066
+ * If the input collection is empty, the result is empty.
1067
+ *
1068
+ * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
1069
+ *
1070
+ * See: https://hl7.org/fhirpath/#containssubstring-string-boolean
1071
+ * @param context The evaluation context.
1011
1072
  * @param input The input collection.
1012
- * @returns The index of the substring.
1073
+ * @param substringAtom The substring to test.
1074
+ * @returns True if the input string contains the given substring.
1013
1075
  */
1014
- contains: (input, substringAtom) => {
1015
- return applyStringFunc((str, substring) => str.includes(substring), input, substringAtom);
1076
+ contains: (context, input, substringAtom) => {
1077
+ return applyStringFunc((str, substring) => str.includes(substring), context, input, substringAtom);
1016
1078
  },
1017
1079
  /**
1080
+ * Returns the input string with all characters converted to upper case.
1081
+ * If the input collection is empty, the result is empty.
1082
+ *
1083
+ * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
1018
1084
  *
1085
+ * See: https://hl7.org/fhirpath/#upper-string
1086
+ * @param context The evaluation context.
1019
1087
  * @param input The input collection.
1020
- * @returns The index of the substring.
1088
+ * @returns The string converted to upper case.
1021
1089
  */
1022
- upper: (input) => {
1023
- return applyStringFunc((str) => str.toUpperCase(), input);
1090
+ upper: (context, input) => {
1091
+ return applyStringFunc((str) => str.toUpperCase(), context, input);
1024
1092
  },
1025
1093
  /**
1094
+ * Returns the input string with all characters converted to lower case.
1095
+ *
1096
+ * If the input collection is empty, the result is empty.
1026
1097
  *
1098
+ * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
1099
+ *
1100
+ * See: https://hl7.org/fhirpath/#lower-string
1101
+ * @param context The evaluation context.
1027
1102
  * @param input The input collection.
1028
- * @returns The index of the substring.
1103
+ * @returns The string converted to lower case.
1029
1104
  */
1030
- lower: (input) => {
1031
- return applyStringFunc((str) => str.toLowerCase(), input);
1105
+ lower: (context, input) => {
1106
+ return applyStringFunc((str) => str.toLowerCase(), context, input);
1032
1107
  },
1033
1108
  /**
1109
+ * Returns the input string with all instances of pattern replaced with substitution. If the substitution is the empty string (''),
1110
+ * instances of pattern are removed from the result. If pattern is the empty string (''), every character in the input string is
1111
+ * surrounded by the substitution, e.g. 'abc'.replace('','x') becomes 'xaxbxcx'.
1034
1112
  *
1113
+ * If the input collection, pattern, or substitution are empty, the result is empty ({ }).
1114
+ *
1115
+ * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
1116
+ *
1117
+ * See: https://hl7.org/fhirpath/#replacepattern-string-substitution-string-string
1118
+ * @param context The evaluation context.
1035
1119
  * @param input The input collection.
1036
- * @returns The index of the substring.
1120
+ * @param patternAtom The pattern to search for.
1121
+ * @param substitionAtom The substition to replace with.
1122
+ * @returns The string with all instances of the search pattern replaced with the substitution string.
1037
1123
  */
1038
- replace: (input, patternAtom, substitionAtom) => {
1039
- return applyStringFunc((str, pattern, substition) => str.replaceAll(pattern, substition), input, patternAtom, substitionAtom);
1124
+ replace: (context, input, patternAtom, substitionAtom) => {
1125
+ return applyStringFunc((str, pattern, substition) => str.replaceAll(pattern, substition), context, input, patternAtom, substitionAtom);
1040
1126
  },
1041
1127
  /**
1128
+ * Returns true when the value matches the given regular expression. Regular expressions should function consistently, regardless of any culture- and locale-specific settings in the environment, should be case-sensitive, use 'single line' mode and allow Unicode characters.
1042
1129
  *
1130
+ * If the input collection or regex are empty, the result is empty ({ }).
1131
+ *
1132
+ * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
1133
+ *
1134
+ * See: https://hl7.org/fhirpath/#matchesregex-string-boolean
1135
+ * @param context The evaluation context.
1043
1136
  * @param input The input collection.
1044
- * @returns The index of the substring.
1137
+ * @param regexAtom The regular expression atom.
1138
+ * @returns True if the input string matches the given regular expression.
1045
1139
  */
1046
- matches: (input, regexAtom) => {
1047
- return applyStringFunc((str, regex) => !!str.match(regex), input, regexAtom);
1140
+ matches: (context, input, regexAtom) => {
1141
+ return applyStringFunc((str, regex) => !!str.match(regex), context, input, regexAtom);
1048
1142
  },
1049
1143
  /**
1144
+ * Matches the input using the regular expression in regex and replaces each match with the substitution string. The substitution may refer to identified match groups in the regular expression.
1145
+ *
1146
+ * If the input collection, regex, or substitution are empty, the result is empty ({ }).
1147
+ *
1148
+ * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
1050
1149
  *
1150
+ * See: https://hl7.org/fhirpath/#replacematchesregex-string-substitution-string-string
1151
+ * @param context The evaluation context.
1051
1152
  * @param input The input collection.
1052
- * @returns The index of the substring.
1153
+ * @param regexAtom The regular expression atom.
1154
+ * @param substitionAtom The substition to replace with.
1155
+ * @returns The string with all instances of the search pattern replaced with the substitution string.
1053
1156
  */
1054
- replaceMatches: (input, regexAtom, substitionAtom) => {
1055
- return applyStringFunc((str, pattern, substition) => str.replaceAll(pattern, substition), input, regexAtom, substitionAtom);
1157
+ replaceMatches: (context, input, regexAtom, substitionAtom) => {
1158
+ return applyStringFunc((str, pattern, substition) => str.replaceAll(pattern, substition), context, input, regexAtom, substitionAtom);
1056
1159
  },
1057
1160
  /**
1058
- *
1161
+ * @param context The evaluation context.
1059
1162
  * @param input The input collection.
1060
1163
  * @returns The index of the substring.
1061
1164
  */
1062
- length: (input) => {
1063
- return applyStringFunc((str) => str.length, input);
1165
+ length: (context, input) => {
1166
+ return applyStringFunc((str) => str.length, context, input);
1064
1167
  },
1065
1168
  /**
1066
1169
  * Returns the list of characters in the input string. If the input collection is empty ({ }), the result is empty.
1067
1170
  *
1068
1171
  * See: https://hl7.org/fhirpath/#tochars-collection
1069
- *
1172
+ * @param context The evaluation context.
1070
1173
  * @param input The input collection.
1174
+ * @returns Array of characters.
1071
1175
  */
1072
- toChars: (input) => {
1073
- return applyStringFunc((str) => (str ? str.split('') : undefined), input);
1176
+ toChars: (context, input) => {
1177
+ return applyStringFunc((str) => (str ? str.split('') : undefined), context, input);
1074
1178
  },
1075
1179
  /*
1076
1180
  * 5.7. Math
@@ -1083,12 +1187,12 @@ const functions = {
1083
1187
  * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
1084
1188
  *
1085
1189
  * See: https://hl7.org/fhirpath/#abs-integer-decimal-quantity
1086
- *
1190
+ * @param context The evaluation context.
1087
1191
  * @param input The input collection.
1088
1192
  * @returns A collection containing the result.
1089
1193
  */
1090
- abs: (input) => {
1091
- return applyMathFunc(Math.abs, input);
1194
+ abs: (context, input) => {
1195
+ return applyMathFunc(Math.abs, context, input);
1092
1196
  },
1093
1197
  /**
1094
1198
  * Returns the first integer greater than or equal to the input.
@@ -1098,12 +1202,12 @@ const functions = {
1098
1202
  * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
1099
1203
  *
1100
1204
  * See: https://hl7.org/fhirpath/#ceiling-integer
1101
- *
1205
+ * @param context The evaluation context.
1102
1206
  * @param input The input collection.
1103
1207
  * @returns A collection containing the result.
1104
1208
  */
1105
- ceiling: (input) => {
1106
- return applyMathFunc(Math.ceil, input);
1209
+ ceiling: (context, input) => {
1210
+ return applyMathFunc(Math.ceil, context, input);
1107
1211
  },
1108
1212
  /**
1109
1213
  * Returns e raised to the power of the input.
@@ -1115,12 +1219,12 @@ const functions = {
1115
1219
  * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
1116
1220
  *
1117
1221
  * See: https://hl7.org/fhirpath/#exp-decimal
1118
- *
1222
+ * @param context The evaluation context.
1119
1223
  * @param input The input collection.
1120
1224
  * @returns A collection containing the result.
1121
1225
  */
1122
- exp: (input) => {
1123
- return applyMathFunc(Math.exp, input);
1226
+ exp: (context, input) => {
1227
+ return applyMathFunc(Math.exp, context, input);
1124
1228
  },
1125
1229
  /**
1126
1230
  * Returns the first integer less than or equal to the input.
@@ -1130,12 +1234,12 @@ const functions = {
1130
1234
  * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
1131
1235
  *
1132
1236
  * See: https://hl7.org/fhirpath/#floor-integer
1133
- *
1237
+ * @param context The evaluation context.
1134
1238
  * @param input The input collection.
1135
1239
  * @returns A collection containing the result.
1136
1240
  */
1137
- floor: (input) => {
1138
- return applyMathFunc(Math.floor, input);
1241
+ floor: (context, input) => {
1242
+ return applyMathFunc(Math.floor, context, input);
1139
1243
  },
1140
1244
  /**
1141
1245
  * Returns the natural logarithm of the input (i.e. the logarithm base e).
@@ -1147,12 +1251,12 @@ const functions = {
1147
1251
  * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
1148
1252
  *
1149
1253
  * See: https://hl7.org/fhirpath/#ln-decimal
1150
- *
1254
+ * @param context The evaluation context.
1151
1255
  * @param input The input collection.
1152
1256
  * @returns A collection containing the result.
1153
1257
  */
1154
- ln: (input) => {
1155
- return applyMathFunc(Math.log, input);
1258
+ ln: (context, input) => {
1259
+ return applyMathFunc(Math.log, context, input);
1156
1260
  },
1157
1261
  /**
1158
1262
  * Returns the logarithm base base of the input number.
@@ -1166,12 +1270,13 @@ const functions = {
1166
1270
  * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
1167
1271
  *
1168
1272
  * See: https://hl7.org/fhirpath/#logbase-decimal-decimal
1169
- *
1273
+ * @param context The evaluation context.
1170
1274
  * @param input The input collection.
1275
+ * @param baseAtom The logarithm base.
1171
1276
  * @returns A collection containing the result.
1172
1277
  */
1173
- log: (input, baseAtom) => {
1174
- return applyMathFunc((value, base) => Math.log(value) / Math.log(base), input, baseAtom);
1278
+ log: (context, input, baseAtom) => {
1279
+ return applyMathFunc((value, base) => Math.log(value) / Math.log(base), context, input, baseAtom);
1175
1280
  },
1176
1281
  /**
1177
1282
  * Raises a number to the exponent power. If this function is used with Integers, the result is an Integer. If the function is used with Decimals, the result is a Decimal. If the function is used with a mixture of Integer and Decimal, the Integer is implicitly converted to a Decimal and the result is a Decimal.
@@ -1183,12 +1288,13 @@ const functions = {
1183
1288
  * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
1184
1289
  *
1185
1290
  * See: https://hl7.org/fhirpath/#powerexponent-integer-decimal-integer-decimal
1186
- *
1291
+ * @param context The evaluation context.
1187
1292
  * @param input The input collection.
1293
+ * @param expAtom The exponent power.
1188
1294
  * @returns A collection containing the result.
1189
1295
  */
1190
- power: (input, expAtom) => {
1191
- return applyMathFunc(Math.pow, input, expAtom);
1296
+ power: (context, input, expAtom) => {
1297
+ return applyMathFunc(Math.pow, context, input, expAtom);
1192
1298
  },
1193
1299
  /**
1194
1300
  * Rounds the decimal to the nearest whole number using a traditional round (i.e. 0.5 or higher will round to 1). If specified, the precision argument determines the decimal place at which the rounding will occur. If not specified, the rounding will default to 0 decimal places.
@@ -1202,12 +1308,12 @@ const functions = {
1202
1308
  * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
1203
1309
  *
1204
1310
  * See: https://hl7.org/fhirpath/#roundprecision-integer-decimal
1205
- *
1311
+ * @param context The evaluation context.
1206
1312
  * @param input The input collection.
1207
1313
  * @returns A collection containing the result.
1208
1314
  */
1209
- round: (input) => {
1210
- return applyMathFunc(Math.round, input);
1315
+ round: (context, input) => {
1316
+ return applyMathFunc(Math.round, context, input);
1211
1317
  },
1212
1318
  /**
1213
1319
  * Returns the square root of the input number as a Decimal.
@@ -1221,12 +1327,12 @@ const functions = {
1221
1327
  * Note that this function is equivalent to raising a number of the power of 0.5 using the power() function.
1222
1328
  *
1223
1329
  * See: https://hl7.org/fhirpath/#sqrt-decimal
1224
- *
1330
+ * @param context The evaluation context.
1225
1331
  * @param input The input collection.
1226
1332
  * @returns A collection containing the result.
1227
1333
  */
1228
- sqrt: (input) => {
1229
- return applyMathFunc(Math.sqrt, input);
1334
+ sqrt: (context, input) => {
1335
+ return applyMathFunc(Math.sqrt, context, input);
1230
1336
  },
1231
1337
  /**
1232
1338
  * Returns the integer portion of the input.
@@ -1236,12 +1342,12 @@ const functions = {
1236
1342
  * If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.
1237
1343
  *
1238
1344
  * See: https://hl7.org/fhirpath/#truncate-integer
1239
- *
1345
+ * @param context The evaluation context.
1240
1346
  * @param input The input collection.
1241
1347
  * @returns A collection containing the result.
1242
1348
  */
1243
- truncate: (input) => {
1244
- return applyMathFunc((x) => x | 0, input);
1349
+ truncate: (context, input) => {
1350
+ return applyMathFunc((x) => x | 0, context, input);
1245
1351
  },
1246
1352
  /*
1247
1353
  * 5.8. Tree navigation
@@ -1262,11 +1368,12 @@ const functions = {
1262
1368
  * function unchanged.
1263
1369
  *
1264
1370
  * See: https://hl7.org/fhirpath/#tracename-string-projection-expression-collection
1265
- *
1371
+ * @param context The evaluation context.
1266
1372
  * @param input The input collection.
1267
1373
  * @param nameAtom The log name.
1374
+ * @returns The input collection.
1268
1375
  */
1269
- trace: (input, nameAtom) => {
1376
+ trace: (context, input, nameAtom) => {
1270
1377
  console.log('trace', input, nameAtom);
1271
1378
  return input;
1272
1379
  },
@@ -1274,6 +1381,7 @@ const functions = {
1274
1381
  * Returns the current date and time, including timezone offset.
1275
1382
  *
1276
1383
  * See: https://hl7.org/fhirpath/#now-datetime
1384
+ * @returns The current dateTime.
1277
1385
  */
1278
1386
  now: () => {
1279
1387
  return [{ type: PropertyType.dateTime, value: new Date().toISOString() }];
@@ -1282,6 +1390,7 @@ const functions = {
1282
1390
  * Returns the current time.
1283
1391
  *
1284
1392
  * See: https://hl7.org/fhirpath/#timeofday-time
1393
+ * @returns The current time string.
1285
1394
  */
1286
1395
  timeOfDay: () => {
1287
1396
  return [{ type: PropertyType.time, value: new Date().toISOString().substring(11) }];
@@ -1290,6 +1399,7 @@ const functions = {
1290
1399
  * Returns the current date.
1291
1400
  *
1292
1401
  * See: https://hl7.org/fhirpath/#today-date
1402
+ * @returns The current date string.
1293
1403
  */
1294
1404
  today: () => {
1295
1405
  return [{ type: PropertyType.date, value: new Date().toISOString().substring(0, 10) }];
@@ -1301,17 +1411,23 @@ const functions = {
1301
1411
  *
1302
1412
  * IBM FHIR issue: https://github.com/IBM/FHIR/issues/1014
1303
1413
  * IBM FHIR PR: https://github.com/IBM/FHIR/pull/1023
1414
+ * @param context The evaluation context.
1415
+ * @param input The input collection.
1416
+ * @param startAtom The start date/time.
1417
+ * @param endAtom The end date/time.
1418
+ * @param unitsAtom Which units to return ("years", "months", or "days").
1419
+ * @returns The Quantity of time between the two dates.
1304
1420
  */
1305
- between: (input, startAtom, endAtom, unitsAtom) => {
1306
- const startDate = functions.toDateTime(startAtom.eval(input));
1421
+ between: (context, input, startAtom, endAtom, unitsAtom) => {
1422
+ const startDate = functions.toDateTime(context, startAtom.eval(context, input));
1307
1423
  if (startDate.length === 0) {
1308
1424
  throw new Error('Invalid start date');
1309
1425
  }
1310
- const endDate = functions.toDateTime(endAtom.eval(input));
1426
+ const endDate = functions.toDateTime(context, endAtom.eval(context, input));
1311
1427
  if (endDate.length === 0) {
1312
1428
  throw new Error('Invalid end date');
1313
1429
  }
1314
- const unit = unitsAtom.eval(input)[0]?.value;
1430
+ const unit = unitsAtom.eval(context, input)[0]?.value;
1315
1431
  if (unit !== 'years' && unit !== 'months' && unit !== 'days') {
1316
1432
  throw new Error('Invalid units');
1317
1433
  }
@@ -1329,12 +1445,12 @@ const functions = {
1329
1445
  * For implementations with compile-time typing, this requires special-case
1330
1446
  * handling when processing the argument to treat it as a type specifier rather
1331
1447
  * than an identifier expression:
1332
- *
1333
- * @param input
1334
- * @param typeAtom
1335
- * @returns
1448
+ * @param _context The evaluation context.
1449
+ * @param input The input collection.
1450
+ * @param typeAtom The desired type.
1451
+ * @returns True if the input element is of the desired type.
1336
1452
  */
1337
- is: (input, typeAtom) => {
1453
+ is: (_context, input, typeAtom) => {
1338
1454
  let typeName = '';
1339
1455
  if (typeAtom instanceof SymbolAtom) {
1340
1456
  typeName = typeAtom.name;
@@ -1354,12 +1470,12 @@ const functions = {
1354
1470
  * 6.5.3. not() : Boolean
1355
1471
  *
1356
1472
  * Returns true if the input collection evaluates to false, and false if it evaluates to true. Otherwise, the result is empty ({ }):
1357
- *
1358
- * @param input
1359
- * @returns
1473
+ * @param context The evaluation context.
1474
+ * @param input The input collection.
1475
+ * @returns True if the input evaluates to false.
1360
1476
  */
1361
- not: (input) => {
1362
- return functions.toBoolean(input).map((value) => ({ type: PropertyType.boolean, value: !value.value }));
1477
+ not: (context, input) => {
1478
+ return functions.toBoolean(context, input).map((value) => ({ type: PropertyType.boolean, value: !value.value }));
1363
1479
  },
1364
1480
  /*
1365
1481
  * Additional functions
@@ -1368,10 +1484,11 @@ const functions = {
1368
1484
  /**
1369
1485
  * For each item in the collection, if it is a string that is a uri (or canonical or url), locate the target of the reference, and add it to the resulting collection. If the item does not resolve to a resource, the item is ignored and nothing is added to the output collection.
1370
1486
  * The items in the collection may also represent a Reference, in which case the Reference.reference is resolved.
1487
+ * @param _context The evaluation context.
1371
1488
  * @param input The input collection.
1372
- * @returns
1489
+ * @returns The resolved resource.
1373
1490
  */
1374
- resolve: (input) => {
1491
+ resolve: (_context, input) => {
1375
1492
  return input
1376
1493
  .map((e) => {
1377
1494
  const value = e.value;
@@ -1405,10 +1522,11 @@ const functions = {
1405
1522
  },
1406
1523
  /**
1407
1524
  * The as operator can be used to treat a value as a specific type.
1525
+ * @param _context The evaluation context.
1408
1526
  * @param input The input value.
1409
1527
  * @returns The value as the specific type.
1410
1528
  */
1411
- as: (input) => {
1529
+ as: (_context, input) => {
1412
1530
  return input;
1413
1531
  },
1414
1532
  /*
@@ -1424,11 +1542,11 @@ const functions = {
1424
1542
  * https://hl7.org/fhirpath/modelinfo.xsd
1425
1543
  *
1426
1544
  * See: https://hl7.org/fhirpath/#model-information
1427
- *
1545
+ * @param _context The evaluation context.
1428
1546
  * @param input The input collection.
1429
- * @returns
1547
+ * @returns The type of the input value.
1430
1548
  */
1431
- type: (input) => {
1549
+ type: (_context, input) => {
1432
1550
  return input.map(({ value }) => {
1433
1551
  if (typeof value === 'boolean') {
1434
1552
  return { type: PropertyType.BackboneElement, value: { namespace: 'System', name: 'Boolean' } };
@@ -1445,8 +1563,8 @@ const functions = {
1445
1563
  return { type: PropertyType.BackboneElement, value: null };
1446
1564
  });
1447
1565
  },
1448
- conformsTo: (input, systemAtom) => {
1449
- const system = systemAtom.eval(input)[0].value;
1566
+ conformsTo: (context, input, systemAtom) => {
1567
+ const system = systemAtom.eval(context, input)[0].value;
1450
1568
  if (!system.startsWith('http://hl7.org/fhir/StructureDefinition/')) {
1451
1569
  throw new Error('Expected a StructureDefinition URL');
1452
1570
  }
@@ -1460,7 +1578,7 @@ const functions = {
1460
1578
  /*
1461
1579
  * Helper utilities
1462
1580
  */
1463
- function applyStringFunc(func, input, ...argsAtoms) {
1581
+ function applyStringFunc(func, context, input, ...argsAtoms) {
1464
1582
  if (input.length === 0) {
1465
1583
  return [];
1466
1584
  }
@@ -1468,7 +1586,7 @@ function applyStringFunc(func, input, ...argsAtoms) {
1468
1586
  if (typeof value !== 'string') {
1469
1587
  throw new Error('String function cannot be called with non-string');
1470
1588
  }
1471
- const result = func(value, ...argsAtoms.map((atom) => atom && atom.eval(input)?.[0]?.value));
1589
+ const result = func(value, ...argsAtoms.map((atom) => atom && atom.eval(context, input)?.[0]?.value));
1472
1590
  if (result === undefined) {
1473
1591
  return [];
1474
1592
  }
@@ -1477,7 +1595,7 @@ function applyStringFunc(func, input, ...argsAtoms) {
1477
1595
  }
1478
1596
  return [toTypedValue(result)];
1479
1597
  }
1480
- function applyMathFunc(func, input, ...argsAtoms) {
1598
+ function applyMathFunc(func, context, input, ...argsAtoms) {
1481
1599
  if (input.length === 0) {
1482
1600
  return [];
1483
1601
  }
@@ -1487,7 +1605,7 @@ function applyMathFunc(func, input, ...argsAtoms) {
1487
1605
  if (typeof numberInput !== 'number') {
1488
1606
  throw new Error('Math function cannot be called with non-number');
1489
1607
  }
1490
- const result = func(numberInput, ...argsAtoms.map((atom) => atom.eval(input)?.[0]?.value));
1608
+ const result = func(numberInput, ...argsAtoms.map((atom) => atom.eval(context, input)?.[0]?.value));
1491
1609
  const type = quantity ? PropertyType.Quantity : input[0].type;
1492
1610
  const returnValue = quantity ? { ...value, value: result } : result;
1493
1611
  return [{ type, value: returnValue }];