@atomic-ehr/fhirpath 0.0.1 → 0.0.2-canary.0a52566.20250805162836

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 (97) hide show
  1. package/README.md +2 -0
  2. package/dist/index.d.ts +157 -50
  3. package/dist/index.js +1612 -705
  4. package/dist/index.js.map +1 -1
  5. package/package.json +1 -1
  6. package/src/analyzer.ts +367 -60
  7. package/src/boxing.ts +124 -0
  8. package/src/errors.ts +246 -0
  9. package/src/index.ts +34 -5
  10. package/src/interpreter.ts +173 -43
  11. package/src/model-provider.ts +3 -1
  12. package/src/operations/abs-function.ts +19 -10
  13. package/src/operations/aggregate-function.ts +11 -3
  14. package/src/operations/all-function.ts +18 -8
  15. package/src/operations/allFalse-function.ts +9 -6
  16. package/src/operations/allTrue-function.ts +9 -6
  17. package/src/operations/and-operator.ts +20 -11
  18. package/src/operations/anyFalse-function.ts +6 -4
  19. package/src/operations/anyTrue-function.ts +6 -4
  20. package/src/operations/as-operator.ts +1 -0
  21. package/src/operations/ceiling-function.ts +9 -5
  22. package/src/operations/combine-function.ts +4 -2
  23. package/src/operations/combine-operator.ts +18 -4
  24. package/src/operations/contains-function.ts +20 -8
  25. package/src/operations/contains-operator.ts +14 -6
  26. package/src/operations/count-function.ts +2 -1
  27. package/src/operations/defineVariable-function.ts +5 -3
  28. package/src/operations/distinct-function.ts +16 -4
  29. package/src/operations/div-operator.ts +15 -2
  30. package/src/operations/divide-operator.ts +10 -5
  31. package/src/operations/dot-operator.ts +3 -1
  32. package/src/operations/empty-function.ts +2 -1
  33. package/src/operations/endsWith-function.ts +22 -10
  34. package/src/operations/equal-operator.ts +18 -6
  35. package/src/operations/equivalent-operator.ts +15 -10
  36. package/src/operations/exclude-function.ts +12 -10
  37. package/src/operations/exists-function.ts +14 -7
  38. package/src/operations/first-function.ts +7 -4
  39. package/src/operations/floor-function.ts +9 -5
  40. package/src/operations/greater-operator.ts +9 -4
  41. package/src/operations/greater-or-equal-operator.ts +9 -4
  42. package/src/operations/iif-function.ts +18 -16
  43. package/src/operations/implies-operator.ts +22 -7
  44. package/src/operations/in-operator.ts +17 -7
  45. package/src/operations/index.ts +1 -0
  46. package/src/operations/indexOf-function.ts +22 -10
  47. package/src/operations/intersect-function.ts +17 -20
  48. package/src/operations/is-operator.ts +13 -7
  49. package/src/operations/isDistinct-function.ts +12 -6
  50. package/src/operations/join-function.ts +15 -4
  51. package/src/operations/last-function.ts +7 -4
  52. package/src/operations/length-function.ts +12 -5
  53. package/src/operations/less-operator.ts +9 -4
  54. package/src/operations/less-or-equal-operator.ts +9 -4
  55. package/src/operations/less-than.ts +25 -1
  56. package/src/operations/lower-function.ts +12 -5
  57. package/src/operations/minus-operator.ts +9 -4
  58. package/src/operations/mod-operator.ts +19 -2
  59. package/src/operations/multiply-operator.ts +11 -6
  60. package/src/operations/not-equal-operator.ts +15 -6
  61. package/src/operations/not-equivalent-operator.ts +15 -10
  62. package/src/operations/not-function.ts +12 -4
  63. package/src/operations/ofType-function.ts +109 -0
  64. package/src/operations/or-operator.ts +20 -11
  65. package/src/operations/plus-operator.ts +18 -6
  66. package/src/operations/power-function.ts +21 -9
  67. package/src/operations/replace-function.ts +26 -9
  68. package/src/operations/round-function.ts +23 -8
  69. package/src/operations/select-function.ts +12 -6
  70. package/src/operations/single-function.ts +5 -3
  71. package/src/operations/skip-function.ts +12 -5
  72. package/src/operations/split-function.ts +24 -9
  73. package/src/operations/sqrt-function.ts +9 -5
  74. package/src/operations/startsWith-function.ts +20 -8
  75. package/src/operations/subsetOf-function.ts +14 -11
  76. package/src/operations/substring-function.ts +36 -19
  77. package/src/operations/supersetOf-function.ts +14 -11
  78. package/src/operations/tail-function.ts +3 -1
  79. package/src/operations/take-function.ts +12 -5
  80. package/src/operations/toBoolean-function.ts +18 -11
  81. package/src/operations/toDecimal-function.ts +13 -6
  82. package/src/operations/toInteger-function.ts +13 -6
  83. package/src/operations/toString-function.ts +17 -10
  84. package/src/operations/trace-function.ts +12 -5
  85. package/src/operations/trim-function.ts +11 -4
  86. package/src/operations/truncate-function.ts +9 -5
  87. package/src/operations/unary-minus-operator.ts +22 -12
  88. package/src/operations/unary-plus-operator.ts +1 -0
  89. package/src/operations/union-function.ts +19 -24
  90. package/src/operations/union-operator.ts +1 -0
  91. package/src/operations/upper-function.ts +12 -5
  92. package/src/operations/where-function.ts +15 -8
  93. package/src/operations/xor-operator.ts +8 -3
  94. package/src/parser.ts +391 -8
  95. package/src/quantity-value.ts +4 -8
  96. package/src/types.ts +7 -6
  97. package/src/parser-base.ts +0 -400
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # @atomic-ehr/fhirpath
2
2
 
