@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
@@ -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
- // Union merges collections and eliminates duplicates using equals (=) operator
11
+ // '|' deduplicates using equals (=) semantics
10
12
  const result: any[] = [];
11
- const seen = new Set<any>();
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
- // Use equals operator semantics for duplicate detection
18
- if (existing === item) {
19
- isDuplicate = true;
20
- break;
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
- if (!isDuplicate) {
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
- let isDuplicate = false;
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 any duplicate values using the equals (=) operator. There is no expectation of order in the resulting collection',
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
  }