- This project implements the FHIRPath language in JavaScript and supports DSTU2, STU3, R4, and R5 model contexts.
- Entry point is
src/fhirpath.js: public API isparse,compile,evaluate,resolveInternalTypes,types. src/fhirpath.jsalso exportsversion,FP_Decimal,ucumUtils, andutil(used by external callers and custom function implementations).- Evaluation flow is
parse()-> AST ->_compile()->applyParsedPath()->engine.doEval(); seesrc/fhirpath.jsandsrc/parser/index.js. - Core behavior is table-driven:
engine.invocationTableinsrc/fhirpath.jsmaps function/operator names to handlers and arity checks. - Most function families live in separate modules (e.g.
src/aggregate.js,src/filtering.js,src/math.js) and export anengineobject. - FHIR version-specific typing/model metadata is in
fhir-context/{dstu2,stu3,r4,r5}and is required for choice-type/type resolution. - CLI entry is
bin/fhirpath; behavior is covered bytest/bin_fhirpath.test.js.
- Internal values are wrapped as
ResourceNode/FP_Type; final conversion happens inprepareEvalResult()(src/fhirpath.js). evaluate()mutates input resources by attaching hidden__path__metadata ( documented inREADME.md); do not assume input objects stay pristine.- Base-path evaluation for partial resources uses
{base, expression}and model normalization viamodel.pathsDefinedElsewhere/model.path2Typein_compile(). - Async operations (
resolve,memberOf,%terminologies.*) requireoptions.async; guards are enforced viautil.checkAllowAsync(seesrc/additional.js,src/terminologies.js). - For mixed sync/async flows,
util.checkAllowAsyncbelongs in the function that creates an async promise; do not add it to pure Promise combiners such assortusingPromise.all(...). evaluate()/compile()acceptoptions.debuggerfor step-level tracing; the callback receives(ctx, parentData, result, node)after each eval step (seeengine.doEvalSync()insrc/fhirpath.js).- With
resolveInternalTypes: false,prepareEvalResult()keepsResourceNodewrappers in output (instead of flattening to plain values), so downstream evaluations can retain type/path metadata. %factory.*is implemented as a class with its own invocation table insrc/factory.jsand injected as%factoryin eval context.
- Spec-style unit tests are YAML-driven:
test/fhirpath.test.jsloadstest/cases/*.yamland generates Jest tests dynamically. test/cases/fhir-r4.yamlandtest/cases/fhir-r5.yamlare generated fromconverter/dataset; refresh them withnode converter/bin/index.js -s(skip download, use local dataset files).- Additional Jest suites in
test/*.test.jscover APIs and behaviors outside YAML cases (e.g.test/async-functions.test.js,test/user-invocation-table.test.js,test/bin_fhirpath.test.js). - Many tests run in both math modes automatically (
preciseMathtrue/false) unless a case setspreciseMathexplicitly. npm run test:unitruns Jest three times across time zones (default,America/New_York,Europe/Paris) to catch datetime regressions.- Test helpers in
test/test_utils.jsauto-load models (r5,r4,stu3,dstu2) and deep-clone input resources to avoid cross-test pollution. - Add new spec-style cases in
test/cases/*.yaml; use keys likemodel,inputfile,variables,context,error,result. - Type declaration checks use
npm run test:tsdwith tests intest/typescript/fhirpath.test-d.ts. - End-to-end browser checks run via Cypress under
test/cypress/(script:npm run test:e2e, which builds the demo first).
- Install:
npm install(ifnodeis missing in this environment, runsource bashrc.fhirpathand retry). - Lint:
npm run lint(targetssrc/parser/index.js,src/*.js,converter/). - Unit tests:
npm run test:unit; debugger mode:npm run test:unit:debug. - Type tests:
npm run test:tsd. - Demo build:
npm run build:demo(npm run build+demowebpack build). - E2E tests:
npm run test:e2e(builds demo + runs Cypress). - Full CI-like local run:
npm test(lint + tsd + unit + e2e). - Parser regeneration:
npm run generateParser(usessrc/parser/FHIRPath.g4,antlr-4.9.3-complete.jar, thenscripts/fix-parser-imports.js). - Browser artifacts:
npm run build(webpack outputs inbrowser-build/, plus zipped distributable). - Performance comparison:
npm run compare-performance(test/benchmark.js). Use-- -r <git-ref>to compare against a local baseline commit and check the generated report attest/benchmark/results/compare-performance-report.html.
- If a command that is important to the task fails due to sandbox restrictions ( for example EPERM/spawn permission errors), rerun it with escalated permissions and include a brief justification request.
- Performance is a top priority: prefer lower-allocation, lower-overhead designs, and treat measurable performance regressions as blockers unless explicitly approved.
- Use CommonJS (
require/module.exports) and 2-space indentation (seeeslint.config.js). - When generating code, keep lines to no more than 80 characters when practical.
- Use modern JavaScript syntax (
const/let, arrow functions, destructuring) where it matches existing files. - In AI chat responses, prefer project-relative file references in
path:lineformat (e.g.src/fhirpath.js:19). - Blank lines: keep two between declarations; for JSDoc, keep two above the block and none between the block and its declaration.
- In authored
test/*.test.jsfiles, keep two blank lines before and afterdescribe(...)blocks and betweenit(...)blocks; inside eachdescribe(...), keep one blank line before the firstit(...)and after the lastit(...). - Keep project layout conventions: core logic in
src/, FHIR-version-specific metadata infhir-context/, tests intest/, and docs indocs/orREADME.md. - New FHIRPath functions are typically added as module functions plus
registration in
engine.invocationTable(src/fhirpath.js). - For feature work, update tests together with implementation (
test/cases/*.yamlfor spec-style behavior, plustest/*.test.jswhen behavior is API-specific). - For custom function hooks, follow
userInvocationTableconventions in_compile(); useinternalStructures: trueonly if handler needs rawResourceNodeaccess. - For async server calls, thread options via
terminologyUrl,fhirServerUrl,httpHeaders, and optionalsignal(seedocs/auth.md,docs/abort.md). - If public API signatures or exports change, update
src/fhirpath.d.tsand validate withnpm run test:tsd(test/typescript/fhirpath.test-d.ts). - Keep behavior standards-compliant with FHIRPath and aligned with the selected FHIR model version when model-aware behavior is involved.
- Contributors MUST NOT hand-edit
test/cases/fhir-r4.yamlortest/cases/fhir-r5.yaml(these files are generated).