@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
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { ASTNode, Diagnostic, FunctionSignature, TypeInfo, Range } from '../types';
|
|
2
|
+
import { DiagnosticSeverity } from '../types';
|
|
3
|
+
|
|
4
|
+
/** Formats a TypeInfo into a user-facing string (e.g., Integer, Decimal[]). */
|
|
5
|
+
export function formatType(t: TypeInfo): string {
|
|
6
|
+
const base = t.type;
|
|
7
|
+
return t.singleton ? base : `${base}[]`;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Determines if a type should be treated as an empty collection for diagnostics.
|
|
12
|
+
* Mirrors existing analyzer semantics: consider explicit isEmpty or Any-collections as empty.
|
|
13
|
+
*/
|
|
14
|
+
export function isEmptyCollection(t: TypeInfo | undefined): boolean {
|
|
15
|
+
if (!t) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
return t.isEmpty === true || (t.type === 'Any' && t.singleton === false);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Returns true if the type carries a union modelContext with choices. */
|
|
22
|
+
export function isUnionType(type: TypeInfo | undefined): boolean {
|
|
23
|
+
const mc: any = type?.modelContext;
|
|
24
|
+
return !!(mc && typeof mc === 'object' && 'isUnion' in mc && mc.isUnion && Array.isArray(mc.choices));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Returns union choice identifiers (type or code) if union; otherwise empty list. */
|
|
28
|
+
export function getUnionChoices(type: TypeInfo | undefined): string[] {
|
|
29
|
+
const mc: any = type?.modelContext;
|
|
30
|
+
if (!mc || !Array.isArray(mc.choices)) {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
return mc.choices
|
|
34
|
+
.map((c: any) => c?.type ?? c?.code)
|
|
35
|
+
.filter((t: unknown): t is string => typeof t === 'string' && t.length > 0);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* If target is not present in the union choices, returns a Warning diagnostic with given code.
|
|
40
|
+
* Otherwise returns null.
|
|
41
|
+
*/
|
|
42
|
+
export function validateUnionChoice(
|
|
43
|
+
type: TypeInfo,
|
|
44
|
+
targetType: string | undefined,
|
|
45
|
+
range: Range,
|
|
46
|
+
code: string,
|
|
47
|
+
messagePrefix: string
|
|
48
|
+
): Diagnostic | null {
|
|
49
|
+
if (!targetType || !isUnionType(type)) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
const choices = getUnionChoices(type);
|
|
53
|
+
if (choices.length === 0) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
if (choices.includes(targetType)) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
severity: DiagnosticSeverity.Warning,
|
|
61
|
+
code,
|
|
62
|
+
message: `${messagePrefix} '${targetType}' is not present in the union type. Available types: ${choices.join(', ')}`,
|
|
63
|
+
range,
|
|
64
|
+
source: 'fhirpath',
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Checks parameter types against a signature and returns diagnostics.
|
|
70
|
+
* - Skips expression parameters.
|
|
71
|
+
* - Treats Decimal-expected vs Integer-actual as compatible.
|
|
72
|
+
* - Emits warnings for empty collections when allowed and function propagates empty.
|
|
73
|
+
*/
|
|
74
|
+
export function checkParamTypes(
|
|
75
|
+
sig: FunctionSignature,
|
|
76
|
+
argTypes: TypeInfo[],
|
|
77
|
+
nodes: ASTNode[],
|
|
78
|
+
opts: {
|
|
79
|
+
warnOnSingletonOnly: boolean;
|
|
80
|
+
doesNotPropagateEmpty: boolean;
|
|
81
|
+
treatEmptyAsWarning?: boolean;
|
|
82
|
+
errorCode?: string;
|
|
83
|
+
}
|
|
84
|
+
): Diagnostic[] {
|
|
85
|
+
const diags: Diagnostic[] = [];
|
|
86
|
+
const params = sig.parameters || [];
|
|
87
|
+
for (let i = 0; i < params.length; i++) {
|
|
88
|
+
const param = params[i];
|
|
89
|
+
const arg = argTypes[i];
|
|
90
|
+
const node = (nodes[i] ?? nodes[0])!;
|
|
91
|
+
if (!param || !arg || param.expression) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (
|
|
96
|
+
isEmptyCollection(arg) &&
|
|
97
|
+
!opts.doesNotPropagateEmpty &&
|
|
98
|
+
opts.treatEmptyAsWarning !== false
|
|
99
|
+
) {
|
|
100
|
+
diags.push({
|
|
101
|
+
range: node.range,
|
|
102
|
+
severity: DiagnosticSeverity.Warning,
|
|
103
|
+
message: `Argument ${i + 1}: expected ${formatType(param.type)}, got empty collection. Result will be empty.`,
|
|
104
|
+
source: 'fhirpath',
|
|
105
|
+
code: opts.errorCode,
|
|
106
|
+
});
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const typeMatch =
|
|
111
|
+
param.type.type === 'Any' ||
|
|
112
|
+
arg.type === 'Any' ||
|
|
113
|
+
param.type.type === arg.type ||
|
|
114
|
+
(param.type.type === 'Decimal' && arg.type === 'Integer');
|
|
115
|
+
const singletonMatch = !param.type.singleton || arg.singleton === true;
|
|
116
|
+
|
|
117
|
+
if (!typeMatch || !singletonMatch) {
|
|
118
|
+
const msg = `Argument ${i + 1}: expected ${formatType(param.type)}, got ${formatType(arg)}`;
|
|
119
|
+
const severity = typeMatch && !singletonMatch && opts.warnOnSingletonOnly
|
|
120
|
+
? DiagnosticSeverity.Warning
|
|
121
|
+
: DiagnosticSeverity.Error;
|
|
122
|
+
diags.push({
|
|
123
|
+
range: node.range,
|
|
124
|
+
severity,
|
|
125
|
+
message: msg,
|
|
126
|
+
source: 'fhirpath',
|
|
127
|
+
code: opts.errorCode,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return diags;
|
|
132
|
+
}
|