@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
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { OperatorDefinition } from '../types';
|
|
2
2
|
import { PRECEDENCE } from '../types';
|
|
3
3
|
import type { OperationEvaluator } from '../types';
|
|
4
|
-
import type { QuantityValue } from '../quantity-value';
|
|
5
|
-
import { box, unbox } from '../boxing';
|
|
4
|
+
import type { QuantityValue } from '../complex-types/quantity-value';
|
|
5
|
+
import { box, unbox } from '../interpreter/boxing';
|
|
6
6
|
|
|
7
7
|
export const evaluate: OperationEvaluator = async (input, context, operand) => {
|
|
8
8
|
// Unary minus negates each boxed value
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { OperatorDefinition } from '../types';
|
|
2
2
|
import { PRECEDENCE } from '../types';
|
|
3
3
|
import type { OperationEvaluator } from '../types';
|
|
4
|
-
import { box, unbox } from '../boxing';
|
|
4
|
+
import { box, unbox } from '../interpreter/boxing';
|
|
5
5
|
|
|
6
6
|
export const evaluate: OperationEvaluator = async (input, context, operand) => {
|
|
7
7
|
// Unary plus returns the operand as-is
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { FunctionDefinition, FunctionEvaluator } from '../types';
|
|
2
2
|
import { Errors } from '../errors';
|
|
3
|
-
import { box, unbox } from '../boxing';
|
|
3
|
+
import { box, unbox } from '../interpreter/boxing';
|
|
4
4
|
|
|
5
5
|
export const evaluate: FunctionEvaluator = async (input, context, args, evaluator) => {
|
|
6
6
|
if (args.length !== 1) {
|
|
@@ -1,45 +1,35 @@
|
|
|
1
1
|
import type { OperatorDefinition } from '../types';
|
|
2
2
|
import { PRECEDENCE } from '../types';
|
|
3
3
|
import type { OperationEvaluator } from '../types';
|
|
4
|
-
import { box, unbox } from '../boxing';
|
|
4
|
+
import { box, unbox } from '../interpreter/boxing';
|
|
5
|
+
import { evaluate as equalsEvaluate } from './equal-operator';
|
|
6
|
+
import { Errors } from '../errors';
|
|
5
7
|
|
|
6
8
|
// Note: The union operator is special and is typically handled directly in the interpreter
|
|
7
9
|
// because it needs to preserve the original context for both operands
|
|
8
10
|
export const evaluate: OperationEvaluator = async (input, context, left, right) => {
|
|
9
|
-
//
|
|
11
|
+
// '|' deduplicates using equals (=) semantics
|
|
10
12
|
const result: any[] = [];
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
// Add items from left collection
|
|
14
|
-
for (const item of left) {
|
|
15
|
-
let isDuplicate = false;
|
|
13
|
+
const isDup = async (candidate: any): Promise<boolean> => {
|
|
16
14
|
for (const existing of result) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
const eq = await equalsEvaluate(input, context, [existing], [candidate]);
|
|
16
|
+
const v = eq.value[0];
|
|
17
|
+
if (v && typeof v.value === 'boolean' && v.value === true) {
|
|
18
|
+
return true;
|
|
21
19
|
}
|
|
22
20
|
}
|
|
23
|
-
|
|
21
|
+
return false;
|
|
22
|
+
};
|
|
23
|
+
for (const item of left) {
|
|
24
|
+
if (!(await isDup(item))) {
|
|
24
25
|
result.push(item);
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
|
-
|
|
28
|
-
// Add items from right collection if not already present
|
|
29
28
|
for (const item of right) {
|
|
30
|
-
|
|
31
|
-
for (const existing of result) {
|
|
32
|
-
// Use equals operator semantics for duplicate detection
|
|
33
|
-
if (existing === item) {
|
|
34
|
-
isDuplicate = true;
|
|
35
|
-
break;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
if (!isDuplicate) {
|
|
29
|
+
if (!(await isDup(item))) {
|
|
39
30
|
result.push(item);
|
|
40
31
|
}
|
|
41
32
|
}
|
|
42
|
-
|
|
43
33
|
return { value: result, context };
|
|
44
34
|
};
|
|
45
35
|
|
|
@@ -49,7 +39,7 @@ export const unionOperator: OperatorDefinition & { evaluate: OperationEvaluator
|
|
|
49
39
|
category: ['collection'],
|
|
50
40
|
precedence: PRECEDENCE.PIPE,
|
|
51
41
|
associativity: 'left',
|
|
52
|
-
description: 'Merges two collections into a single collection, eliminating
|
|
42
|
+
description: 'Merges two collections into a single collection, eliminating duplicates using equals (=) semantics. Order is not guaranteed.',
|
|
53
43
|
examples: [
|
|
54
44
|
'name.given | name.family',
|
|
55
45
|
'Patient.identifier | Patient.contact.identifier',
|
|
@@ -65,4 +55,4 @@ export const unionOperator: OperatorDefinition & { evaluate: OperationEvaluator
|
|
|
65
55
|
}
|
|
66
56
|
],
|
|
67
57
|
evaluate
|
|
68
|
-
};
|
|
58
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { FunctionDefinition, FunctionEvaluator } from '../types';
|
|
2
2
|
import { Errors } from '../errors';
|
|
3
|
-
import { box, unbox } from '../boxing';
|
|
3
|
+
import { box, unbox } from '../interpreter/boxing';
|
|
4
4
|
|
|
5
5
|
export const evaluate: FunctionEvaluator = async (input, context, args, evaluator) => {
|
|
6
6
|
// Handle empty input collection
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { FunctionDefinition, ASTNode } from '../types';
|
|
2
|
-
import { RuntimeContextManager } from '../interpreter';
|
|
2
|
+
import { RuntimeContextManager } from '../interpreter/runtime-context';
|
|
3
3
|
import { type FunctionEvaluator } from '../types';
|
|
4
|
-
import { unbox } from '../boxing';
|
|
4
|
+
import { unbox } from '../interpreter/boxing';
|
|
5
5
|
|
|
6
6
|
export const evaluate: FunctionEvaluator = async (input, context, args, evaluator) => {
|
|
7
7
|
// If no condition provided, return input as-is
|
|
@@ -58,4 +58,4 @@ export const whereFunction: FunctionDefinition & { evaluate: FunctionEvaluator }
|
|
|
58
58
|
result: 'inputType' as any,
|
|
59
59
|
}],
|
|
60
60
|
evaluate
|
|
61
|
-
};
|
|
61
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { OperatorDefinition } from '../types';
|
|
2
2
|
import { PRECEDENCE } from '../types';
|
|
3
3
|
import type { OperationEvaluator } from '../types';
|
|
4
|
-
import { box, unbox } from '../boxing';
|
|
4
|
+
import { box, unbox } from '../interpreter/boxing';
|
|
5
5
|
|
|
6
6
|
export const evaluate: OperationEvaluator = async (input, context, left, right) => {
|
|
7
7
|
// Three-valued logic for XOR
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// yearOf() function - Extracts year component from Date or DateTime
|
|
2
|
+
import type { FunctionDefinition, FunctionEvaluator } from '../types';
|
|
3
|
+
import { box, unbox } from '../interpreter/boxing';
|
|
4
|
+
import { isFHIRDate, isFHIRDateTime } from '../complex-types/temporal';
|
|
5
|
+
import { Errors } from '../errors';
|
|
6
|
+
|
|
7
|
+
export const yearOfEvaluator: FunctionEvaluator = async (input, context, args) => {
|
|
8
|
+
// yearOf() takes no arguments
|
|
9
|
+
if (args.length !== 0) {
|
|
10
|
+
throw Errors.wrongArgumentCount('yearOf', 0, args.length);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Empty input returns empty
|
|
14
|
+
if (input.length === 0) {
|
|
15
|
+
return { value: [], context };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Multiple items throws error
|
|
19
|
+
if (input.length > 1) {
|
|
20
|
+
throw Errors.singletonRequired('yearOf', input.length);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const boxedValue = input[0];
|
|
24
|
+
if (!boxedValue) {
|
|
25
|
+
return { value: [], context };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const value = unbox(boxedValue);
|
|
29
|
+
|
|
30
|
+
// Check if it's a Date or DateTime
|
|
31
|
+
if (isFHIRDate(value) || isFHIRDateTime(value)) {
|
|
32
|
+
// Check if year component is present
|
|
33
|
+
if (value.year === undefined) {
|
|
34
|
+
return { value: [], context };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Return the year as an Integer
|
|
38
|
+
return {
|
|
39
|
+
value: [box(value.year, { type: 'Integer', singleton: true })],
|
|
40
|
+
context
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Not a Date or DateTime, return empty
|
|
45
|
+
return { value: [], context };
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const yearOfFunction: FunctionDefinition & { evaluate: typeof yearOfEvaluator } = {
|
|
49
|
+
name: 'yearOf',
|
|
50
|
+
category: ['temporal'],
|
|
51
|
+
description: 'Returns the year component of a Date or DateTime value',
|
|
52
|
+
examples: [
|
|
53
|
+
'@2014-01-05.yearOf()',
|
|
54
|
+
'@2014-01-05T10:30:00.yearOf()',
|
|
55
|
+
'Patient.birthDate.yearOf()'
|
|
56
|
+
],
|
|
57
|
+
signatures: [
|
|
58
|
+
{
|
|
59
|
+
name: 'yearOf',
|
|
60
|
+
input: { type: 'Any', singleton: true },
|
|
61
|
+
parameters: [],
|
|
62
|
+
result: { type: 'Integer', singleton: true }
|
|
63
|
+
}
|
|
64
|
+
],
|
|
65
|
+
evaluate: yearOfEvaluator
|
|
66
|
+
};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { BaseASTNode } from '../types';
|
|
2
|
+
|
|
1
3
|
export enum CursorContext {
|
|
2
4
|
Operator = 'operator',
|
|
3
5
|
Identifier = 'identifier',
|
|
@@ -6,14 +8,10 @@ export enum CursorContext {
|
|
|
6
8
|
Type = 'type',
|
|
7
9
|
}
|
|
8
10
|
|
|
9
|
-
export interface CursorNode {
|
|
11
|
+
export interface CursorNode extends BaseASTNode {
|
|
10
12
|
type: 'CursorNode';
|
|
11
13
|
context: CursorContext;
|
|
12
14
|
position: number;
|
|
13
|
-
range: {
|
|
14
|
-
start: { line: number; character: number; offset: number };
|
|
15
|
-
end: { line: number; character: number; offset: number };
|
|
16
|
-
};
|
|
17
15
|
}
|
|
18
16
|
|
|
19
17
|
export interface CursorOperatorNode extends CursorNode {
|
|
@@ -22,6 +20,7 @@ export interface CursorOperatorNode extends CursorNode {
|
|
|
22
20
|
|
|
23
21
|
export interface CursorIdentifierNode extends CursorNode {
|
|
24
22
|
context: CursorContext.Identifier;
|
|
23
|
+
partialText?: string;
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
export interface CursorArgumentNode extends CursorNode {
|
|
@@ -37,6 +36,7 @@ export interface CursorIndexNode extends CursorNode {
|
|
|
37
36
|
export interface CursorTypeNode extends CursorNode {
|
|
38
37
|
context: CursorContext.Type;
|
|
39
38
|
typeOperator: 'is' | 'as' | 'ofType';
|
|
39
|
+
partialText?: string;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export type AnyCursorNode =
|
|
@@ -60,12 +60,13 @@ export function createCursorOperatorNode(position: number): CursorOperatorNode {
|
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
export function createCursorIdentifierNode(position: number): CursorIdentifierNode {
|
|
63
|
+
export function createCursorIdentifierNode(position: number, partialText?: string): CursorIdentifierNode {
|
|
64
64
|
const point = { line: 0, character: position, offset: position };
|
|
65
65
|
return {
|
|
66
66
|
type: 'CursorNode',
|
|
67
67
|
context: CursorContext.Identifier,
|
|
68
68
|
position,
|
|
69
|
+
partialText,
|
|
69
70
|
range: { start: point, end: point },
|
|
70
71
|
};
|
|
71
72
|
}
|
|
@@ -98,7 +99,8 @@ export function createCursorIndexNode(position: number): CursorIndexNode {
|
|
|
98
99
|
|
|
99
100
|
export function createCursorTypeNode(
|
|
100
101
|
position: number,
|
|
101
|
-
typeOperator: 'is' | 'as' | 'ofType'
|
|
102
|
+
typeOperator: 'is' | 'as' | 'ofType',
|
|
103
|
+
partialText?: string
|
|
102
104
|
): CursorTypeNode {
|
|
103
105
|
const point = { line: 0, character: position, offset: position };
|
|
104
106
|
return {
|
|
@@ -106,6 +108,7 @@ export function createCursorTypeNode(
|
|
|
106
108
|
context: CursorContext.Type,
|
|
107
109
|
position,
|
|
108
110
|
typeOperator,
|
|
111
|
+
partialText,
|
|
109
112
|
range: { start: point, end: point },
|
|
110
113
|
};
|
|
111
114
|
}
|