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

@glion/transform-profile-groups

v0.27.1

Published

Unified plugin to group HL7v2 segments into the segment groups their event schema defines

Readme

@glion/transform-profile-groups

Unified plugin that nests HL7v2 segments in the segment groups their event schema defines.

What it does

The parser produces a flat list of segments. This plugin nests them in Group nodes the way the HL7v2 standard defines the event's message structure: in an ORU_R01, each order's OBR and its results go in an ORDER_OBSERVATION, inside a PATIENT_RESULT. It reads the event schema MSH-12 and MSH-9 name and moves the existing segment nodes; it does not copy or change them.

Install

npm install @glion/transform-profile-groups

Use

import { parseHL7v2 } from "@glion/parser";
import { hl7v2TransformProfileGroups } from "@glion/transform-profile-groups";
import { unified } from "unified";
import { VFile } from "vfile";

const tree = parseHL7v2(
  [
    "MSH|^~\\&|LAB|FAC|EMR|RFAC|20241201120000||ORU^R01^ORU_R01|MSG1|P|2.5",
    "PID|1||12345^^^MRN||Doe^John",
    "PV1|1|I",
    "ORC|RE|ORD1",
    "OBR|1|ORD1||CBC",
    "OBX|1|NM|WBC||5.0",
    "OBX|2|NM|RBC||4.1",
  ].join("\r")
);

await unified().use(hl7v2TransformProfileGroups).run(tree, new VFile());

The root now holds:

MSH
PATIENT_RESULT
  PATIENT
    PID
    VISIT
      PV1
  ORDER_OBSERVATION
    ORC
    OBR
    OBSERVATION
      OBX
    OBSERVATION
      OBX

Paths from @glion/util-query address the groups:

import { selectAll, value } from "@glion/util-query";

selectAll(tree, "PATIENT_RESULT.ORDER_OBSERVATION"); // each order
value(tree, "PATIENT_RESULT.ORDER_OBSERVATION[1].OBSERVATION[2].OBX.5")?.value; // => "4.1"

Options

| Option | Type | Default | Description | | ---------------- | ------------------------------------------------------ | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | definition | EventSchema \| (context) => EventSchema \| undefined | the schema MSH-9 names | The event schema to group by, or a function of { tree, file } that returns one, sync or async. undefined falls back to the schema MSH-9 names. | | allowZSegments | boolean | true | Whether a Z-segment the event schema does not name fits at any position, as HL7v2 allows (v2.5.1 §2.11). When false, such a segment leaves the tree flat. |

An event schema of your own groups a message the bundled schemas do not define, such as one with a site's Z-segment:

import type { EventSchema } from "@glion/profiles";

const definition: EventSchema = {
  id: "ZAD_Z01",
  elements: [
    { type: "segment", name: "MSH", optional: false, repeating: false },
    { type: "segment", name: "PID", optional: false, repeating: false },
    {
      type: "group",
      id: "VISIT",
      name: "VISIT",
      optional: false,
      repeating: false,
      elements: [
        { type: "segment", name: "PV1", optional: false, repeating: false },
        { type: "segment", name: "ZPV", optional: true, repeating: false },
      ],
    },
  ],
};

await unified()
  .use(hl7v2TransformProfileGroups, { definition })
  .run(tree, new VFile());
// MSH, PID, VISIT(PV1, ZPV)

API

unified().use(hl7v2TransformProfileGroups[, options])

Replaces the root's segments with nested Group nodes holding the same segment nodes, in the same order.

import type { Root } from "@glion/ast";
import type { EventSchema } from "@glion/profiles";
import type { Plugin } from "unified";
import type { VFile } from "vfile";

interface TransformProfileGroupsContext {
  tree: Root;
  file: VFile;
}

interface TransformProfileGroupsOptions {
  definition?:
    | EventSchema
    | ((
        context: TransformProfileGroupsContext
      ) => EventSchema | undefined | Promise<EventSchema | undefined>);
  allowZSegments?: boolean;
}

declare const hl7v2TransformProfileGroups: Plugin<
  [TransformProfileGroupsOptions?],
  Root,
  Root
>;
export default hl7v2TransformProfileGroups;
Requires

Without options.definition: a message whose MSH-12 and MSH-9 name a bundled event schema. MSH-9.3 names the schema; when it is empty, MSH-9.1 and MSH-9.2 name the event, and the version's event map gives its schema.

Returns

Async transformer. Mutates the tree in place and returns it.

Throws

When the event schema is invalid: it has no elements, a segment has no name, a group has no ID, no name, or no elements, a choice has no alternatives, or a choice alternative can match no segment. When a bundled event schema fails to load.

Behavior

  • Each Group has type: "group", the group's id, such as ORDER_OBSERVATION or PATIENT_VISIT, its name in title case, such as Order Observation or Patient Visit, and a position from the start of its first segment to the end of its last.
  • Each occurrence of a repeating group is its own Group node: two results give two OBSERVATION nodes.
  • A choice, the standard's < OBR | RXO >, adds no node: the chosen segment sits in the enclosing group.
  • A group occurrence that holds no segment is left out.
  • Where the schema admits more than one grouping, the plugin enters an optional element rather than skip it, repeats an element rather than leave it, and takes the earlier alternative of a choice. A segment therefore continues the group it is in before it starts a new enclosing one: in an ORU_R01, an ORC after an OBX starts a new ORDER_OBSERVATION in the current PATIENT_RESULT.
  • A Z-segment, a segment ID that starts with Z, that the schema does not name goes right after the segment before it, in that segment's group: in an ORU_R01, a ZPI after the PID sits in PATIENT, and a ZDS after the OBR in ORDER_OBSERVATION. Consecutive Z-segments stay together, in order, and a Z-segment before every segment the schema names stays at the top level. A Z-segment the schema names is placed where the schema puts it. With allowZSegments: false, a Z-segment the schema does not name leaves the tree flat.
  • A tree that already holds a group, from a first run or from another plugin, is left as it is, and definition is not called for it.
  • The tree is also left unchanged when there is no event schema, or when the segments do not fit the schema: a segment out of order, a required segment missing, or a segment the schema does not define that is not a Z-segment. @glion/lint-profile-segment-order reports those messages.
  • Running it twice changes nothing.

Grouping does not change serialization: toHl7v2 writes the same text. Profile annotation and lint plugins read segments at any depth, so they run before or after it.

Grouping changes the paths of the segments it nests. A @glion/util-query path names every group from the message down, so after grouping PID.3.1 returns null and the patient identifier is PATIENT_RESULT.PATIENT.PID.3.1. Segments left at the top level, such as MSH, keep their paths.

Part of Glion

@glion/transform-profile-groups is part of Glion, the application framework for HL7v2. See the Glion README for the full package catalog and architecture.