@atomic-ehr/fhirpath 0.0.1-canary.35b105d.20250724165800

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 (57) hide show
  1. package/README.md +307 -0
  2. package/dist/index.d.ts +225 -0
  3. package/dist/index.js +8185 -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 +152 -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 +579 -0
  18. package/src/compiler/index.ts +2 -0
  19. package/src/compiler/prototype-context-adapter.ts +99 -0
  20. package/src/compiler/types.ts +23 -0
  21. package/src/index.ts +52 -0
  22. package/src/interpreter/README.md +78 -0
  23. package/src/interpreter/interpreter.ts +485 -0
  24. package/src/interpreter/types.ts +110 -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 +425 -0
  39. package/src/registry/operations/comparison.ts +432 -0
  40. package/src/registry/operations/existence.ts +703 -0
  41. package/src/registry/operations/filtering.ts +358 -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 +542 -0
  52. package/src/registry/registry.ts +146 -0
  53. package/src/registry/types.ts +161 -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
  57. package/src/runtime/context.ts +179 -0
@@ -0,0 +1,110 @@
1
+ // Core types for FHIRPath interpreter following the stream-processing mental model
2
+
3
+ /**
4
+ * The result of evaluating any FHIRPath expression.
5
+ * Every expression returns a collection and potentially modified context.
6
+ */
7
+ import type { RuntimeContext } from '../runtime/context';
8
+
9
+ export interface EvaluationResult {
10
+ value: any[]; // Always a collection (even single values are collections of one)
11
+ context: RuntimeContext;
12
+ }
13
+
14
+ // Re-export RuntimeContext as Context for backward compatibility
15
+ export type { RuntimeContext as Context } from '../runtime/context';
16
+
17
+ /**
18
+ * Error thrown during evaluation with position information
19
+ */
20
+ export class EvaluationError extends Error {
21
+ constructor(
22
+ message: string,
23
+ public position?: { line: number; column: number; offset: number }
24
+ ) {
25
+ super(message);
26
+ this.name = 'EvaluationError';
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Type information for runtime type checking
32
+ */
33
+ export interface TypeInfo {
34
+ namespace: string; // 'System' or 'FHIR'
35
+ name: string; // Type name like 'String', 'Patient'
36
+ isCollection?: boolean;
37
+ }
38
+
39
+ /**
40
+ * Helper type for ensuring we always work with collections
41
+ */
42
+ export type Collection<T = any> = T[];
43
+
44
+ /**
45
+ * Singleton conversion result
46
+ */
47
+ export type SingletonResult<T = any> = T | undefined;
48
+
49
+ /**
50
+ * Helper functions for working with collections
51
+ */
52
+ export const CollectionUtils = {
53
+ /**
54
+ * Convert any value to a collection
55
+ */
56
+ toCollection(value: any): any[] {
57
+ if (value === null || value === undefined) {
58
+ return [];
59
+ }
60
+ return Array.isArray(value) ? value : [value];
61
+ },
62
+
63
+ /**
64
+ * Apply singleton evaluation rules
65
+ * @returns The single value or undefined if rules don't apply
66
+ * @throws Error if multiple items when single expected
67
+ */
68
+ toSingleton(collection: any[], expectedType?: string): SingletonResult {
69
+ if (collection.length === 0) {
70
+ return undefined; // Empty propagates
71
+ }
72
+
73
+ if (collection.length === 1) {
74
+ const value = collection[0];
75
+
76
+ // Rule 2: Collection with one item, expecting Boolean → true
77
+ if (expectedType === 'boolean' && typeof value !== 'boolean') {
78
+ return true;
79
+ }
80
+
81
+ // Rule 1: Collection with one item convertible to expected type → use it
82
+ return value;
83
+ }
84
+
85
+ // Rule 4: Multiple items → ERROR
86
+ throw new EvaluationError(`Expected single value but got ${collection.length} items`);
87
+ },
88
+
89
+ /**
90
+ * Check if a collection is empty
91
+ */
92
+ isEmpty(collection: any[]): boolean {
93
+ return collection.length === 0;
94
+ },
95
+
96
+ /**
97
+ * Flatten nested collections
98
+ */
99
+ flatten(collection: any[]): any[] {
100
+ const result: any[] = [];
101
+ for (const item of collection) {
102
+ if (Array.isArray(item)) {
103
+ result.push(...item);
104
+ } else {
105
+ result.push(item);
106
+ }
107
+ }
108
+ return result;
109
+ }
110
+ };
@@ -0,0 +1,37 @@
1
+ // Character classification lookup table for O(1) checks
2
+ export const CHAR_FLAGS = new Uint8Array(128);
3
+
4
+ // Bit flags for character properties
5
+ export const FLAG_DIGIT = 1 << 0;
6
+ export const FLAG_ALPHA = 1 << 1;
7
+ export const FLAG_WHITESPACE = 1 << 2;
8
+ export const FLAG_IDENTIFIER_START = 1 << 3;
9
+ export const FLAG_IDENTIFIER_CONT = 1 << 4;
10
+
11
+ // Initialize lookup table (called once at startup)
12
+ export function initCharTables(): void {
13
+ // Digits
14
+ for (let i = 48; i <= 57; i++) {
15
+ CHAR_FLAGS[i]! |= FLAG_DIGIT | FLAG_IDENTIFIER_CONT;
16
+ }
17
+
18
+ // Letters
19
+ for (let i = 65; i <= 90; i++) {
20
+ CHAR_FLAGS[i]! |= FLAG_ALPHA | FLAG_IDENTIFIER_START | FLAG_IDENTIFIER_CONT;
21
+ }
22
+ for (let i = 97; i <= 122; i++) {
23
+ CHAR_FLAGS[i]! |= FLAG_ALPHA | FLAG_IDENTIFIER_START | FLAG_IDENTIFIER_CONT;
24
+ }
25
+
26
+ // Underscore
27
+ CHAR_FLAGS[95]! |= FLAG_IDENTIFIER_START | FLAG_IDENTIFIER_CONT;
28
+
29
+ // Whitespace
30
+ CHAR_FLAGS[32]! |= FLAG_WHITESPACE; // space
31
+ CHAR_FLAGS[9]! |= FLAG_WHITESPACE; // tab
32
+ CHAR_FLAGS[10]! |= FLAG_WHITESPACE; // newline
33
+ CHAR_FLAGS[13]! |= FLAG_WHITESPACE; // carriage return
34
+ }
35
+
36
+ // Initialize the table immediately
37
+ initCharTables();
@@ -0,0 +1,31 @@
1
+ import type { Position } from './token';
2
+
3
+ export class LexerError extends Error {
4
+ constructor(
5
+ message: string,
6
+ public position: Position,
7
+ public char?: string
8
+ ) {
9
+ super(message);
10
+ this.name = 'LexerError';
11
+ }
12
+
13
+ override toString(): string {
14
+ const location = `${this.position.line}:${this.position.column}`;
15
+ const charInfo = this.char ? ` (found '${this.char}')` : '';
16
+ return `${this.name}: ${this.message} at ${location}${charInfo}`;
17
+ }
18
+ }
19
+
20
+ export function formatError(error: LexerError, input: string): string {
21
+ const lines = input.split('\n');
22
+ const line = lines[error.position.line - 1] || '';
23
+ const pointer = ' '.repeat(error.position.column - 1) + '^';
24
+
25
+ return [
26
+ error.toString(),
27
+ '',
28
+ line,
29
+ pointer
30
+ ].join('\n');
31
+ }
@@ -0,0 +1,5 @@
1
+ export { FHIRPathLexer, lex } from './lexer';
2
+ export type { Token, Position } from './token';
3
+ export { TokenType, Channel } from './token';
4
+ export { LexerError, formatError } from './errors';
5
+ export { CHAR_FLAGS, FLAG_DIGIT, FLAG_ALPHA, FLAG_WHITESPACE, FLAG_IDENTIFIER_START, FLAG_IDENTIFIER_CONT } from './char-tables';