@atomic-ehr/fhirpath 0.0.2 → 0.0.3

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 (143) hide show
  1. package/README.md +716 -238
  2. package/dist/index.d.ts +225 -119
  3. package/dist/index.js +10911 -5600
  4. package/dist/index.js.map +1 -1
  5. package/package.json +9 -4
  6. package/src/analyzer/augmentor.ts +242 -0
  7. package/src/analyzer/cursor-services.ts +75 -0
  8. package/src/analyzer/scope-manager.ts +57 -0
  9. package/src/analyzer/trivia-indexer.ts +58 -0
  10. package/src/analyzer/type-compat.ts +157 -0
  11. package/src/analyzer/utils.ts +132 -0
  12. package/src/analyzer.ts +921 -1208
  13. package/src/completion-provider.ts +209 -191
  14. package/src/{quantity-value.ts → complex-types/quantity-value.ts} +112 -22
  15. package/src/complex-types/temporal.ts +1737 -0
  16. package/src/errors.ts +25 -3
  17. package/src/index.ts +17 -104
  18. package/src/inspect.ts +4 -4
  19. package/src/{boxing.ts → interpreter/boxing.ts} +1 -1
  20. package/src/interpreter/navigator.ts +94 -0
  21. package/src/interpreter/runtime-context.ts +273 -0
  22. package/src/interpreter.ts +435 -469
  23. package/src/lexer.ts +188 -210
  24. package/src/model-provider.ts +71 -43
  25. package/src/operations/abs-function.ts +1 -1
  26. package/src/operations/aggregate-function.ts +84 -5
  27. package/src/operations/all-function.ts +4 -3
  28. package/src/operations/allFalse-function.ts +2 -1
  29. package/src/operations/allTrue-function.ts +2 -1
  30. package/src/operations/and-operator.ts +2 -1
  31. package/src/operations/anyFalse-function.ts +2 -1
  32. package/src/operations/anyTrue-function.ts +2 -1
  33. package/src/operations/as-function.ts +58 -0
  34. package/src/operations/as-operator.ts +57 -19
  35. package/src/operations/ceiling-function.ts +1 -1
  36. package/src/operations/children-function.ts +14 -5
  37. package/src/operations/combine-function.ts +6 -3
  38. package/src/operations/combine-operator.ts +6 -7
  39. package/src/operations/comparison.ts +692 -0
  40. package/src/operations/contains-function.ts +1 -1
  41. package/src/operations/contains-operator.ts +2 -1
  42. package/src/operations/convertsToBoolean-function.ts +78 -0
  43. package/src/operations/convertsToDecimal-function.ts +82 -0
  44. package/src/operations/convertsToInteger-function.ts +71 -0
  45. package/src/operations/convertsToLong-function.ts +89 -0
  46. package/src/operations/convertsToQuantity-function.ts +116 -0
  47. package/src/operations/convertsToString-function.ts +88 -0
  48. package/src/operations/count-function.ts +2 -1
  49. package/src/operations/dateOf-function.ts +69 -0
  50. package/src/operations/dayOf-function.ts +66 -0
  51. package/src/operations/decimal-boundaries.ts +133 -0
  52. package/src/operations/defineVariable-function.ts +130 -17
  53. package/src/operations/distinct-function.ts +1 -1
  54. package/src/operations/div-operator.ts +1 -1
  55. package/src/operations/divide-operator.ts +12 -7
  56. package/src/operations/dot-operator.ts +1 -1
  57. package/src/operations/empty-function.ts +30 -21
  58. package/src/operations/endsWith-function.ts +6 -1
  59. package/src/operations/equal-operator.ts +23 -32
  60. package/src/operations/equivalent-operator.ts +13 -53
  61. package/src/operations/exclude-function.ts +2 -1
  62. package/src/operations/exists-function.ts +4 -3
  63. package/src/operations/first-function.ts +1 -1
  64. package/src/operations/floor-function.ts +1 -1
  65. package/src/operations/greater-operator.ts +20 -3
  66. package/src/operations/greater-or-equal-operator.ts +20 -3
  67. package/src/operations/highBoundary-function.ts +120 -0
  68. package/src/operations/hourOf-function.ts +66 -0
  69. package/src/operations/iif-function.ts +186 -7
  70. package/src/operations/implies-operator.ts +1 -1
  71. package/src/operations/in-operator.ts +2 -1
  72. package/src/operations/index.ts +41 -0
  73. package/src/operations/indexOf-function.ts +1 -1
  74. package/src/operations/intersect-function.ts +1 -1
  75. package/src/operations/is-function.ts +59 -0
  76. package/src/operations/is-operator.ts +20 -9
  77. package/src/operations/isDistinct-function.ts +2 -1
  78. package/src/operations/join-function.ts +1 -1
  79. package/src/operations/last-function.ts +1 -1
  80. package/src/operations/lastIndexOf-function.ts +85 -0
  81. package/src/operations/length-function.ts +1 -1
  82. package/src/operations/less-operator.ts +20 -3
  83. package/src/operations/less-or-equal-operator.ts +20 -3
  84. package/src/operations/less-than.ts +2 -2
  85. package/src/operations/lowBoundary-function.ts +120 -0
  86. package/src/operations/lower-function.ts +1 -1
  87. package/src/operations/matches-function.ts +86 -0
  88. package/src/operations/matchesFull-function.ts +96 -0
  89. package/src/operations/millisecondOf-function.ts +66 -0
  90. package/src/operations/minus-operator.ts +69 -4
  91. package/src/operations/minuteOf-function.ts +66 -0
  92. package/src/operations/mod-operator.ts +1 -1
  93. package/src/operations/monthOf-function.ts +66 -0
  94. package/src/operations/multiply-operator.ts +27 -3
  95. package/src/operations/not-equal-operator.ts +24 -30
  96. package/src/operations/not-equivalent-operator.ts +13 -53
  97. package/src/operations/not-function.ts +1 -1
  98. package/src/operations/ofType-function.ts +8 -12
  99. package/src/operations/or-operator.ts +2 -1
  100. package/src/operations/plus-operator.ts +71 -7
  101. package/src/operations/power-function.ts +35 -10
  102. package/src/operations/repeat-function.ts +169 -0
  103. package/src/operations/replace-function.ts +1 -1
  104. package/src/operations/replaceMatches-function.ts +120 -0
  105. package/src/operations/round-function.ts +1 -1
  106. package/src/operations/secondOf-function.ts +66 -0
  107. package/src/operations/select-function.ts +66 -5
  108. package/src/operations/single-function.ts +1 -1
  109. package/src/operations/skip-function.ts +1 -1
  110. package/src/operations/split-function.ts +1 -1
  111. package/src/operations/sqrt-function.ts +15 -8
  112. package/src/operations/startsWith-function.ts +1 -1
  113. package/src/operations/subsetOf-function.ts +6 -2
  114. package/src/operations/substring-function.ts +1 -1
  115. package/src/operations/supersetOf-function.ts +6 -2
  116. package/src/operations/tail-function.ts +1 -1
  117. package/src/operations/take-function.ts +1 -1
  118. package/src/operations/temporal-functions.ts +555 -0
  119. package/src/operations/timeOf-function.ts +67 -0
  120. package/src/operations/timezoneOffsetOf-function.ts +69 -0
  121. package/src/operations/toBoolean-function.ts +27 -8
  122. package/src/operations/toChars-function.ts +56 -0
  123. package/src/operations/toDecimal-function.ts +27 -8
  124. package/src/operations/toInteger-function.ts +15 -3
  125. package/src/operations/toLong-function.ts +98 -0
  126. package/src/operations/toQuantity-function.ts +181 -0
  127. package/src/operations/toString-function.ts +45 -3
  128. package/src/operations/trace-function.ts +1 -1
  129. package/src/operations/trim-function.ts +1 -1
  130. package/src/operations/truncate-function.ts +1 -1
  131. package/src/operations/unary-minus-operator.ts +2 -2
  132. package/src/operations/unary-plus-operator.ts +1 -1
  133. package/src/operations/union-function.ts +1 -1
  134. package/src/operations/union-operator.ts +16 -26
  135. package/src/operations/upper-function.ts +1 -1
  136. package/src/operations/where-function.ts +3 -3
  137. package/src/operations/xor-operator.ts +1 -1
  138. package/src/operations/yearOf-function.ts +66 -0
  139. package/src/{cursor-nodes.ts → parser/cursor-nodes.ts} +10 -7
  140. package/src/parser.ts +248 -501
  141. package/src/registry.ts +53 -42
  142. package/src/types.ts +128 -16
  143. package/src/utils/pprint.ts +151 -0
