npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

fhir-structuremap-js

v1.2.1

Published

Standalone, browser-capable JS engine that executes FHIR StructureMap (FHIR Mapping Language) transforms.

Readme

fhir-structuremap-js

A standalone, dependency-light, browser-capable JavaScript engine that executes FHIR StructureMap resources — the FHIR Mapping Language (FML). Spun out of fhir-questionnaire-builder, but usable standalone in any Node.js or browser project.

No FHIRPath engine, no base FHIR profiles, and no terminology server are bundled — you inject them. This keeps the package small and lets you reuse whatever fhirpath implementation, StructureDefinitions, and terminology access your host application already has.

Install

npm install fhir-structuremap-js fhirpath

fhirpath is a peer dependency — bring your own version (or any object with a compatible evaluate(resource, expression, env) signature).

Quick start

Execute a StructureMap (JSON)

import { StructureMapDocument, StructureMapEngine } from 'fhir-structuremap-js';
import fhirpath from 'fhirpath';

const doc = StructureMapDocument.fromJSON(structureMapJson);
const engine = new StructureMapEngine({
  evaluator: { evaluate: (resource, expr, env) => fhirpath.evaluate(resource, expr, env) },
});

const result = engine.run(doc, { source: patientResource, target: {} });
// result.target is the populated Observation/whatever your map's target input produces

Parse FML text instead of JSON

import { parseFMLToDocument } from 'fhir-structuremap-js';

const doc = parseFMLToDocument(`
  map "http://example.org/StructureMap/PatientToPerson" = PatientToPerson
  group main(source src : Patient, target tgt : Person) {
    src.name as n -> tgt.name = n;
  }
`);

Injected dependencies (Mapping Support API)

The spec's own "Mapping Support API" (§7.8.0.1) is deliberately not built in — pass whichever of these your use case needs to new StructureMapEngine({ ... }):

| Option | Used for | |---|---| | evaluator | Required. { evaluate(resource, expr, env) => unknown[] } — any FHIRPath implementation. | | env | Extra FHIRPath environment variables (%name), merged with doc.const[]. | | registry | Override/extend transform functions — defaults to createDefaultTransformRegistry(). | | createInstance(type) | Backs create() and untyped auto-create. Defaults to {}. | | translate(source, mapUri) | Backs the translate() transform (ConceptMap lookups). | | uuidFactory() | Backs uuid(). Defaults to crypto.randomUUID(). | | structureMapResolver(pattern) | Resolves import[] entries (incl. * wildcards) to an array of StructureMapDocuments. | | structureDefinitionResolver(type) | Backs type-filtered sources, cast(), and default-mapping-group dispatch. | | queryInstances(type) / produceInstance(type) | Backs queried/produced structure modes for custom transforms. | | onLog(message) | Receives log() source-clause output. |

Architecture

  • Factory/registry pattern for every extensible concept (TransformRegistry, createDefaultTransformRegistry()) — add a transform by registering a name, never by editing engine dispatch code.
  • Model layer is pure data + parsing (src/model/) — StructureMapDocument.fromJSON() never evaluates anything.
  • One concern per file across src/model/, src/engine/, src/transforms/, src/fml/.

Supported

All 8 implementation phases are complete:

  • Full StructureMap JSON model (metadata, structure refs, imports, constants, groups, rules, sources, targets, parameters, nested rules, dependent invocations).
  • Multi-source rule matching (cartesian permutation, same-rule context chaining), cardinality, listMode (source: first/not_first/last/not_last/only_one), where/check/log, defaultValue.
  • All 18 target transform functions (create, copy, truncate, escape, cast, append, translate, reference, uuid, pointer, evaluate, cc, c, qty, id, cp, dateOp).
  • Target listMode (first/share/last/single) assembly, order-independent of rule execution order.
  • Nested rules, dependent rule/group invocation, extends, default mapping groups (typeMode: types | type-and-types) and the identity-transform simple form, plus its batch/list shorthand (src -> tgt: a, b, c;, §"Simple Form: Identity Transform").
  • Imports (incl. * wildcard resolution) and lazy, cached, circular-safe constants, correctly re-scoped per document — a group invoked from an imported map sees that map's own const[], not the caller's (§7.8.0.6).
  • Type-aware structural checks and queried/produced structure modes via injected resolvers.
  • A hand-written FML concrete-syntax parser (lexer + recursive-descent parser), grounded in mapping.g4 and cross-checked against the official HAPI/HL7 Java reference implementation (org.hl7.fhir.r5.utils.structuremap.StructureMapUtilities) for shapes the published grammar omits, e.g. the identity-transform batch shorthand above and multi-line """markdown""" metadata values (/// description = """...""").
  • Direct multi-segment copy (tgt.a = src.b.c, no as x binding needed) — desugared at parse time into evaluate(src, 'b.c'), reusing the already-injected FHIRPath evaluator rather than requiring a flat variable-name lookup.
  • dateOp(date, '+'|'-', value, unit) — the StructureMap spec's own table leaves this transform's parameters undefined ("??"); grounded instead in FHIRPath's own standardized date/time arithmetic (§6.5.1), since the engine already hard-depends on an injected FHIRPath evaluator for everything else. Verified against the real fhirpath npm package's accepted calendar-duration units (year(s)/month(s)/week(s)/ day(s)/hour(s)/minute(s)/second(s)/millisecond(s), plus the quoted UCUM short forms 'wk'/'d'/'h'/'min'/'s'/'ms').
  • Validated against the official example StructureMaps published at structuremap-examples.html (see tests/integration/hl7-examples.test.js).
  • Dotted/repeating /// metadata properties (name{.property}*, e.g. jurisdiction.coding.system) per §7.8.0.3, incl. repeat detection ("additional items with the same name represent repeats") — for the two complex StructureMap metadata fields realistically used in hand-written FML, jurisdiction (CodeableConcept[]) and contact (ContactDetail[]); metadata parsing correctly stops at the map statement so a coincidental ///-shaped line later in the file (e.g. a rule-body comment) is never mistaken for metadata.

Design non-goals (deliberate, not gaps)

  • No bundled StructureDefinitions, FHIRPath engine, or terminology client — always via an injected resolver/evaluator/callback, to keep the library small and host-agnostic. See PLAN.md "Non-goals". One consequence: auto-create is untyped by default — without an injected structureDefinitionResolver that resolves both ends' types, a transform-less target auto-creates a plain {} rather than dispatching to the identity-transform's default-mapping-group.

License

MIT