@atomic-ehr/fhirpath 0.0.1-canary.69eb286.20250724163205

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 (56) hide show
  1. package/README.md +307 -0
  2. package/dist/index.d.ts +225 -0
  3. package/dist/index.js +8256 -0
  4. package/dist/index.js.map +1 -0
  5. package/package.json +51 -0
  6. package/src/analyzer/analyzer.ts +486 -0
  7. package/src/analyzer/model-provider.ts +244 -0
  8. package/src/analyzer/schemas/index.ts +2 -0
  9. package/src/analyzer/schemas/types.ts +40 -0
  10. package/src/analyzer/types.ts +142 -0
  11. package/src/api/builder.ts +148 -0
  12. package/src/api/errors.ts +134 -0
  13. package/src/api/expression.ts +149 -0
  14. package/src/api/index.ts +57 -0
  15. package/src/api/registry.ts +128 -0
  16. package/src/api/types.ts +154 -0
  17. package/src/compiler/compiler.ts +589 -0
  18. package/src/compiler/index.ts +2 -0
  19. package/src/compiler/types.ts +23 -0
  20. package/src/index.ts +52 -0
  21. package/src/interpreter/README.md +78 -0
  22. package/src/interpreter/context.ts +181 -0
  23. package/src/interpreter/interpreter.ts +484 -0
  24. package/src/interpreter/types.ts +132 -0
  25. package/src/lexer/char-tables.ts +37 -0
  26. package/src/lexer/errors.ts +31 -0
  27. package/src/lexer/index.ts +5 -0
  28. package/src/lexer/lexer.ts +745 -0
  29. package/src/lexer/token.ts +104 -0
  30. package/src/parser/ast.ts +123 -0
  31. package/src/parser/index.ts +3 -0
  32. package/src/parser/parser.ts +701 -0
  33. package/src/parser/pprint.ts +169 -0
  34. package/src/registry/default-analyzers.ts +257 -0
  35. package/src/registry/default-compilers.ts +31 -0
  36. package/src/registry/index.ts +93 -0
  37. package/src/registry/operations/arithmetic.ts +506 -0
  38. package/src/registry/operations/collection.ts +422 -0
  39. package/src/registry/operations/comparison.ts +432 -0
  40. package/src/registry/operations/existence.ts +719 -0
  41. package/src/registry/operations/filtering.ts +374 -0
  42. package/src/registry/operations/literals.ts +341 -0
  43. package/src/registry/operations/logical.ts +402 -0
  44. package/src/registry/operations/math.ts +128 -0
  45. package/src/registry/operations/membership.ts +132 -0
  46. package/src/registry/operations/string.ts +507 -0
  47. package/src/registry/operations/subsetting.ts +174 -0
  48. package/src/registry/operations/type-checking.ts +162 -0
  49. package/src/registry/operations/type-conversion.ts +404 -0
  50. package/src/registry/operations/type-operators.ts +307 -0
  51. package/src/registry/operations/utility.ts +553 -0
  52. package/src/registry/registry.ts +146 -0
  53. package/src/registry/types.ts +162 -0
  54. package/src/registry/utils/evaluation-helpers.ts +93 -0
  55. package/src/registry/utils/index.ts +3 -0
  56. package/src/registry/utils/type-system.ts +173 -0