@@ -11,35 +11,27 @@ export interface QuantityValue {
11
11
  }
12
12
 
13
13
  /**
14
- * Calendar duration unit to UCUM unit mapping
14
+ * Calendar duration units used in FHIRPath
15
+ * These are NOT UCUM units and should not be converted
15
16
  */
16
- export const CALENDAR_TO_UCUM: Record<string, string> = {
17
- 'year': 'a', // annum
18
- 'years': 'a',
19
- 'month': 'mo', // month
20
- 'months': 'mo',
21
- 'week': 'wk', // week
22
- 'weeks': 'wk',
23
- 'day': 'd', // day
24
- 'days': 'd',
25
- 'hour': 'h', // hour
26
- 'hours': 'h',
27
- 'minute': 'min', // minute
28
- 'minutes': 'min',
29
- 'second': 's', // second
30
- 'seconds': 's',
31
- 'millisecond': 'ms', // millisecond
32
- 'milliseconds': 'ms'
33
- };
17
+ export const CALENDAR_DURATION_UNITS = new Set([
18
+ 'year', 'years',
19
+ 'month', 'months',
20
+ 'week', 'weeks',
21
+ 'day', 'days',
22
+ 'hour', 'hours',
23
+ 'minute', 'minutes',
24
+ 'second', 'seconds',
25
+ 'millisecond', 'milliseconds'
26
+ ]);
34
27
 
