fhirpath.js

repository·master·Indexed 41 days ago

https://github.com/hl7/fhirpath.js

A JavaScript implementation of the FHIRPath language used for querying and navigating FHIR resources. Version 5.2.0 includes a CLI for evaluating expressions, a converter for transforming XML test cases to YAML/JSON, and specialized functions like htmlChecks() for validating FHIR narratives and weight() for retrieving score extensions.

Tokens
13.6K
Snippets
42
Records
65
Agent score
52%

What's inside fhirpath.js

  1. How the weight() function searches for score extensions

    master

    When evaluating weight(), the engine searches for the first available score extension for each source node using the following priority order:

    1. Source Node: Check the source node itself for a score extension.
    2. QuestionnaireResponse Answers: If the source node is an answer from a QuestionnaireResponse or its value[x]:
      • Check the value[x] element for a score extension.
      • Check the corresponding answer option (if any) of the corresponding Questionnaire item for a score extension.
      • If the Questionnaire item references a contained ValueSet, check the corresponding element there for a score extension.
    3. Local CodeSystem: If the source resource (e.g., QuestionnaireResponse) or Questionnaire contains a corresponding CodeSystem, check for a score extension (R4) or property (R5) there.
    4. Terminology Server: Look for a score extension (R4) or property (R5) in the corresponding CodeSystem loaded from a remote terminology server.
  2. Rules enforced by `htmlChecks()`

    master

    htmlChecks() enforces two main categories of rules: FHIR narrative rules and XML well-formedness.

    FHIR Narrative Rules

    • Allowed Elements/Attributes: Only elements and attributes permitted by the FHIR narrative rules (based on HTML 4.0 chapters 7-11 and 15) are allowed.
    • Images: <img> is allowed, but image maps (<map>, <area>) and their attributes (usemap, ismap) are rejected.
    • Anchors: <a> elements may carry name or href (or both). Other anchor attributes like charset, type, hreflang, rel, and rev are rejected.
    • Tables: width is accepted on <table> and <img> only. Other table attributes like abbr, align, axis, char, charoff, colspan, headers, rowspan, scope, span, and valign are accepted on any element.
    • Prohibited Content: Scripts, forms, objects, frames, iframes, head, body, base, link, xlink:*, deprecated elements, and event-related attributes (e.g., onClick) are rejected.
    • Content Requirement: The div must have non-whitespace content (text or an <img> with a src attribute).
    • Entities: HTML entities like &nbsp; are not supported. Use Unicode characters or numeric character references (e.g., &#160;) instead.
    • Namespaces: A default namespace declaration is optional but must be the XHTML namespace (http://www.w3.org/1999/xhtml).

    XML Well-formedness

    • Closing Tags: Every element must be closed (<br></br>) or self-closed (<br/>). HTML void-element shorthand (e.g., <br>) is rejected.
    • Attributes: Must have quoted values (<p class="c">) and be separated by whitespace.
    • Characters: Raw < is not allowed in attribute values. Only legal XML characters are permitted (no C0 control characters except tab, LF, and CR).
    • Comments: Must not contain -- and cannot end with -.
    • Prohibited XML structures: <!DOCTYPE> declarations and <![CDATA[ sections are not allowed.
    • Namespaces: Namespace prefixes are not supported. Only a default xmlns declaration is accepted.
  3. Configure headers for multiple terminology servers

    master
    If the terminologyUrl option is configured with an array of multiple server URLs, you must provide a corresponding entry in the httpHeaders object for every server base URL that requires authentication. The library automatically applies the headers when the key matches the server being requested.
  4. Behavior of shared in-flight server requests

    master

    Identical in-flight server requests are shared across multiple evaluations.

    • Cancellation Scope: Aborting one evaluation via its AbortSignal only rejects that specific consumer. The shared network request continues as long as at least one other consumer is still active.
    • Network Abort: The underlying network request is only physically aborted once all consumers of that shared request have cancelled (provided the runtime supports AbortController).
  5. Understand AbortError vs TimeoutError during evaluation

    master

    When an asynchronous evaluation is interrupted, the error type depends on the cause:

    1. AbortError: Occurs when a user manually cancels the evaluation using an AbortController.abort() call.
    2. TimeoutError: Occurs when a shared network request remains pending for one hour (including while reading the response body). In this case, the request is removed from the cache, all active consumers are rejected with a TimeoutError, and the underlying network request is aborted (if supported by the runtime).
  6. Abort asynchronous FHIRPath expression evaluation

    master

    When evaluating FHIRPath expressions asynchronously (using the async: true option), you can use an AbortSignal to cancel an evaluation in progress.

    Important: Do not pass the signal option to fhirpath.compile(). If you pass it to compile(), the resulting function cannot be reused. Instead, pass the signal option to the function returned by compile() during the actual evaluation call. This allows you to reuse the compiled expression while still being able to abort individual evaluation instances.

    const evalExpr = fhirpath.compile(
      expression, model, {async: true}
    );
    const abortController = new AbortController();
    const signal = abortController.signal;
    
    // Pass the signal here to allow aborting this specific evaluation
    let res = evalExpr(resource, environment, {signal});
    
    // Abort the evaluation
    abortController.abort();
  7. Authenticate to FHIR servers using httpHeaders

    master

    When using third-party authentication (such as OAuth2) to access FHIR servers or terminology servers, you can provide authentication credentials via the httpHeaders option in the fhirpath.evaluate options object.

    To use this, map the server's base URL to an object containing the required headers. If you are using the fhirclient npm package, you can pass the header obtained from client.getAuthorizationHeader() directly into this configuration.

    FHIR.oauth2.ready().then(client => {
      const res = fhirpath.evaluate(
        {"resourceType": "QuestionnaireResponse", ...},
        '%context.repeat(item).answer.weight().sum()',
        {},
        fhirpath_r4_model,
        {
          async: true,
          terminologyUrl: 'https://some-server',
          httpHeaders: {
            'https://some-server': {
              // Use the same Authorization header as fhirClient
              Authorization: client.getAuthorizationHeader()
            }
          }
        }
      );
    });
  8. Convert FHIRPath XML test cases to YAML/JSON

    master

    The converter is a CLI tool designed to transform FHIRPath XML test cases (specifically those from the HL7 FHIRPath R4 test suite) into the fhirpath.js YAML test case format accompanied by JSON resource files.

    You can run the converter using the entry point script located at converter/bin/index.js.

    converter/bin/index.js
  9. Understand the FHIRPath evaluation engine

    master

    The FHIRPath interpreter works by recursively reducing/evaluating nodes in an Abstract Syntax Tree (AST) using an evaluation context and the current data.

    Key components of the evaluation process:

    • evaluate function: The entry point that takes the FHIRPath AST and the resource to evaluate.
    • evalTable: A registry where each AST node type is mapped to an eval function.
    • invocationTable: A lookup table for functions and operators. When a function or operator is invoked, the engine:
      1. Looks up the entry in the invocationTable.
      2. Unpacks parameters based on the arity signature.
      3. Validates parameter types.
      4. Executes the function.
      5. Wraps the result using util.arraify.
    • Nullability: If a function is marked as nullable and any of its parameters are empty or null, the function is not invoked, and an empty result is returned.
  10. How Member Invocations work (Member Access)

    master

    Member Invocations handle property access (e.g., code or Observation.code). The engine supports two modes:

    1. Regular Member Access: Retrieves child nodes for the specified key from the current data items.
    2. Root-Level Type Filtering: If the expression is a root-level invocation (e.g., starting with a type name like Observation.code), the engine checks if the current item matches the specified type. If it matches, the item itself is returned; otherwise, it attempts regular member access.

    All data items are wrapped in a ResourceNode during this process to ensure consistent type handling and path tracking.