@@ -0,0 +1,589 @@
1
+ import type {
2
+ ASTNode,
3
+ LiteralNode,
4
+ IdentifierNode,
5
+ VariableNode,
6
+ BinaryNode,
7
+ UnaryNode,
8
+ FunctionNode,
9
+ CollectionNode,
10
+ IndexNode,
11
+ UnionNode,
12
+ MembershipTestNode,
13
+ TypeCastNode,
14
+ TypeReferenceNode,
15
+ TypeOrIdentifierNode
16
+ } from '../parser/ast';
17
+ import { NodeType } from '../parser/ast';
18
+ import { TokenType } from '../lexer/token';
19
+ import type { CompiledNode } from './types';
20
+ import type { Context, EvaluationResult } from '../interpreter/types';
21
+ import { EvaluationError, CollectionUtils } from '../interpreter/types';
22
+ import { ContextManager } from '../interpreter/context';
23
+ import { isTruthy, toSingleton } from '../registry/utils';
24
+ import type { Compiler as ICompiler, CompiledExpression, TypeRef, RuntimeContext } from '../registry/types';
25
+ // Import the global registry to ensure all operations are registered
26
+ import '../registry';
27
+ import { Registry } from '../registry';
28
+
29
+ /**
30
+ * FHIRPath to JavaScript Closure Compiler
31
+ *
32
+ * Transforms FHIRPath AST nodes into JavaScript functions that implement
33
+ * the same stream-processing semantics as the interpreter.
34
+ */
35
+ export class Compiler implements ICompiler {
36
+ /**
37
+ * Main entry point - compiles an AST into an executable function
38
+ */
39
+ compile(node: ASTNode, input?: CompiledExpression): CompiledExpression {
40
+ const compiled = this.compileNode(node);
41
+
42
+ // Wrap the compiled function to ensure $this is set
43
+ return {
44
+ ...compiled,
45
+ fn: (ctx: RuntimeContext) => {
46
+ // Ensure $this is set if not already present
47
+ if (!ctx.env?.$this) {
48
+ ctx = {
49
+ ...ctx,
50
+ env: {
51
+ ...ctx.env,
52
+ $this: ctx.input
53
+ }
54
+ };
55
+ }
56
+ return compiled.fn(ctx);
57
+ }
58
+ };
59
+ }
60
+
61
+ /**
62
+ * Resolve a type name to a TypeRef
63
+ */
64
+ resolveType(typeName: string): TypeRef {
65
+ // For now, return a simple type reference
66
+ // In the future, this should use a model provider
67
+ return { type: typeName } as TypeRef;
68
+ }
69
+
70
+ /**
71
+ * Dispatches to specific compilation methods based on node type
72
+ */
73
+ private compileNode(node: ASTNode): CompiledExpression {
74
+ switch (node.type) {
75
+ case NodeType.Literal:
76
+ return this.compileLiteral(node as LiteralNode);
77
+ case NodeType.Identifier:
78
+ return this.compileIdentifier(node as IdentifierNode);
79
+ case NodeType.TypeOrIdentifier:
80
+ return this.compileTypeOrIdentifier(node as TypeOrIdentifierNode);
81
+ case NodeType.Variable:
82
+ return this.compileVariable(node as VariableNode);
83
+ case NodeType.Binary:
84
+ return this.compileBinary(node as BinaryNode);
85
+ case NodeType.Unary:
86
+ return this.compileUnary(node as UnaryNode);
87
+ case NodeType.Function:
88
+ return this.compileFunction(node as FunctionNode);
89
+ case NodeType.Collection:
90
+ return this.compileCollection(node as CollectionNode);
91
+ case NodeType.Index:
92
+ return this.compileIndex(node as IndexNode);
93
+ case NodeType.Union:
94
+ return this.compileUnion(node as UnionNode);
95
+ case NodeType.MembershipTest:
96
+ return this.compileMembershipTest(node as MembershipTestNode);
97
+ case NodeType.TypeCast:
98
+ return this.compileTypeCast(node as TypeCastNode);
99
+ case NodeType.TypeReference:
100
+ return this.compileTypeReference(node as TypeReferenceNode);
101
+ default:
102
+ throw new EvaluationError(
103
+ `Unknown node type: ${(node as any).type}`,
104
+ node.position
105
+ );
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Compiles a literal node - returns a constant value
111
+ */
112
+ private compileLiteral(node: LiteralNode): CompiledExpression {
113
+ const value = node.value;
114
+
115
+ // Check if literal is an operation reference
116
+ if (typeof value === 'string') {
117
+ const operation = Registry.get(value);
118
+ if (operation && operation.kind === 'literal') {
119
+ return operation.compile(this, { fn: () => [], type: this.resolveType('Any'), isSingleton: false }, []);
120
+ }
121
+ }
122
+
123
+ // Return a compiled expression for the literal value
124
+ return {
125
+ fn: (ctx: RuntimeContext) => value === null ? [] : [value],
126
+ type: this.resolveType(this.getLiteralType(value)),
127
+ isSingleton: true,
128
+ source: JSON.stringify(value)
129
+ };
130
+ }
131
+
132
+ private getLiteralType(value: any): string {
133
+ if (value === null || value === undefined) return 'Any';
134
+ if (typeof value === 'boolean') return 'Boolean';
135
+ if (typeof value === 'string') return 'String';
136
+ if (typeof value === 'number') {
137
+ return Number.isInteger(value) ? 'Integer' : 'Decimal';
138
+ }
139
+ return 'Any';
140
+ }
141
+
142
+ /**
143
+ * Compiles an identifier node - performs property navigation
144
+ */
145
+ private compileIdentifier(node: IdentifierNode): CompiledExpression {
146
+ const name = node.name;
147
+
148
+ return {
149
+ fn: (ctx: RuntimeContext) => {
150
+ const input = ctx.focus || ctx.input || [];
151
+ const results: any[] = [];
152
+
153
+ for (const item of input) {
154
+ if (item == null || typeof item !== 'object') {
155
+ continue;
156
+ }
157
+
158
+ const value = item[name];
159
+ if (value !== undefined) {
160
+ if (Array.isArray(value)) {
161
+ results.push(...value);
162
+ } else {
163
+ results.push(value);
164
+ }
165
+ }
166
+ }
167
+
168
+ return results;
169
+ },
170
+ type: this.resolveType('Any'), // Would need type inference in a real implementation
171
+ isSingleton: false,
172
+ source: name
173
+ };
174
+ }
175
+
176
+ /**
177
+ * Compiles a TypeOrIdentifier node - handles both type filtering and property navigation
178
+ */
179
+ private compileTypeOrIdentifier(node: TypeOrIdentifierNode): CompiledExpression {
180
+ const name = node.name;
181
+
182
+ return {
183
+ fn: (ctx: RuntimeContext) => {
184
+ const input = ctx.focus || ctx.input || [];
185
+
186
+ // First, check if this is a type filter (e.g., Patient in Patient.name)
187
+ // Check if any input items have this as their resourceType
188
+ const hasMatchingResourceType = input.some((item: any) =>
189
+ item && typeof item === 'object' && item.resourceType === name
190
+ );
191
+
192
+ if (hasMatchingResourceType) {
193
+ // This is a type filter - return only items matching this resourceType
194
+ return input.filter((item: any) =>
195
+ item && typeof item === 'object' && item.resourceType === name
196
+ );
197
+ }
198
+
199
+ // Not a type filter, treat as property navigation
200
+ const results: any[] = [];
201
+
202
+ for (const item of input) {
203
+ if (item == null || typeof item !== 'object') {
204
+ continue;
205
+ }
206
+
207
+ const value = item[name];
208
+ if (value !== undefined) {
209
+ if (Array.isArray(value)) {
210
+ results.push(...value);
211
+ } else {
212
+ results.push(value);
213
+ }
214
+ }
215
+ }
216
+
217
+ return results;
218
+ },
219
+ type: this.resolveType('Any'),
220
+ isSingleton: false,
221
+ source: name
222
+ };
223
+ }
224
+
225
+ /**
226
+ * Compiles a variable node - looks up value from context
227
+ */
228
+ private compileVariable(node: VariableNode): CompiledExpression {
229
+ const name = node.name;
230
+
231
+ return {
232
+ fn: (ctx: RuntimeContext) => {
233
+ if (name.startsWith('$')) {
234
+ // Special environment variables
235
+ switch (name) {
236
+ case '$this':
237
+ return ctx.env.$this || [];
238
+ case '$index':
239
+ return ctx.env.$index !== undefined ? [ctx.env.$index] : [];
240
+ case '$total':
241
+ return ctx.env.$total !== undefined ? [ctx.env.$total] : [];
242
+ default:
243
+ throw new EvaluationError(`Unknown special variable: ${name}`, node.position);
244
+ }
245
+ } else {
246
+ // User-defined variables (remove % prefix if present)
247
+ const varName = name.startsWith('%') ? name.substring(1) : name;
248
+
249
+ // Special root variables
250
+ switch (varName) {
251
+ case 'context':
252
+ return ctx.env.$context || ctx.input || [];
253
+ case 'resource':
254
+ return ctx.env.$resource || ctx.input || [];
255
+ case 'rootResource':
256
+ return ctx.env.$rootResource || ctx.input || [];
257
+ default:
258
+ const value = ctx.env[varName];
259
+ if (value === undefined) {
260
+ return [];
261
+ }
262
+ // Wrap non-array values in an array to create a singleton collection
263
+ return Array.isArray(value) ? value : [value];
264
+ }
265
+ }
266
+ },
267
+ type: this.resolveType('Any'),
268
+ isSingleton: false,
269
+ source: name
270
+ };
271
+ }
272
+
273
+ /**
274
+ * Compiles a binary operator node
275
+ */
276
+ private compileBinary(node: BinaryNode): CompiledExpression {
277
+ const operator = node.operator;
278
+
279
+ // Handle case where parser incorrectly creates BinaryNode for unary minus
280
+ if (!node.left && !node.right && (node as any).operand) {
281
+ // This is actually a unary operation
282
+ return this.compileUnary(node as any);
283
+ }
284
+
285
+ // Special handling for dot operator - it's a pipeline
286
+ if (operator === TokenType.DOT) {
287
+ const left = this.compileNode(node.left);
288
+ const right = this.compileNode(node.right);
289
+
290
+ return {
291
+ fn: (ctx: RuntimeContext) => {
292
+ // DON'T create a new env - use the one from ctx directly
293
+ // This allows nested DOT operators to share the same env object
294
+ const mutableCtx = {
295
+ ...ctx
296
+ // env is shared from ctx
297
+ };
298
+
299
+ // Execute left side with mutable context
300
+ const leftResult = left.fn(mutableCtx);
301
+
302
+ // Execute right side with left's result as input, using the potentially modified context
303
+ const rightCtx: RuntimeContext = {
304
+ ...mutableCtx, // Use the potentially modified context
305
+ input: leftResult,
306
+ focus: leftResult
307
+ // env is still shared from the original ctx
308
+ };
309
+ return right.fn(rightCtx);
310
+ },
311
+ type: right.type,
312
+ isSingleton: right.isSingleton,
313
+ source: `${left.source || ''}.${right.source || ''}`
314
+ };
315
+ }
316
+
317
+ // Get operation from registry
318
+ const operation = node.operation || Registry.getByToken(operator, 'infix');
319
+ if (!operation || operation.kind !== 'operator') {
320
+ throw new EvaluationError(`Unknown operator: ${operator}`, node.position);
321
+ }
322
+
323
+ // Compile operands
324
+ const left = this.compileNode(node.left);
325
+ const right = this.compileNode(node.right);
326
+
327
+ // Use operation's compile method
328
+ // For operators, pass both operands in args array
329
+ return operation.compile(this, left, [left, right]);
330
+ }
331
+
332
+ /**
333
+ * Compiles a unary operator node
334
+ */
335
+ private compileUnary(node: UnaryNode): CompiledExpression {
336
+ const operator = node.operator;
337
+
338
+ // Get operation from registry
339
+ // Don't use node.operation as parser might have assigned wrong operation
340
+ const operation = Registry.getByToken(operator, 'prefix');
341
+ if (!operation || operation.kind !== 'operator') {
342
+ throw new EvaluationError(`Unknown unary operator: ${operator}`, node.position);
343
+ }
344
+
345
+ // Compile operand
346
+ const operand = this.compileNode(node.operand);
347
+
348
+ // Use operation's compile method
349
+ // For unary operators, pass operand in args array
350
+ return operation.compile(this, operand, [operand]);
351
+ }
352
+
353
+ /**
354
+ * Compiles a function call node
355
+ */
356
+ private compileFunction(node: FunctionNode): CompiledExpression {
357
+ // For now, handle only identifier function names
358
+ if (node.name.type !== NodeType.Identifier) {
359
+ throw new EvaluationError('Dynamic function names not yet supported', node.position);
360
+ }
361
+
362
+ const functionName = (node.name as IdentifierNode).name;
363
+
364
+ // Check if function is registered
365
+ const operation = Registry.get(functionName);
366
+ if (!operation || operation.kind !== 'function') {
367
+ throw new EvaluationError(`Unknown function: ${functionName}`, node.position);
368
+ }
369
+
370
+ // Compile arguments
371
+ const compiledArgs = node.arguments.map(arg => this.compileNode(arg));
372
+
373
+ // Use operation's compile method
374
+ // For functions, the input is passed as the first compiled expression
375
+ const inputExpr: CompiledExpression = {
376
+ fn: (ctx) => ctx.focus || ctx.input || [],
377
+ type: this.resolveType('Any'),
378
+ isSingleton: false
379
+ };
380
+
381
+ return operation.compile(this, inputExpr, compiledArgs);
382
+ }
383
+
384
+ /**
385
+ * Compiles a collection node
386
+ */
387
+ private compileCollection(node: CollectionNode): CompiledExpression {
388
+ const compiledElements = node.elements.map(elem => this.compileNode(elem));
389
+
390
+ return {
391
+ fn: (ctx: RuntimeContext) => {
392
+ const results: any[] = [];
393
+
394
+ for (const element of compiledElements) {
395
+ const elementResult = element.fn(ctx);
396
+ results.push(...elementResult);
397
+ }
398
+
399
+ return results;
400
+ },
401
+ type: this.resolveType('Any'),
402
+ isSingleton: false,
403
+ source: `{${compiledElements.map(e => e.source || '').join(', ')}}`
404
+ };
405
+ }
406
+
407
+ /**
408
+ * Compiles an index node
409
+ */
410
+ private compileIndex(node: IndexNode): CompiledExpression {
411
+ const expression = this.compileNode(node.expression);
412
+ const index = this.compileNode(node.index);
413
+
414
+ return {
415
+ fn: (ctx: RuntimeContext) => {
416
+ const exprResult = expression.fn(ctx);
417
+ // Evaluate index in the original context
418
+ const indexResult = index.fn(ctx);
419
+
420
+ if (indexResult.length === 0) {
421
+ return [];
422
+ }
423
+
424
+ const idx = toSingleton(indexResult);
425
+ if (typeof idx !== 'number' || !Number.isInteger(idx)) {
426
+ throw new EvaluationError('Index must be an integer', node.position);
427
+ }
428
+
429
+ if (idx < 0 || idx >= exprResult.length) {
430
+ return [];
431
+ }
432
+
433
+ return [exprResult[idx]];
434
+ },
435
+ type: expression.type,
436
+ isSingleton: true,
437
+ source: `${expression.source || ''}[${index.source || ''}]`
438
+ };
439
+ }
440
+
441
+ /**
442
+ * Compiles a union node
443
+ */
444
+ private compileUnion(node: UnionNode): CompiledExpression {
445
+ const compiledOperands = node.operands.map(op => this.compileNode(op));
446
+
447
+ return {
448
+ fn: (ctx: RuntimeContext) => {
449
+ const results: any[] = [];
450
+ const seen = new Set();
451
+
452
+ for (const operand of compiledOperands) {
453
+ // Create a fresh context copy for each operand
454
+ // This prevents variable definitions from leaking between branches
455
+ const operandCtx = { ...ctx, env: { ...ctx.env } };
456
+ const operandResult = operand.fn(operandCtx);
457
+
458
+ // Remove duplicates
459
+ for (const item of operandResult) {
460
+ const key = JSON.stringify(item);
461
+ if (!seen.has(key)) {
462
+ seen.add(key);
463
+ results.push(item);
464
+ }
465
+ }
466
+ }
467
+
468
+ return results;
469
+ },
470
+ type: this.resolveType('Any'),
471
+ isSingleton: false,
472
+ source: compiledOperands.map(o => o.source || '').join(' | ')
473
+ };
474
+ }
475
+
476
+ /**
477
+ * Compiles membership test (is operator)
478
+ */
479
+ private compileMembershipTest(node: MembershipTestNode): CompiledExpression {
480
+ // Get the 'is' operator from registry
481
+ const operation = Registry.getByToken(TokenType.IS, 'infix');
482
+ if (!operation || operation.kind !== 'operator') {
483
+ throw new EvaluationError('is operator not found in registry', node.position);
484
+ }
485
+
486
+ const expression = this.compileNode(node.expression);
487
+ const typeExpr: CompiledExpression = {
488
+ fn: () => [node.targetType],
489
+ type: this.resolveType('String'),
490
+ isSingleton: true,
491
+ source: node.targetType
492
+ };
493
+
494
+ try {
495
+ return operation.compile(this, expression, [expression, typeExpr]);
496
+ } catch (error: any) {
497
+ // If the error doesn't have position, add it from the node
498
+ if (error instanceof EvaluationError && !error.position) {
499
+ error.position = node.position;
500
+ }
501
+ throw error;
502
+ }
503
+ }
504
+
505
+ /**
506
+ * Compiles type cast (as operator)
507
+ */
508
+ private compileTypeCast(node: TypeCastNode): CompiledExpression {
509
+ // Get the 'as' operator from registry
510
+ const operation = Registry.getByToken(TokenType.AS, 'infix');
511
+ if (!operation || operation.kind !== 'operator') {
512
+ throw new EvaluationError('as operator not found in registry', node.position);
513
+ }
514
+
515
+ const expression = this.compileNode(node.expression);
516
+ const typeExpr: CompiledExpression = {
517
+ fn: () => [node.targetType],
518
+ type: this.resolveType('String'),
519
+ isSingleton: true,
520
+ source: node.targetType
521
+ };
522
+
523
+ try {
524
+ return operation.compile(this, expression, [typeExpr]);
525
+ } catch (error: any) {
526
+ // If the error doesn't have position, add it from the node
527
+ if (error instanceof EvaluationError && !error.position) {
528
+ error.position = node.position;
529
+ }
530
+ throw error;
531
+ }
532
+ }
533
+
534
+ /**
535
+ * Compiles type reference - should not be evaluated directly
536
+ */
537
+ private compileTypeReference(node: TypeReferenceNode): CompiledExpression {
538
+ // Type references are used in ofType() and similar functions
539
+ // They should compile to return the type name as a string
540
+ const typeName = node.typeName;
541
+ return {
542
+ fn: (ctx: RuntimeContext) => [typeName],
543
+ type: this.resolveType('String'),
544
+ isSingleton: true,
545
+ source: typeName
546
+ };
547
+ }
548
+ }
549
+
550
+ /**
551
+ * Helper function to compile a FHIRPath expression
552
+ */
553
+ export function compile(expression: string | ASTNode): CompiledExpression {
554
+ // Parse if string
555
+ const ast = typeof expression === 'string'
556
+ ? require('../parser').parse(expression)
557
+ : expression;
558
+
559
+ // Create compiler and compile
560
+ const compiler = new Compiler();
561
+ return compiler.compile(ast);
562
+ }
563
+
564
+ /**
565
+ * Helper function to compile and evaluate a FHIRPath expression
566
+ */
567
+ export function evaluateCompiled(
568
+ expression: string | ASTNode,
569
+ input: any,
570
+ context?: RuntimeContext
571
+ ): any[] {
572
+ // Compile the expression
573
+ const compiled = compile(expression);
574
+
575
+ // Convert input to collection
576
+ const inputCollection = CollectionUtils.toCollection(input);
577
+
578
+ // Create runtime context
579
+ const runtimeContext: RuntimeContext = context || {
580
+ input: inputCollection,
581
+ focus: inputCollection,
582
+ env: {
583
+ $this: inputCollection
584
+ }
585
+ };
586
+
587
+ // Execute the compiled function
588
+ return compiled.fn(runtimeContext);
589
+ }
@@ -0,0 +1,2 @@
1
+ export { Compiler, compile, evaluateCompiled } from './compiler';
2
+ export type { CompiledNode, NodeCompiler, CompilationContext } from './types';
@@ -0,0 +1,23 @@
1
+ import type { Context, EvaluationResult } from '../interpreter/types';
2
+ import type { ASTNode } from '../parser/ast';
3
+
4
+ /**
5
+ * A compiled FHIRPath node - a JavaScript function that implements
6
+ * the stream-processing model: (input, context) → (output, new context)
7
+ */
8
+ export type CompiledNode = (input: any[], context: Context) => EvaluationResult;
9
+
10
+ /**
11
+ * A function that compiles a specific AST node type into a JavaScript closure
12
+ */
13
+ export type NodeCompiler<T extends ASTNode = ASTNode> = (node: T) => CompiledNode;
14
+
15
+ /**
16
+ * Compilation context for tracking state during compilation
17
+ */
18
+ export interface CompilationContext {
19
+ // Future: optimization flags, source map info, etc.
20
+ }
21
+
22
+ // Re-export types from registry to avoid conflicts
23
+ export type { CompiledExpression, RuntimeContext } from '../registry/types';
package/src/index.ts ADDED
@@ -0,0 +1,52 @@
1
+ // Import registry to trigger operation registration
2
+ import './registry';
3
+
4
+ // Core API functions
5
+ import { parse, evaluate, compile, analyze, registry } from './api/index';
6
+
7
+ // Default export with common operations
8
+ export default {
9
+ parse,
10
+ evaluate,
11
+ compile,
12
+ analyze,
13
+ registry
14
+ };
15
+
16
+ // Named exports for core functions
17
+ export { parse, evaluate, compile, analyze, registry };
18
+
19
+ // Named exports for advanced usage
20
+ export { FHIRPath } from './api/builder';
21
+ export { FHIRPathError, ErrorCode } from './api/errors';
22
+
23
+ // Export types
24
+ export type {
25
+ // Core types
26
+ FHIRPathExpression,
27
+ CompiledExpression,
28
+ EvaluationContext,
29
+ CompileOptions,
30
+ AnalyzeOptions,
31
+ AnalysisResult,
32
+
33
+ // Error types
34
+ AnalysisError,
35
+ AnalysisWarning,
36
+ Location,
37
+
38
+ // Extension types
39
+ ModelProvider,
40
+ PropertyDefinition,
41
+ CustomFunction,
42
+ CustomFunctionMap,
43
+
44
+ // Registry types
45
+ RegistryAPI,
46
+ OperationMetadata,
47
+ OperationInfo,
48
+
49
+ // Builder types
50
+ FHIRPathBuilder,
51
+ FHIRPathAPI
52
+ } from './api/types';