35
28
  /**
36
29
  * Create a quantity value
37
30
  */
38
- export function createQuantity(value: number, unit: string, isCalendarUnit: boolean = false): QuantityValue {
39
- const actualUnit = isCalendarUnit && CALENDAR_TO_UCUM[unit] ? CALENDAR_TO_UCUM[unit] : unit;
31
+ export function createQuantity(value: number, unit: string): QuantityValue {
40
32
  return {
41
33
  value,
42
- unit: actualUnit
34
+ unit
43
35
  };
44
36
  }
45
37
 
@@ -47,6 +39,11 @@ export function createQuantity(value: number, unit: string, isCalendarUnit: bool
47
39
  * Get or create the UCUM quantity for a QuantityValue
48
40
  */
49
41
  export function getUcumQuantity(quantity: QuantityValue): Quantity | null {
42
+ // Calendar duration units are not UCUM units
43
+ if (CALENDAR_DURATION_UNITS.has(quantity.unit)) {
44
+ return null;
45
+ }
46
+
50
47
  if (!quantity._ucumQuantity) {
51
48
  try {
52
49
  quantity._ucumQuantity = ucum.quantity(quantity.value, quantity.unit);
@@ -60,8 +57,14 @@ export function getUcumQuantity(quantity: QuantityValue): Quantity | null {
60
57
 
61
58
  /**
62
59
  * Check if a quantity has a valid unit
60
+ * Valid units are either UCUM units or calendar duration units
63
61
  */
64
62
  export function isValidQuantity(quantity: QuantityValue): boolean {
63
+ // Calendar duration units are valid FHIRPath quantities
64
+ if (CALENDAR_DURATION_UNITS.has(quantity.unit)) {
65
+ return true;
66
+ }
67
+ // Otherwise check if it's a valid UCUM unit
65
68
  return getUcumQuantity(quantity) !== null;
66
69
  }
67
70
 
@@ -69,6 +72,19 @@ export function isValidQuantity(quantity: QuantityValue): boolean {
69
72
  * Add two quantities
70
73
  */
71
74
  export function addQuantities(left: QuantityValue, right: QuantityValue): QuantityValue | null {
75
+ // Special case: adding calendar durations with the same unit
76
+ if (CALENDAR_DURATION_UNITS.has(left.unit) && left.unit === right.unit) {
77
+ return {
78
+ value: left.value + right.value,
79
+ unit: left.unit
80
+ };
81
+ }
82
+
83
+ // Different calendar units cannot be added
84
+ if (CALENDAR_DURATION_UNITS.has(left.unit) || CALENDAR_DURATION_UNITS.has(right.unit)) {
85
+ return null;
86
+ }
87
+
72
88
  const leftUcum = getUcumQuantity(left);
73
89
  const rightUcum = getUcumQuantity(right);
74
90
 
@@ -92,6 +108,19 @@ export function addQuantities(left: QuantityValue, right: QuantityValue): Quanti
92
108
  * Subtract two quantities
93
109
  */
94
110
  export function subtractQuantities(left: QuantityValue, right: QuantityValue): QuantityValue | null {
111
+ // Special case: subtracting calendar durations with the same unit
112
+ if (CALENDAR_DURATION_UNITS.has(left.unit) && left.unit === right.unit) {
113
+ return {
114
+ value: left.value - right.value,
115
+ unit: left.unit
116
+ };
117
+ }
118
+
119
+ // Different calendar units cannot be subtracted
120
+ if (CALENDAR_DURATION_UNITS.has(left.unit) || CALENDAR_DURATION_UNITS.has(right.unit)) {
121
+ return null;
122
+ }
123
+
95
124
  const leftUcum = getUcumQuantity(left);
96
125
  const rightUcum = getUcumQuantity(right);
97
126
 
@@ -115,6 +144,34 @@ export function subtractQuantities(left: QuantityValue, right: QuantityValue): Q
115
144
  * Multiply two quantities
116
145
  */
117
146
  export function multiplyQuantities(left: QuantityValue, right: QuantityValue): QuantityValue | null {
147
+ // Special case: multiplying calendar duration by a dimensionless number
148
+ // e.g., 1 year * 2 = 2 years, or 2 * 1 year = 2 years
149
+ if (CALENDAR_DURATION_UNITS.has(left.unit) && right.unit === '1') {
150
+ // Calendar duration * number
151
+ return {
152
+ value: left.value * right.value,
153
+ unit: left.unit
154
+ };
155
+ }
156
+ if (CALENDAR_DURATION_UNITS.has(right.unit) && left.unit === '1') {
157
+ // Number * calendar duration
158
+ return {
159
+ value: left.value * right.value,
160
+ unit: right.unit
161
+ };
162
+ }
163
+
164
+ // Check if both are calendar duration units - this is not allowed
165
+ if (CALENDAR_DURATION_UNITS.has(left.unit) && CALENDAR_DURATION_UNITS.has(right.unit)) {
166
+ // Calendar duration units cannot be multiplied together - the result would be meaningless
167
+ throw new Error(`Cannot multiply calendar duration units: ${left.unit} * ${right.unit}`);
168
+ }
169
+
170
+ // Mixed calendar and non-calendar units are not allowed
171
+ if (CALENDAR_DURATION_UNITS.has(left.unit) || CALENDAR_DURATION_UNITS.has(right.unit)) {
172
+ throw new Error(`Cannot multiply calendar duration with non-calendar units: ${left.unit} * ${right.unit}`);
173
+ }
174
+
118
175
  const leftUcum = getUcumQuantity(left);
119
176
  const rightUcum = getUcumQuantity(right);
120
177
 
@@ -137,6 +194,23 @@ export function multiplyQuantities(left: QuantityValue, right: QuantityValue): Q
137
194
  * Divide two quantities
138
195
  */
139
196
  export function divideQuantities(left: QuantityValue, right: QuantityValue): QuantityValue | null {
197
+ // Special case: dividing calendar duration by a dimensionless number
198
+ // e.g., 10 months / 2 = 5 months
199
+ if (CALENDAR_DURATION_UNITS.has(left.unit) && right.unit === '1') {
200
+ // Calendar duration / number
201
+ return {
202
+ value: left.value / right.value,
203
+ unit: left.unit
204
+ };
205
+ }
206
+
207
+ // Division of number by calendar duration is not allowed
208
+ // Division of two calendar durations is not allowed
209
+ if (CALENDAR_DURATION_UNITS.has(left.unit) || CALENDAR_DURATION_UNITS.has(right.unit)) {
210
+ // Calendar duration units cannot be divided except by dimensionless numbers
211
+ throw new Error(`Cannot divide calendar duration units: ${left.unit} / ${right.unit}`);
212
+ }
213
+
140
214
  const leftUcum = getUcumQuantity(left);
141
215
  const rightUcum = getUcumQuantity(right);
142
216
 
@@ -160,6 +234,22 @@ export function divideQuantities(left: QuantityValue, right: QuantityValue): Qua
160
234
  * Returns -1 if left < right, 0 if equal, 1 if left > right, null if incomparable
161
235
  */
162
236
  export function compareQuantities(left: QuantityValue, right: QuantityValue): number | null {
237
+ // Special case: comparing calendar durations with the same unit
238
+ if (CALENDAR_DURATION_UNITS.has(left.unit) && left.unit === right.unit) {
239
+ if (left.value < right.value) {
240
+ return -1;
241
+ } else if (left.value > right.value) {
242
+ return 1;
243
+ } else {
244
+ return 0;
245
+ }
246
+ }
247
+
248
+ // Different calendar units cannot be compared
249
+ if (CALENDAR_DURATION_UNITS.has(left.unit) || CALENDAR_DURATION_UNITS.has(right.unit)) {
250
+ return null;
251
+ }
252
+
163
253
  const leftUcum = getUcumQuantity(left);
164
254
  const rightUcum = getUcumQuantity(right);
165
255