@atomic-ehr/fhirpath 0.0.1-canary.0c6931e.20250727185306
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 +473 -0
- package/dist/index.d.ts +462 -0
- package/dist/index.js +10307 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -0
- package/src/analyzer/analyzer.ts +499 -0
- package/src/analyzer/model-provider.ts +244 -0
- package/src/analyzer/schemas/index.ts +2 -0
- package/src/analyzer/schemas/types.ts +40 -0
- package/src/analyzer/types.ts +142 -0
- package/src/api/builder.ts +157 -0
- package/src/api/errors.ts +145 -0
- package/src/api/expression.ts +156 -0
- package/src/api/index.ts +122 -0
- package/src/api/inspect.ts +99 -0
- package/src/api/registry.ts +128 -0
- package/src/api/types.ts +210 -0
- package/src/compiler/compiler.ts +546 -0
- package/src/compiler/index.ts +2 -0
- package/src/compiler/prototype-context-adapter.ts +99 -0
- package/src/compiler/types.ts +24 -0
- package/src/index.ts +107 -0
- package/src/interpreter/README.md +78 -0
- package/src/interpreter/interpreter.ts +475 -0
- package/src/interpreter/types.ts +108 -0
- package/src/lexer/char-tables.ts +37 -0
- package/src/lexer/errors.ts +31 -0
- package/src/lexer/index.ts +5 -0
- package/src/lexer/lexer.ts +745 -0
- package/src/lexer/token.ts +104 -0
- package/src/lexer2/index.md +232 -0
- package/src/lexer2/index.perf.test.ts +68 -0
- package/src/lexer2/index.test.ts +549 -0
- package/src/lexer2/index.ts +1251 -0
- package/src/lexer2/notes.md +173 -0
- package/src/lexer2/optimization-summary.md +718 -0
- package/src/parser/ast-factory.ts +220 -0
- package/src/parser/ast.ts +144 -0
- package/src/parser/collection-parser.ts +89 -0
- package/src/parser/diagnostic-messages.ts +216 -0
- package/src/parser/diagnostics.ts +85 -0
- package/src/parser/error-reporter.ts +230 -0
- package/src/parser/index.ts +3 -0
- package/src/parser/literal-parser.ts +103 -0
- package/src/parser/parse-error.ts +16 -0
- package/src/parser/parser-error-factory.ts +141 -0
- package/src/parser/parser-state.ts +134 -0
- package/src/parser/parser.ts +1272 -0
- package/src/parser/pprint.ts +169 -0
- package/src/parser/precedence-manager.ts +64 -0
- package/src/parser/source-mapper.ts +248 -0
- package/src/parser/special-constructs.ts +142 -0
- package/src/parser/token-navigator.ts +110 -0
- package/src/parser/types.ts +60 -0
- package/src/parser2/index.md +177 -0
- package/src/parser2/index.perf.test.ts +184 -0
- package/src/parser2/index.test.ts +305 -0
- package/src/parser2/index.ts +578 -0
- package/src/parser2/optimization-summary.md +176 -0
- package/src/registry/default-analyzers.ts +257 -0
- package/src/registry/default-compilers.ts +31 -0
- package/src/registry/index.ts +96 -0
- package/src/registry/operations/arithmetic.ts +506 -0
- package/src/registry/operations/collection.ts +425 -0
- package/src/registry/operations/comparison.ts +432 -0
- package/src/registry/operations/existence.ts +703 -0
- package/src/registry/operations/filtering.ts +358 -0
- package/src/registry/operations/literals.ts +341 -0
- package/src/registry/operations/logical.ts +439 -0
- package/src/registry/operations/math.ts +128 -0
- package/src/registry/operations/membership.ts +132 -0
- package/src/registry/operations/navigation.ts +52 -0
- package/src/registry/operations/string.ts +507 -0
- package/src/registry/operations/subsetting.ts +174 -0
- package/src/registry/operations/type-checking.ts +162 -0
- package/src/registry/operations/type-conversion.ts +404 -0
- package/src/registry/operations/type-operators.ts +308 -0
- package/src/registry/operations/utility.ts +644 -0
- package/src/registry/registry.ts +146 -0
- package/src/registry/types.ts +161 -0
- package/src/registry/utils/evaluation-helpers.ts +93 -0
- package/src/registry/utils/index.ts +3 -0
- package/src/registry/utils/type-system.ts +173 -0
- package/src/runtime/context.ts +158 -0
- package/src/runtime/debug-context.ts +135 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* Unified runtime context that works with both interpreter and compiler.
|
|
4
|
+
* Uses prototype-based inheritance for efficient context copying.
|
|
5
|
+
*
|
|
6
|
+
* Variable Storage Convention:
|
|
7
|
+
* - Special variables: $this, $index, $total (prefixed with $)
|
|
8
|
+
* - Environment variables: %context, %resource, %rootResource (stored with % prefix)
|
|
9
|
+
* - User-defined variables: stored with % prefix (e.g., %x, %y)
|
|
10
|
+
*/
|
|
11
|
+
export interface RuntimeContext {
|
|
12
|
+
input: any[];
|
|
13
|
+
focus: any[];
|
|
14
|
+
variables: Record<string, any>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Runtime context manager that provides efficient prototype-based context operations
|
|
19
|
+
* for both interpreter and compiler.
|
|
20
|
+
*/
|
|
21
|
+
export class RuntimeContextManager {
|
|
22
|
+
/**
|
|
23
|
+
* Create a new runtime context
|
|
24
|
+
*/
|
|
25
|
+
static create(input: any[], initialVariables?: Record<string, any>): RuntimeContext {
|
|
26
|
+
const context = Object.create(null) as RuntimeContext;
|
|
27
|
+
|
|
28
|
+
context.input = input;
|
|
29
|
+
context.focus = input;
|
|
30
|
+
|
|
31
|
+
// Create variables object with null prototype to avoid pollution
|
|
32
|
+
context.variables = Object.create(null);
|
|
33
|
+
|
|
34
|
+
// Set root context variables with % prefix
|
|
35
|
+
context.variables['%context'] = input;
|
|
36
|
+
context.variables['%resource'] = input;
|
|
37
|
+
context.variables['%rootResource'] = input;
|
|
38
|
+
|
|
39
|
+
// Add any initial variables (with % prefix for user-defined)
|
|
40
|
+
if (initialVariables) {
|
|
41
|
+
for (const [key, value] of Object.entries(initialVariables)) {
|
|
42
|
+
// Add % prefix if not already present and not a special variable
|
|
43
|
+
const varKey = key.startsWith('$') || key.startsWith('%') ? key : `%${key}`;
|
|
44
|
+
context.variables[varKey] = value;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return context;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Create a child context using prototype inheritance
|
|
53
|
+
* O(1) operation - no copying needed
|
|
54
|
+
*/
|
|
55
|
+
static copy(context: RuntimeContext): RuntimeContext {
|
|
56
|
+
// Create child context with parent as prototype
|
|
57
|
+
const newContext = Object.create(context) as RuntimeContext;
|
|
58
|
+
|
|
59
|
+
// Create child variables that inherit from parent's variables
|
|
60
|
+
newContext.variables = Object.create(context.variables);
|
|
61
|
+
|
|
62
|
+
// input and focus are inherited through prototype chain
|
|
63
|
+
// Only set them if they need to change
|
|
64
|
+
|
|
65
|
+
return newContext;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Create a new context with updated input/focus
|
|
70
|
+
*/
|
|
71
|
+
static withInput(context: RuntimeContext, input: any[], focus?: any[]): RuntimeContext {
|
|
72
|
+
const newContext = this.copy(context);
|
|
73
|
+
newContext.input = input;
|
|
74
|
+
newContext.focus = focus ?? input;
|
|
75
|
+
return newContext;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Set special variable ($this, $index, $total)
|
|
80
|
+
*/
|
|
81
|
+
static setSpecialVariable(context: RuntimeContext, name: string, value: any): RuntimeContext {
|
|
82
|
+
const newContext = this.copy(context);
|
|
83
|
+
const varKey = `$${name}`;
|
|
84
|
+
newContext.variables[varKey] = value;
|
|
85
|
+
|
|
86
|
+
// Update input/focus for $this
|
|
87
|
+
if (name === 'this' && Array.isArray(value) && value.length === 1) {
|
|
88
|
+
newContext.input = value;
|
|
89
|
+
newContext.focus = value;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return newContext;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Set iterator context ($this, $index)
|
|
97
|
+
*/
|
|
98
|
+
static withIterator(
|
|
99
|
+
context: RuntimeContext,
|
|
100
|
+
item: any,
|
|
101
|
+
index: number
|
|
102
|
+
): RuntimeContext {
|
|
103
|
+
let newContext = this.setSpecialVariable(context, 'this', [item]);
|
|
104
|
+
newContext = this.setSpecialVariable(newContext, 'index', index);
|
|
105
|
+
return newContext;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Set a user-defined variable in the context
|
|
110
|
+
*/
|
|
111
|
+
static setVariable(context: RuntimeContext, name: string, value: any[], allowRedefinition: boolean = false): RuntimeContext {
|
|
112
|
+
// Check for system variables
|
|
113
|
+
const systemVariables = ['context', 'resource', 'rootResource', 'ucum', 'sct', 'loinc'];
|
|
114
|
+
if (systemVariables.includes(name)) {
|
|
115
|
+
// Silently return original context for system variable redefinition
|
|
116
|
+
return context;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Add % prefix for user-defined variables
|
|
120
|
+
const varKey = name.startsWith('%') ? name : `%${name}`;
|
|
121
|
+
|
|
122
|
+
// Check if variable already exists (unless redefinition is allowed)
|
|
123
|
+
if (!allowRedefinition && context.variables && Object.prototype.hasOwnProperty.call(context.variables, varKey)) {
|
|
124
|
+
// Silently return original context for variable redefinition
|
|
125
|
+
return context;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const newContext = this.copy(context);
|
|
129
|
+
newContext.variables[varKey] = value;
|
|
130
|
+
return newContext;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Get a variable from context
|
|
135
|
+
*/
|
|
136
|
+
static getVariable(context: RuntimeContext, name: string): any | undefined {
|
|
137
|
+
// Handle special cases
|
|
138
|
+
if (name === '$this' || name === '$index' || name === '$total') {
|
|
139
|
+
return context.variables[name];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Handle environment variables (with or without % prefix)
|
|
143
|
+
if (name === 'context' || name === '%context') {
|
|
144
|
+
return context.variables['%context'];
|
|
145
|
+
}
|
|
146
|
+
if (name === 'resource' || name === '%resource') {
|
|
147
|
+
return context.variables['%resource'];
|
|
148
|
+
}
|
|
149
|
+
if (name === 'rootResource' || name === '%rootResource') {
|
|
150
|
+
return context.variables['%rootResource'];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Handle user-defined variables (add % prefix if not present)
|
|
154
|
+
const varKey = name.startsWith('%') ? name : `%${name}`;
|
|
155
|
+
return context.variables[varKey];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import type { RuntimeContext } from './context';
|
|
2
|
+
import type { TraceEntry, EvaluationStep, InspectOptions } from '../api/types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Debug-enabled runtime context that extends RuntimeContext
|
|
6
|
+
* with debugging capabilities for inspect() function
|
|
7
|
+
*/
|
|
8
|
+
export interface DebugRuntimeContext extends RuntimeContext {
|
|
9
|
+
debugMode: true;
|
|
10
|
+
traces: TraceEntry[];
|
|
11
|
+
steps?: EvaluationStep[];
|
|
12
|
+
startTime: number;
|
|
13
|
+
callStack: CallStackEntry[];
|
|
14
|
+
inspectOptions?: InspectOptions;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface CallStackEntry {
|
|
18
|
+
expression: string;
|
|
19
|
+
nodeType: string;
|
|
20
|
+
timestamp: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Check if a context is a debug context
|
|
25
|
+
*/
|
|
26
|
+
export function isDebugContext(context: RuntimeContext): context is DebugRuntimeContext {
|
|
27
|
+
return 'debugMode' in context && context.debugMode === true;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Create a debug context from a regular context
|
|
32
|
+
*/
|
|
33
|
+
export function createDebugContext(
|
|
34
|
+
context: RuntimeContext,
|
|
35
|
+
options?: InspectOptions
|
|
36
|
+
): DebugRuntimeContext {
|
|
37
|
+
const debugContext = Object.create(context) as DebugRuntimeContext;
|
|
38
|
+
debugContext.debugMode = true;
|
|
39
|
+
debugContext.traces = [];
|
|
40
|
+
debugContext.startTime = performance.now();
|
|
41
|
+
debugContext.callStack = [];
|
|
42
|
+
debugContext.inspectOptions = options;
|
|
43
|
+
|
|
44
|
+
if (options?.recordSteps) {
|
|
45
|
+
debugContext.steps = [];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return debugContext;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Add a trace entry to the debug context
|
|
53
|
+
*/
|
|
54
|
+
export function addTrace(
|
|
55
|
+
context: DebugRuntimeContext,
|
|
56
|
+
name: string,
|
|
57
|
+
values: any[]
|
|
58
|
+
): void {
|
|
59
|
+
// Check trace limit
|
|
60
|
+
if (context.inspectOptions?.maxTraces &&
|
|
61
|
+
context.traces.length >= context.inspectOptions.maxTraces) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const trace: TraceEntry = {
|
|
66
|
+
name,
|
|
67
|
+
values,
|
|
68
|
+
timestamp: performance.now() - context.startTime,
|
|
69
|
+
depth: context.callStack.length
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
context.traces.push(trace);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Record an evaluation step
|
|
77
|
+
*/
|
|
78
|
+
export function recordStep(
|
|
79
|
+
context: DebugRuntimeContext,
|
|
80
|
+
nodeType: string,
|
|
81
|
+
expression: string,
|
|
82
|
+
input: any[],
|
|
83
|
+
output: any[]
|
|
84
|
+
): void {
|
|
85
|
+
if (!context.steps) return;
|
|
86
|
+
|
|
87
|
+
// Check step limit
|
|
88
|
+
if (context.inspectOptions?.maxSteps &&
|
|
89
|
+
context.steps.length >= context.inspectOptions.maxSteps) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const stepStart = performance.now();
|
|
94
|
+
|
|
95
|
+
const step: EvaluationStep = {
|
|
96
|
+
nodeType,
|
|
97
|
+
expression,
|
|
98
|
+
input,
|
|
99
|
+
output,
|
|
100
|
+
variables: { ...context.variables }, // Snapshot current variables
|
|
101
|
+
timestamp: stepStart - context.startTime,
|
|
102
|
+
duration: 0 // Will be calculated when step completes
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
context.steps.push(step);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Push an entry onto the call stack
|
|
110
|
+
*/
|
|
111
|
+
export function pushCallStack(
|
|
112
|
+
context: DebugRuntimeContext,
|
|
113
|
+
expression: string,
|
|
114
|
+
nodeType: string
|
|
115
|
+
): void {
|
|
116
|
+
context.callStack.push({
|
|
117
|
+
expression,
|
|
118
|
+
nodeType,
|
|
119
|
+
timestamp: performance.now() - context.startTime
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Pop an entry from the call stack
|
|
125
|
+
*/
|
|
126
|
+
export function popCallStack(context: DebugRuntimeContext): void {
|
|
127
|
+
context.callStack.pop();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Get the current call stack depth
|
|
132
|
+
*/
|
|
133
|
+
export function getCallDepth(context: DebugRuntimeContext): number {
|
|
134
|
+
return context.callStack.length;
|
|
135
|
+
}
|