@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.
- package/README.md +716 -238
- package/dist/index.d.ts +225 -119
- package/dist/index.js +10911 -5600
- package/dist/index.js.map +1 -1
- package/package.json +9 -4
- package/src/analyzer/augmentor.ts +242 -0
- package/src/analyzer/cursor-services.ts +75 -0
- package/src/analyzer/scope-manager.ts +57 -0
- package/src/analyzer/trivia-indexer.ts +58 -0
- package/src/analyzer/type-compat.ts +157 -0
- package/src/analyzer/utils.ts +132 -0
- package/src/analyzer.ts +921 -1208
- package/src/completion-provider.ts +209 -191
- package/src/{quantity-value.ts → complex-types/quantity-value.ts} +112 -22
- package/src/complex-types/temporal.ts +1737 -0
- package/src/errors.ts +25 -3
- package/src/index.ts +17 -104
- package/src/inspect.ts +4 -4
- package/src/{boxing.ts → interpreter/boxing.ts} +1 -1
- package/src/interpreter/navigator.ts +94 -0
- package/src/interpreter/runtime-context.ts +273 -0
- package/src/interpreter.ts +435 -469
- package/src/lexer.ts +188 -210
- package/src/model-provider.ts +71 -43
- package/src/operations/abs-function.ts +1 -1
- package/src/operations/aggregate-function.ts +84 -5
- package/src/operations/all-function.ts +4 -3
- package/src/operations/allFalse-function.ts +2 -1
- package/src/operations/allTrue-function.ts +2 -1
- package/src/operations/and-operator.ts +2 -1
- package/src/operations/anyFalse-function.ts +2 -1
- package/src/operations/anyTrue-function.ts +2 -1
- package/src/operations/as-function.ts +58 -0
- package/src/operations/as-operator.ts +57 -19
- package/src/operations/ceiling-function.ts +1 -1
- package/src/operations/children-function.ts +14 -5
- package/src/operations/combine-function.ts +6 -3
- package/src/operations/combine-operator.ts +6 -7
- package/src/operations/comparison.ts +692 -0
- package/src/operations/contains-function.ts +1 -1
- package/src/operations/contains-operator.ts +2 -1
- package/src/operations/convertsToBoolean-function.ts +78 -0
- package/src/operations/convertsToDecimal-function.ts +82 -0
- package/src/operations/convertsToInteger-function.ts +71 -0
- package/src/operations/convertsToLong-function.ts +89 -0
- package/src/operations/convertsToQuantity-function.ts +116 -0
- package/src/operations/convertsToString-function.ts +88 -0
- package/src/operations/count-function.ts +2 -1
- package/src/operations/dateOf-function.ts +69 -0
- package/src/operations/dayOf-function.ts +66 -0
- package/src/operations/decimal-boundaries.ts +133 -0
- package/src/operations/defineVariable-function.ts +130 -17
- package/src/operations/distinct-function.ts +1 -1
- package/src/operations/div-operator.ts +1 -1
- package/src/operations/divide-operator.ts +12 -7
- package/src/operations/dot-operator.ts +1 -1
- package/src/operations/empty-function.ts +30 -21
- package/src/operations/endsWith-function.ts +6 -1
- package/src/operations/equal-operator.ts +23 -32
- package/src/operations/equivalent-operator.ts +13 -53
- package/src/operations/exclude-function.ts +2 -1
- package/src/operations/exists-function.ts +4 -3
- package/src/operations/first-function.ts +1 -1
- package/src/operations/floor-function.ts +1 -1
- package/src/operations/greater-operator.ts +20 -3
- package/src/operations/greater-or-equal-operator.ts +20 -3
- package/src/operations/highBoundary-function.ts +120 -0
- package/src/operations/hourOf-function.ts +66 -0
- package/src/operations/iif-function.ts +186 -7
- package/src/operations/implies-operator.ts +1 -1
- package/src/operations/in-operator.ts +2 -1
- package/src/operations/index.ts +41 -0
- package/src/operations/indexOf-function.ts +1 -1
- package/src/operations/intersect-function.ts +1 -1
- package/src/operations/is-function.ts +59 -0
- package/src/operations/is-operator.ts +20 -9
- package/src/operations/isDistinct-function.ts +2 -1
- package/src/operations/join-function.ts +1 -1
- package/src/operations/last-function.ts +1 -1
- package/src/operations/lastIndexOf-function.ts +85 -0
- package/src/operations/length-function.ts +1 -1
- package/src/operations/less-operator.ts +20 -3
- package/src/operations/less-or-equal-operator.ts +20 -3
- package/src/operations/less-than.ts +2 -2
- package/src/operations/lowBoundary-function.ts +120 -0
- package/src/operations/lower-function.ts +1 -1
- package/src/operations/matches-function.ts +86 -0
- package/src/operations/matchesFull-function.ts +96 -0
- package/src/operations/millisecondOf-function.ts +66 -0
- package/src/operations/minus-operator.ts +69 -4
- package/src/operations/minuteOf-function.ts +66 -0
- package/src/operations/mod-operator.ts +1 -1
- package/src/operations/monthOf-function.ts +66 -0
- package/src/operations/multiply-operator.ts +27 -3
- package/src/operations/not-equal-operator.ts +24 -30
- package/src/operations/not-equivalent-operator.ts +13 -53
- package/src/operations/not-function.ts +1 -1
- package/src/operations/ofType-function.ts +8 -12
- package/src/operations/or-operator.ts +2 -1
- package/src/operations/plus-operator.ts +71 -7
- package/src/operations/power-function.ts +35 -10
- package/src/operations/repeat-function.ts +169 -0
- package/src/operations/replace-function.ts +1 -1
- package/src/operations/replaceMatches-function.ts +120 -0
- package/src/operations/round-function.ts +1 -1
- package/src/operations/secondOf-function.ts +66 -0
- package/src/operations/select-function.ts +66 -5
- package/src/operations/single-function.ts +1 -1
- package/src/operations/skip-function.ts +1 -1
- package/src/operations/split-function.ts +1 -1
- package/src/operations/sqrt-function.ts +15 -8
- package/src/operations/startsWith-function.ts +1 -1
- package/src/operations/subsetOf-function.ts +6 -2
- package/src/operations/substring-function.ts +1 -1
- package/src/operations/supersetOf-function.ts +6 -2
- package/src/operations/tail-function.ts +1 -1
- package/src/operations/take-function.ts +1 -1
- package/src/operations/temporal-functions.ts +555 -0
- package/src/operations/timeOf-function.ts +67 -0
- package/src/operations/timezoneOffsetOf-function.ts +69 -0
- package/src/operations/toBoolean-function.ts +27 -8
- package/src/operations/toChars-function.ts +56 -0
- package/src/operations/toDecimal-function.ts +27 -8
- package/src/operations/toInteger-function.ts +15 -3
- package/src/operations/toLong-function.ts +98 -0
- package/src/operations/toQuantity-function.ts +181 -0
- package/src/operations/toString-function.ts +45 -3
- package/src/operations/trace-function.ts +1 -1
- package/src/operations/trim-function.ts +1 -1
- package/src/operations/truncate-function.ts +1 -1
- package/src/operations/unary-minus-operator.ts +2 -2
- package/src/operations/unary-plus-operator.ts +1 -1
- package/src/operations/union-function.ts +1 -1
- package/src/operations/union-operator.ts +16 -26
- package/src/operations/upper-function.ts +1 -1
- package/src/operations/where-function.ts +3 -3
- package/src/operations/xor-operator.ts +1 -1
- package/src/operations/yearOf-function.ts +66 -0
- package/src/{cursor-nodes.ts → parser/cursor-nodes.ts} +10 -7
- package/src/parser.ts +248 -501
- package/src/registry.ts +53 -42
- package/src/types.ts +128 -16
- package/src/utils/pprint.ts +151 -0
|
@@ -11,35 +11,27 @@ export interface QuantityValue {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* Calendar duration
|
|
14
|
+
* Calendar duration units used in FHIRPath
|
|
15
|
+
* These are NOT UCUM units and should not be converted
|
|
15
16
|
*/
|
|
16
|
-
export const
|
|
17
|
-
'year'
|
|
18
|
-
'
|
|
19
|
-
'
|
|
20
|
-
'
|
|
21
|
-
'
|
|
22
|
-
'
|
|
23
|
-
'
|
|
24
|
-
'
|
|
25
|
-
|
|
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
|
|
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
|
|
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
|
|