@glion/transform-profile-groups
v0.27.1
Published
Unified plugin to group HL7v2 segments into the segment groups their event schema defines
Maintainers
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-groupsUse
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
OBXPaths 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
Grouphastype: "group", the group'sid, such asORDER_OBSERVATIONorPATIENT_VISIT, itsnamein title case, such asOrder ObservationorPatient Visit, and apositionfrom the start of its first segment to the end of its last. - Each occurrence of a repeating group is its own
Groupnode: two results give twoOBSERVATIONnodes. - 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, anORCafter anOBXstarts a newORDER_OBSERVATIONin the currentPATIENT_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 anORU_R01, aZPIafter thePIDsits inPATIENT, and aZDSafter theOBRinORDER_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. WithallowZSegments: 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
definitionis 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-orderreports 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.