3
+ [![npm version](https://badge.fury.io/js/@atomic-ehr%2Ffhirpath.svg)](https://www.npmjs.com/package/@atomic-ehr/fhirpath)
4
+
3
5
  A TypeScript implementation of FHIRPath, the path-based navigation and extraction language for FHIR (Fast Healthcare Interoperability Resources).
4
6
 
5
7
  ## Installation
package/dist/index.d.ts CHANGED
@@ -1,5 +1,37 @@
1
1
  import { FHIRSchema } from '@atomic-ehr/fhirschema';
2
2
 
3
+ /**
4
+ * Symbol to mark boxed values
5
+ */
6
+ declare const BOXED_SYMBOL: unique symbol;
7
+ /**
8
+ * Extension structure for FHIR primitive elements
9
+ */
10
+ interface Extension {
11
+ url: string;
12
+ [key: string]: any;
13
+ }
14
+ /**
15
+ * Metadata for FHIR primitive elements (e.g., _gender for gender property)
16
+ */
17
+ interface PrimitiveElement {
18
+ id?: string;
19
+ extension?: Extension[];
20
+ }
21
+ /**
22
+ * Boxed FHIRPath value with metadata
23
+ */
24
+ interface FHIRPathValue<T = any> {
25
+ /** The actual value */
26
+ value: T;
27
+ /** Type information from ModelProvider */
28
+ typeInfo?: TypeInfo;
29
+ /** Primitive element extension (for primitives only) */
30
+ primitiveElement?: PrimitiveElement;
31
+ /** Internal marker to identify boxed values */
32
+ [BOXED_SYMBOL]: true;
33
+ }
34
+
3
35
  /**
4
36
  * Simplified FHIRPath Lexer
5
37
  *
@@ -301,9 +333,10 @@ interface RuntimeContext {
301
333
  input: any[];
302
334
  focus: any[];
303
335
  variables: Record<string, any>;
336
+ currentNode?: ASTNode;
304
337
  }
305
338
  interface EvaluationResult {
306
- value: any[];
339
+ value: FHIRPathValue[];
307
340
  context: RuntimeContext;
308
341
  }
309
342
  declare enum DiagnosticSeverity {
@@ -346,51 +379,8 @@ interface ParseResult {
346
379
  availableCompletions: string[];
347
380
  };
348
381
  }
349
- type OperationEvaluator = (input: any[], context: RuntimeContext, ...args: any[]) => EvaluationResult;
350
- type FunctionEvaluator = (input: any[], context: RuntimeContext, args: ASTNode[], evaluator: (node: ASTNode, input: any[], context: RuntimeContext) => EvaluationResult) => EvaluationResult;
351
-
352
- /**
353
- * Abstract base parser with shared parsing logic
354
- * Subclasses must implement node creation and error handling
355
- */
356
- declare abstract class BaseParser<TNode extends BaseASTNode = BaseASTNode> {
357
- protected lexer: Lexer;
358
- protected tokens: Token[];
359
- protected current: number;
360
- constructor(input: string, lexerOptions?: LexerOptions);
361
- protected abstract createIdentifierNode(name: string, token: Token): TNode;
362
- protected abstract createLiteralNode(value: any, valueType: 'string' | 'number' | 'boolean' | 'date' | 'time' | 'datetime' | 'null', token: Token): TNode;
363
- protected abstract createBinaryNode(token: Token, left: TNode, right: TNode): TNode;
364
- protected abstract createUnaryNode(token: Token, operand: TNode): TNode;
365
- protected abstract createFunctionNode(name: TNode, args: TNode[], startToken: Token): TNode;
366
- protected abstract createVariableNode(name: string, token: Token): TNode;
367
- protected abstract createIndexNode(expression: TNode, index: TNode, startToken: Token): TNode;
368
- protected abstract createMembershipTestNode(expression: TNode, targetType: string, startToken: Token): TNode;
369
- protected abstract createTypeCastNode(expression: TNode, targetType: string, startToken: Token): TNode;
370
- protected abstract createCollectionNode(elements: TNode[], startToken: Token): TNode;
371
- protected abstract createQuantityNode(value: number, unit: string, isCalendarUnit: boolean, startToken: Token, endToken: Token): TNode;
372
- protected abstract handleError(message: string, token?: Token): never | TNode;
373
- protected expression(): TNode;
374
- protected parseExpressionWithPrecedence(minPrecedence: number): TNode;
375
- protected parsePrimary(): TNode;
376
- protected parseInvocation(): TNode;
377
- protected parseArgumentList(): TNode[];
378
- protected parseCollectionElements(): TNode[];
379
- protected parseTypeName(): string;
380
- protected parseStringValue(raw: string): string;
381
- protected parseIdentifierValue(raw: string): string;
382
- protected isFunctionCall(node: TNode): boolean;
383
- protected isBinaryOperatorToken(token: Token): boolean;
384
- protected isKeywordAllowedAsMember(token: Token): boolean;
385
- protected isKeywordAllowedAsIdentifier(token: Token): boolean;
386
- protected peek(): Token;
387
- protected previous(): Token;
388
- protected isAtEnd(): boolean;
389
- protected advance(): Token;
390
- protected check(type: TokenType): boolean;
391
- protected match(...types: TokenType[]): boolean;
392
- protected consume(type: TokenType, message: string): Token;
393
- }
382
+ type OperationEvaluator = (input: FHIRPathValue[], context: RuntimeContext, ...args: any[]) => EvaluationResult;
383
+ type FunctionEvaluator = (input: FHIRPathValue[], context: RuntimeContext, args: ASTNode[], evaluator: (node: ASTNode, input: FHIRPathValue[], context: RuntimeContext) => EvaluationResult) => EvaluationResult;
394
384
 
395
385
  interface ParserOptions {
396
386
  mode?: 'simple' | 'lsp';
@@ -401,7 +391,10 @@ interface ParserOptions {
401
391
  cursorPosition: number;
402
392
  };
403
393
  }
404
- declare class Parser extends BaseParser<ASTNode> {
394
+ declare class Parser {
395
+ protected lexer: Lexer;
396
+ protected tokens: Token[];
397
+ protected current: number;
405
398
  private mode;
406
399
  private options;
407
400
  private errors?;
@@ -419,6 +412,26 @@ declare class Parser extends BaseParser<ASTNode> {
419
412
  parse(): ParseResult;
420
413
  private parseSimple;
421
414
  private parseLSP;
415
+ protected expression(): ASTNode;
416
+ protected parseExpressionWithPrecedence(minPrecedence: number): ASTNode;
417
+ protected parsePrimary(): ASTNode;
418
+ protected parseInvocation(): ASTNode;
419
+ protected parseArgumentList(): ASTNode[];
420
+ protected parseCollectionElements(): ASTNode[];
421
+ protected parseTypeName(): string;
422
+ protected parseStringValue(raw: string): string;
423
+ protected parseIdentifierValue(raw: string): string;
424
+ protected isFunctionCall(node: ASTNode): boolean;
425
+ protected isBinaryOperatorToken(token: Token): boolean;
426
+ protected isKeywordAllowedAsMember(token: Token): boolean;
427
+ protected isKeywordAllowedAsIdentifier(token: Token): boolean;
428
+ protected peek(): Token;
429
+ protected previous(): Token;
430
+ protected isAtEnd(): boolean;
431
+ protected advance(): Token;
432
+ protected check(type: TokenType): boolean;
433
+ protected match(...types: TokenType[]): boolean;
434
+ protected consume(type: TokenType, message: string): Token;
422
435
  protected createIdentifierNode(name: string, token: Token): ASTNode;
423
436
  protected createLiteralNode(value: any, valueType: LiteralNode['valueType'], token: Token): LiteralNode;
424
437
  protected createBinaryNode(token: Token, left: ASTNode, right: ASTNode): BinaryNode;
@@ -502,8 +515,11 @@ declare class Analyzer {
502
515
  private visitBinaryOperator;
503
516
  private visitIdentifier;
504
517
  private visitFunctionCall;
518
+ private visitMembershipTest;
519
+ private visitTypeCast;
505
520
  private validateVariable;
506
- private addDiagnostic;
521
+ private collectDefinedVariables;
522
+ private collectDefinedVariablesWithTypes;
507
523
  private inferType;
508
524
  private inferErrorNodeType;
509
525
  private inferLiteralType;
@@ -567,7 +583,7 @@ declare class FHIRModelProvider implements ModelProvider<FHIRModelContext> {
567
583
  private initialized;
568
584
  private readonly typeMapping;
569
585
  private readonly commonTypes;
570
- constructor(config: FHIRModelProviderConfig);
586
+ constructor(config?: FHIRModelProviderConfig);
571
587
  initialize(): Promise<void>;
572
588
  private buildCanonicalUrl;
573
589
  private loadSchemaAsync;
@@ -617,9 +633,100 @@ interface InspectResult {
617
633
  }
618
634
  declare function inspect(expression: string, options?: InspectOptions): InspectResult;
619
635
 
636
+ /**
637
+ * Base error class for all FHIRPath errors
638
+ */
639
+ declare class FHIRPathError extends Error {
640
+ code: string;
641
+ location?: Range | undefined;
642
+ constructor(code: string, message: string, location?: Range | undefined);
643
+ }
644
+ /**
645
+ * Error factory with specialized constructors
646
+ */
647
+ declare const Errors: {
648
+ unknownOperator(operator: string, location?: Range): FHIRPathError;
649
+ unknownFunction(name: string, location?: Range): FHIRPathError;
650
+ unknownVariable(name: string, location?: Range): FHIRPathError;
651
+ unknownUserVariable(name: string, location?: Range): FHIRPathError;
652
+ unknownProperty(property: string, type: string, location?: Range): FHIRPathError;
653
+ unknownNodeType(nodeType: string, location?: Range): FHIRPathError;
654
+ noEvaluatorFound(evaluatorType: string, name: string, location?: Range): FHIRPathError;
655
+ variableNotDefined(name: string, location?: Range): FHIRPathError;
656
+ wrongArgumentCount(funcName: string, expected: number, actual: number, location?: Range): FHIRPathError;
657
+ wrongArgumentCountRange(funcName: string, min: number, max: number, actual: number, location?: Range): FHIRPathError;
658
+ singletonRequired(funcName: string, actualCount: number, location?: Range): FHIRPathError;
659
+ stringSingletonRequired(funcName: string, actualCount: number, location?: Range): FHIRPathError;
660
+ emptyNotAllowed(funcName: string, location?: Range): FHIRPathError;
661
+ argumentRequired(funcName: string, argumentName: string, location?: Range): FHIRPathError;
662
+ typeNotAssignable(sourceType: string, targetType: string, location?: Range): FHIRPathError;
663
+ operatorTypeMismatch(operator: string, leftType: string, rightType: string, location?: Range): FHIRPathError;
664
+ argumentTypeMismatch(argIndex: number, funcName: string, expected: string, actual: string, location?: Range): FHIRPathError;
665
+ conversionFailed(value: string, targetType: string, location?: Range): FHIRPathError;
666
+ invalidValueType(expected: string, actual: string, location?: Range): FHIRPathError;
667
+ invalidOperandType(operation: string, type: string, location?: Range): FHIRPathError;
668
+ stringOperationOnNonString(operation: string, location?: Range): FHIRPathError;
669
+ numericOperationOnNonNumeric(operation: string, location?: Range): FHIRPathError;
670
+ booleanOperationOnNonBoolean(operation: string, index: number, actualType: string, location?: Range): FHIRPathError;
671
+ modelProviderRequired(operation: string, location?: Range): FHIRPathError;
672
+ unexpectedToken(token: string, location?: Range): FHIRPathError;
673
+ expectedToken(expected: string, actual: string, location?: Range): FHIRPathError;
674
+ invalidSyntax(details: string, location?: Range): FHIRPathError;
675
+ expectedIdentifier(after: string, actual: string, location?: Range): FHIRPathError;
676
+ expectedTypeName(actual: string, location?: Range): FHIRPathError;
677
+ divisionByZero(location?: Range): FHIRPathError;
678
+ invalidDateTimeFormat(format: string, location?: Range): FHIRPathError;
679
+ incompatibleUnits(unit1: string, unit2: string, location?: Range): FHIRPathError;
680
+ indexOutOfBounds(index: number, size: number, location?: Range): FHIRPathError;
681
+ invalidOperation(details: string, location?: Range): FHIRPathError;
682
+ invalidPrecision(operation: string, location?: Range): FHIRPathError;
683
+ invalidStringOperation(operation: string, paramName: string, location?: Range): FHIRPathError;
684
+ invalidNumericOperation(operation: string, paramName: string, expectedType: string, location?: Range): FHIRPathError;
685
+ };
686
+ declare enum ErrorCodes {
687
+ UNKNOWN_OPERATOR = "FP1001",
688
+ UNKNOWN_FUNCTION = "FP1002",
689
+ UNKNOWN_VARIABLE = "FP1003",
690
+ UNKNOWN_USER_VARIABLE = "FP1004",
691
+ UNKNOWN_PROPERTY = "FP1005",
692
+ UNKNOWN_NODE_TYPE = "FP1006",
693
+ NO_EVALUATOR_FOUND = "FP1007",
694
+ VARIABLE_NOT_DEFINED = "FP1008",
695
+ WRONG_ARGUMENT_COUNT = "FP2001",
696
+ WRONG_ARGUMENT_COUNT_RANGE = "FP2002",
697
+ SINGLETON_REQUIRED = "FP2003",
698
+ EMPTY_NOT_ALLOWED = "FP2004",
699
+ ARGUMENT_REQUIRED = "FP2005",
700
+ TYPE_NOT_ASSIGNABLE = "FP3001",
701
+ OPERATOR_TYPE_MISMATCH = "FP3002",
702
+ ARGUMENT_TYPE_MISMATCH = "FP3003",
703
+ CONVERSION_FAILED = "FP3004",
704
+ INVALID_VALUE_TYPE = "FP3005",
705
+ INVALID_OPERAND_TYPE = "FP3006",
706
+ STRING_OPERATION_ON_NON_STRING = "FP3007",
707
+ NUMERIC_OPERATION_ON_NON_NUMERIC = "FP3008",
708
+ BOOLEAN_OPERATION_ON_NON_BOOLEAN = "FP3009",
709
+ MODEL_PROVIDER_REQUIRED = "FP4001",
710
+ UNEXPECTED_TOKEN = "FP5001",
711
+ EXPECTED_TOKEN = "FP5002",
712
+ INVALID_SYNTAX = "FP5003",
713
+ EXPECTED_IDENTIFIER = "FP5004",
714
+ EXPECTED_TYPE_NAME = "FP5005",
715
+ DIVISION_BY_ZERO = "FP6001",
716
+ INVALID_DATE_TIME_FORMAT = "FP6002",
717
+ INCOMPATIBLE_UNITS = "FP6003",
718
+ INDEX_OUT_OF_BOUNDS = "FP6004",
719
+ INVALID_OPERATION = "FP6005",
720
+ INVALID_PRECISION = "FP6006",
721
+ INVALID_STRING_OPERATION = "FP6007",
722
+ INVALID_NUMERIC_OPERATION = "FP6008"
723
+ }
724
+
620
725
  interface EvaluateOptions {
621
726
  input?: unknown;
622
727
  variables?: Record<string, unknown>;
728
+ modelProvider?: ModelProvider;
729
+ inputType?: TypeInfo;
623
730
  }
624
731
  declare function evaluate(expression: string, options?: EvaluateOptions): any[];
625
732
  declare function analyze(expression: string, options?: {
@@ -629,4 +736,4 @@ declare function analyze(expression: string, options?: {
629
736
  errorRecovery?: boolean;
630
737
  }): AnalysisResult;
631
738
 
632
- export { type ASTNode, type AnalysisResult, Analyzer, type Diagnostic, DiagnosticSeverity, type EvaluateOptions, type FHIRModelContext, FHIRModelProvider, type FHIRModelProviderConfig, type FunctionDefinition, type InspectOptions, type InspectResult, Interpreter, type ModelProvider as ModelTypeProvider, type OperatorDefinition, type ParseResult, Parser, Registry, type TraceEntry, type TypeInfo, type TypeName, analyze, evaluate, inspect, parse, registry };
739
+ export { type ASTNode, type AnalysisResult, Analyzer, type Diagnostic, DiagnosticSeverity, ErrorCodes, Errors, type EvaluateOptions, type FHIRModelContext, FHIRModelProvider, type FHIRModelProviderConfig, FHIRPathError, type FunctionDefinition, type InspectOptions, type InspectResult, Interpreter, type ModelProvider as ModelTypeProvider, type OperatorDefinition, type ParseResult, Parser, Registry, type TraceEntry, type TypeInfo, type TypeName, analyze, evaluate, inspect, parse, registry };