CRITICAL: AFTER CONTEXT RESET/COMPACT - Read CONTEXT-RESET-CHECKLIST.md IMMEDIATELY
When you are generating code prefer to be concise and to the point. Make comments only if needed.
This is a design project for a new unit library in typescript. Please be concise and to the point.
This is a comprehensive TypeScript implementation of FHIRPath - a path-based navigation and extraction language for FHIR resources, designed for high performance and LSP (Language Server Protocol) support.
-
Lexer (
lexer.ts): Multi-channel tokenizer with trivia preservation for LSP support- Recognizes operators, literals, identifiers, structural tokens
- Supports temporal literals (@DateTime, @Date, @Time) and quantities
- Preserves comments and whitespace in hidden channel for IDE features
-
Parser (
parser.ts): Robust expression parser with error recovery- Dual mode: simple (fast parsing) and LSP (with error recovery)
- Precedence climbing for operators
- Cursor node injection for completion support (
parser/cursor-nodes.ts) - AST augmentation with position and trivia information
-
Analyzer (
analyzer.ts): Static type analysis and validation- Context-flow type inference
- Function/operator signature matching
- Error diagnostics with precise location information
- Cursor-aware analysis for IDE completions
- Supporting modules:
analyzer/augmentor.ts- AST augmentation with type informationanalyzer/scope-manager.ts- Variable scope trackinganalyzer/cursor-services.ts- Cursor position analysisanalyzer/trivia-indexer.ts- Trivia preservation for LSPanalyzer/type-compat.ts- Type compatibility checkinganalyzer/utils.ts- Utility functions
-
Interpreter (
interpreter.ts): High-performance AST evaluator- Visitor pattern with optimized dispatch
- Prototype-based context management for efficiency
- Boxing/unboxing system for type preservation
- Support for all FHIRPath types and operations
- Supporting modules:
interpreter/boxing.ts- Type boxing/unboxing systeminterpreter/runtime-context.ts- Runtime context managementinterpreter/navigator.ts- FHIR resource navigation
-
Registry (
registry.ts): Centralized operation management- Symbol, keyword, and unary operator registration
- Function definitions with multiple signatures
- Precedence and associativity rules
- Auto-registration of operations from
operations/directory
-
Operations (
operations/): 80+ operators and functions organized by category- Arithmetic: plus, minus, multiply, divide, div, mod, power, abs, ceiling, floor, round, sqrt, truncate
- Logical: and, or, xor, not, implies
- Comparison: equal, not-equal, less-than, greater-than, less-or-equal, greater-or-equal
- String: length, substring, startsWith, endsWith, contains, indexOf, lastIndexOf, matches, matchesFull, replace, replaceMatches, split, join, trim, upper, lower, toChars, repeat
- Collection: where, select, first, last, tail, skip, take, single, distinct, count, exists, empty, all, allTrue, allFalse, anyTrue, anyFalse, combine, union, intersect, exclude, subsetOf, supersetOf, isDistinct
- Type conversion: toBoolean, toInteger, toLong, toDecimal, toString, toQuantity, convertsToBoolean, convertsToInteger, convertsToLong, convertsToDecimal, convertsToString, convertsToQuantity
- Type testing: is, as, ofType
- Temporal: now, today, timeOfDay, dateOf, timeOf, yearOf, monthOf, dayOf, hourOf, minuteOf, secondOf, millisecondOf, timezoneOffsetOf
- Utility: trace, defineVariable, aggregate, iif, children, descendants
- Membership: in, contains
- Boundaries: highBoundary, lowBoundary
-
Complex Types (
complex-types/):temporal.ts- Date, DateTime, Time handling with timezone supportquantity-value.ts- UCUM quantity support with unit conversion
-
Error System (
errors.ts):- Structured error codes and messages
- FHIRPathError class with diagnostic information
- Parse, analysis, and runtime error differentiation
-
Model Provider (
model-provider.ts):- FHIR model integration using @atomic-ehr/fhir-canonical-manager
- Support for R4, R5, STU3, DSTU2 FHIR versions
- Type hierarchy and element property resolution
- Schema caching for performance
-
LSP Support (
completion-provider.ts):- Context-aware code completions
- Function and property suggestions
- Variable completions
- Integration with cursor tracking
-
Utilities (
utils/):pprint.ts- Pretty printing for AST and debug output
-
Type System (
types.ts):- Complete FHIRPath type hierarchy (primitives, collections, FHIR types)
- Union type support with proper inference
- Polymorphic function signatures
- AST node type definitions
- Operator and function definition interfaces
-
Main Entry Point (
index.ts):evaluate()- Execute FHIRPath expressions with input dataanalyze()- Type analysis and validationparse()- Parse expressions to ASTprovideCompletions()- LSP completionsinspect()- Debug expressions with traces
-
Runtime Context:
- Efficient prototype-based variable scoping via RuntimeContextManager
- Built-in variables: $this, $index, $total
- User-defined variables with % prefix
- System variables: %context, %resource, %rootResource
- Cached temporal values for deterministic evaluation
-
Type Safety:
- Complete type inference through expression chains
- Union type handling for polymorphic operations
- FHIR resource type awareness
- Type compatibility checking with coercion rules
-
Performance Optimizations:
- Prototype-based context for minimal allocation
- Lazy evaluation where possible
- Schema and type hierarchy caching
- Optimized operator dispatch
-
Error Recovery:
- LSP mode with error recovery for IDE integration
- Partial AST generation for incomplete expressions
- Diagnostic collection without throwing
import { evaluate, analyze } from './src/index';
import { FHIRModelProvider } from './src/model-provider';
// Simple evaluation
const result = await evaluate("Patient.name.where(use = 'official').given", {
input: { resourceType: 'Patient', name: [{use: 'official', given: ['John']}] }
});
// Returns: ['John']
// With type analysis and FHIR model
const modelProvider = new FHIRModelProvider('R4');
const analysis = await analyze("Patient.name.given", {
inputType: { type: 'Patient', singleton: true },
modelProvider
});
// Returns type info, diagnostics, and analyzed AST
// LSP completions
import { provideCompletions } from './src/index';
const completions = await provideCompletions('Patient.na', 10, { modelProvider });
// Returns completion items for properties starting with 'na'- ./spec is official spec of FHIRPath
- ./spec/FHIRPath.g4 - official FHIRPath grammar
- ./adr is a folder for Architecture Decision Records. (read ./adr/README.md for more details)
- ./concepts is a wiki like knowledge base for the project.
- ./tasks is a folder for task management (read ./tasks/README.md for more details) Task file name convention is [00-].md When creating new tasks, create them in ./tasks/todo/.md When working on tasks move files to ./tasks/in-progress/.md When task finished move files to ./tasks/done/.md and write what was done in this file.
- ./test is a folder for tests - tests should be named as ./test/.test.ts by convention.
- ./tmp use this folder for temporary scripts and files during debugging and development.
- Before making significant architectural changes, check existing ADRs in ./adr
- Create new ADRs for important design decisions using ./adr/template.md
- Document alternatives considered and rationale for choices
-
For fhirpath strings prefer
'instead of" -
Follow the Google TypeScript Style Guide located at
./guides/tsguide.mdfor all TypeScript code -
Key style points from the guide:
- Use 2 spaces for indentation (not tabs)
- Use single quotes for strings unless escaping
- Always use
constorlet, nevervar - Prefer
constfor values that don't change - Use
import typefor type-only imports - Use trailing commas in multi-line structures
- Prefer interfaces over type aliases for object types
- Use PascalCase for types/interfaces, camelCase for variables/functions
- Avoid
anytype - useunknownif type is truly unknown
-
Imports and Exports:
- Use ES6 module syntax (
import/export), NEVER userequire()ormodule.exports - Prefer relative imports for files in same project:
./foonotpath/to/foo - Use named exports, avoid default exports
- Export visibility: minimize exported API surface
- Never use
namespace, use separate files instead - Group imports: external deps first, then internal by path depth
- Use ES6 module syntax (
-
Classes and Functions:
- Prefer function declarations for named functions:
function foo() {}notconst foo = () => {} - Arrow functions for callbacks and when
thisbinding needed - Class members: use
readonlyfor never-reassigned properties - Use parameter properties in constructors:
constructor(private readonly foo: Foo) {} - Never use
#privatefields, use TypeScript'sprivatekeyword - Avoid
publicmodifier (it's default), except for parameter properties - Getters must be pure functions (no side effects)
- Prefer function declarations for named functions:
-
Error Handling:
- Always throw
Errorobjects, never strings:throw new Error('msg') - Use
try-catchwith typed catch:catch (e: unknown) - Empty catch blocks must have explanatory comment
- Custom errors should extend
Errorclass
- Always throw
-
Type Safety:
- Use type annotations on object literals:
const foo: Foo = {...}not{...} as Foo - Avoid type assertions (
as) and non-null assertions (!) without clear justification - Use
===and!==for equality (exception:== nullto check null/undefined) - No implicit boolean coercion for enums
- Arrays: use
[]syntax notArray()constructor - Objects: use
{}syntax notObject()constructor
- Use type annotations on object literals:
-
Control Flow:
- Always use braces for control structures (if/for/while)
switchstatements must havedefaultcase- Prefer
for-offor arrays,Object.entries()for objects - No assignment in conditionals unless double-parenthesized
-
Best Practices:
- One variable per declaration
- Initialize class fields at declaration when possible
- Destructuring: provide defaults on left side:
{foo = 'default'}: Options = {} - Template literals for complex string concatenation
- Use
Number()for parsing, check forNaN - Never use
parseInt()/parseFloat()except for non-base-10 - Never use
require()- useimport!!!
-
Use
bun run <filename.ts>to run files -
When you create or update typescript file, run
bun tsc --noEmitto check for errors and fix them. -
Create tests for new functionality. Put test file as ./test/.test.ts by convention.
-
Use
import {describe, it, expect} from 'bun:test'for writing tests -
IMPORTANT: Always use
bun run testto run tests - this automatically filters output to show only failures, making it easier to identify issues quickly. Usebun run test:outputif you need full verbose output. -
Main test cases are located in ./test-cases folder as JSON files organized according to ADR-008:
- ./test-cases/operations/ contains subdirectories for each operation category (arithmetic/, logical/, etc.)
- Each operation has its own test file (e.g., plus.json, where.json)
- Use
bun tools/testcase.ts <path-to-test-file>to run tests
When working on tasks move files to ./tasks/in-progress/.md When task finished move files to ./tasks/done/.md and write what was done in this file.
Use the TypeScript MCP tools for TypeScript-specific operations like finding symbols, renaming, refactoring, and analyzing code:
mcp__typescript__list_tools- List all available TypeScript MCP toolsmcp__typescript__get_type_in_module- Get detailed signature for a type/interface/class in a modulemcp__typescript__get_type_at_symbol- Get type information for a symbol at specific locationmcp__typescript__find_references- Find all references to a symbol across codebasemcp__typescript__get_definitions- Get definition(s) of a TypeScript symbolmcp__typescript__rename_symbol- Rename a symbol across the codebasemcp__typescript__move_file- Move a file and update all importsmcp__typescript__move_directory- Move a directory and update all importsmcp__typescript__delete_symbol- Delete a symbol and all its referencesmcp__typescript__get_module_symbols- Get all exported symbols from a modulemcp__typescript__get_symbols_in_scope- Get all symbols visible at a locationmcp__typescript__get_diagnostics- Get TypeScript errors/warnings for a file
-
Parser Tool (
./tools/parser.ts) - Parse FHIRPath expressions and output AST as JSONbun tools/parser.ts "<fhirpath-expression>"Examples:
bun tools/parser.ts "Patient.name.given"bun tools/parser.ts "5 + 3"bun tools/parser.ts "Patient.where(active = true)"
-
Interpreter Tool (
./tools/interpreter.ts) - Evaluate FHIRPath expressions with optional input databun tools/interpreter.ts "<fhirpath-expression>" [input-json]Examples:
bun tools/interpreter.ts "5 + 3"bun tools/interpreter.ts "name.given" '{"name": [{"given": ["John", "James"]}]}'bun tools/interpreter.ts "name.where(use = 'official').given" '{"name": [{"use": "official", "given": ["John"]}]}'bun tools/interpreter.ts "'Hello' + ' ' + 'World'"
-
Analyzer Tool (
./tools/analyzer.ts) - Analyze FHIRPath expressions for type information and diagnosticsbun tools/analyzer.ts "<fhirpath-expression>" [options]Options:
--type, -t- Input type (e.g., "Patient", "String", etc.)--vars, -v- JSON object with variables--singleton- Input is a singleton (single value)--ast- Show AST structure
Examples:
bun tools/analyzer.ts "5 + 3"- Analyze simple expressionbun tools/analyzer.ts "name.given" --type Patient- Analyze with typed inputbun tools/analyzer.ts "%x + %y" --vars '{"x": 10, "y": 20}'- With variablesbun tools/analyzer.ts "property.defineVariable('x', $this.value).select(%x)"- Complex expression
-
Inspect Tool (
./tools/inspect.ts) - Debug FHIRPath expressions with rich debugging information including traces, AST, and timingbun tools/inspect.ts "<fhirpath-expression>" [input-json] [options]Options:
--vars, -v- JSON object with variables (e.g., '{"x": 10}')--max-traces- Maximum number of traces to collect--verbose- Show full trace values (default: truncated)--ast- Show only the AST--traces- Show only traces--timing- Show only timing information
Examples:
bun tools/inspect.ts "5 + 3"- Simple expressionbun tools/inspect.ts "name.trace('names').given.trace('given names')" '{"name": [{"given": ["John"]}]}'- With tracesbun tools/inspect.ts "Patient.name.given" @patient.json- Input from filebun tools/inspect.ts "%x + %y" --vars '{"x": 10, "y": 20}'- With variablesbun tools/inspect.ts "complex.expression" @data.json --traces- Show only tracesbun tools/inspect.ts "expression" --ast- Show AST structure
-
Registry Lookup Tool (
./tools/registry-lookup.ts) - Lookup operation metadata from the FHIRPath registrybun tools/registry-lookup.ts <operation-name|"list">
Examples:
bun tools/registry-lookup.ts "+"- Get metadata for the + operatorbun tools/registry-lookup.ts "where"- Get metadata for the where functionbun tools/registry-lookup.ts "list"- List all operationsbun tools/registry-lookup.ts "list functions"- List all functionsbun tools/registry-lookup.ts "list operators"- List all operators
-
Test Case Runner (
./tools/testcase.ts) - Run test cases from JSON test filesbun tools/testcase.ts <test-file> [test-name] [mode] bun tools/testcase.ts <test-file> --list bun tools/testcase.ts <test-file> --pending bun tools/testcase.ts <test-file> --toggle-pending <test-name> [reason] bun tools/testcase.ts --tags bun tools/testcase.ts --tag <tag-name> bun tools/testcase.ts --failing bun tools/testcase.ts --failing-commands bun tools/testcase.ts --pending bun tools/testcase.ts --watch
Arguments:
test-file- Path to JSON test file (relative to test-cases/)test-name- Optional: specific test name to run (if not provided, runs all tests)mode- Optional: 'interpreter' | 'compiler' | 'both' (default: 'both')
Commands:
--list- List all tests in a specific file--pending- Show all pending tests (globally or for a specific file)--toggle-pending- Toggle pending status on/off for a specific test--tags- List all unique tags from all test files with usage counts--tag <tag-name>- Show all test expressions for a specific tag--failing- Show all failing tests with detailed information and debug commands--failing-commands- Output only the commands to run failing tests (useful for scripting)--watch- Watch for changes in failing tests and re-run them automatically
Examples:
bun tools/testcase.ts operators/arithmetic.json- Run all tests in a filebun tools/testcase.ts operators/arithmetic.json "addition - integers"- Run a specific testbun tools/testcase.ts operators/arithmetic.json "addition - integers" interpreter- Run with interpreter onlybun tools/testcase.ts operators/arithmetic.json --list- List all tests in a filebun tools/testcase.ts operations/utility/defineVariable.json --pending- Show pending tests in a specific filebun tools/testcase.ts variables.json --toggle-pending "test name" "Reason for pending"- Disable a testbun tools/testcase.ts variables.json --toggle-pending "test name"- Enable a test (removes pending)bun tools/testcase.ts --tags- List all unique tags across all test casesbun tools/testcase.ts --tag arithmetic- Show all expressions with the "arithmetic" tagbun tools/testcase.ts --failing- Show all failing tests with commands to debug thembun tools/testcase.ts --failing-commands- Get just the commands for failing testsbun tools/testcase.ts --pending- Show all pending tests across all test files
Scripting Examples:
# Run all failing tests one by one bun tools/testcase.ts --failing-commands | while read cmd; do echo "Running: $cmd" $cmd done # Save failing test commands to a file bun tools/testcase.ts --failing-commands > failing-tests.sh # Run failing tests for a specific tag bun tools/testcase.ts --tag arithmetic | grep "Run:" | cut -d' ' -f2- | bash
-
Spec Search Tool (
./tools/spec.ts) - Search FHIRPath specifications by keywords and titlebun tools/spec.ts <search-query> [options]
Options:
--content, -c- Show full content of matching sections--limit, -l <n>- Limit results to top N matches (default: 10)--all, -a- Show all matching results (no limit)
Examples:
bun tools/spec.ts "where"- Search for sections about 'where'bun tools/spec.ts "where function" -c- Search and show contentbun tools/spec.ts "arithmetic operator" -l 5- Show top 5 matchesbun tools/spec.ts "+" -c- Search for plus operator with contentbun tools/spec.ts "defineVariable" -c- Get full specification for defineVariable
-
Build Spec Index (
./scripts/build-spec-index.ts) - Build cached index for faster spec searchesbun scripts/build-spec-index.ts
This script:
- Reads all metadata files from
spec/sections-meta/ - Creates a single
.index.jsonfile containing all metadata - Improves spec.ts search performance by ~15%
- Should be run after updating section metadata files
- Reads all metadata files from
-
Research Tool (
./tools/research.ts) - Query multiple AI models and collect responses for research purposesbun tools/research.ts "<prompt>" [options]Options:
-m, --models <model>- Models to query (default: grok-heavy, o3, claude-3-opus). Can be specified multiple times-s, --summarize- Generate a summary of responses (default: true)--no-summarize- Disable summary generation-h, --help- Show help message
Environment Variables:
XAI_API_KEY- API key for X.AI (Grok)OPENAI_API_KEY- API key for OpenAIANTHROPIC_API_KEY- API key for Anthropic (Claude)
Examples:
bun tools/research.ts "What are the key differences between interpreted and compiled languages?"bun tools/research.ts "Explain quantum computing" -m gpt-4 -m claudebun tools/research.ts "Compare React and Vue frameworks" --no-summarize
This tool:
- Queries multiple AI models simultaneously with the same prompt
- Saves individual responses to
llm/<date>-<prompt-slug>/directory - Creates files:
prompt.md,grok.md,openai.md,anthropic.md - Optionally generates a summary comparing responses and extracting common themes
- Useful for getting diverse perspectives on technical questions during research
-
FHIRPath.js Test Runner (
./tools/fhirpathjs-tests.ts) - Run fhirpath.js test cases for compatibility referencebun tools/fhirpathjs-tests.ts [options] [test-file|pattern]Note: This is an auxiliary test suite from the fhirpath.js project, used as a reference for compatibility testing. Our primary test cases are in
./test-cases/. We do not aim for 100% compliance with fhirpath.js - this tool helps identify areas where our implementation differs and whether those differences are intentional.Arguments:
test-file- Specific test file to run (e.g.,simple.yaml)pattern- Pattern to match test files (e.g.,"5.*.yaml")
Options:
--list- List all available test files--verbose- Show detailed output including passed tests--filter <expr>- Filter tests by expression or description--summary- Show only summary (default for all tests)
Examples:
bun tools/fhirpathjs-tests.ts simple.yaml- Run a specific test filebun tools/fhirpathjs-tests.ts --list- List available test filesbun tools/fhirpathjs-tests.ts "5.*.yaml"- Run all section 5 testsbun tools/fhirpathjs-tests.ts simple.yaml --filter "name"- Run only tests containing "name"bun tools/fhirpathjs-tests.ts "*.yaml"- Run all test files
Test Convention:
- Tests are loaded from
fhirpath.js/test/cases/(git submodule) - Each YAML file may contain a
subjectfield with the test resource - If
subjectcontains onlyresourceTypeandid, the tool loads the full resource by convention:- Pattern:
fhirpath.js/test/resources/{model}/{resourceType}-{id}.json - Example:
Patientwith idexample→patient-example.json
- Pattern:
- Uses our FHIRModelProvider for R4/R5/STU3/DSTU2 model context
Current Status (as of last run):
- Overall pass rate: ~62% (1,668/2,675 tests)
- FHIR R4 tests: ~56% passing
- FHIR R5 tests: ~56% passing
- Simple navigation: ~79% passing
- Boolean logic: ~93% passing
Known Differences:
- Some functions like
getValue(),hasValue()are fhirpath.js extensions - Quantity literal format differences (we parse to objects, they keep as strings)
- Unicode escape handling differences
- Some edge cases in type conversion and coercion