@glion/to-hl7v2 0.26.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/dist/index.js +237 -299
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
package/LICENSE
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,103 +1,95 @@
|
|
|
1
1
|
import { DEFAULT_DELIMITERS } from "@glion/utils";
|
|
2
2
|
//#region ../util-query/dist/index.js
|
|
3
|
+
function sentence(code, path) {
|
|
4
|
+
switch (code) {
|
|
5
|
+
case "EMPTY_PATH": return "The path is empty; a path is `[GROUP[N].]...NAME[N][.FIELD[REPETITION][.COMPONENT[.SUBCOMPONENT]]]`, or `FIELD[REPETITION][.COMPONENT[.SUBCOMPONENT]]` read from a segment, with positions from 1, such as `PID.5.1` or `5.1`.";
|
|
6
|
+
case "INVALID_PATH": return `Path \`${path}\` does not follow the path grammar; a path is \`[GROUP[N].]...NAME[N][.FIELD[REPETITION][.COMPONENT[.SUBCOMPONENT]]]\`, or \`FIELD[REPETITION][.COMPONENT[.SUBCOMPONENT]]\` read from a segment, with positions from 1, such as \`PID.5.1\` or \`5.1\`.`;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
/** A path that `@glion/util-query` cannot read. */
|
|
10
|
+
var QueryError = class extends Error {
|
|
11
|
+
name = "QueryError";
|
|
12
|
+
code;
|
|
13
|
+
path;
|
|
14
|
+
constructor(code, path) {
|
|
15
|
+
super(sentence(code, path));
|
|
16
|
+
this.code = code;
|
|
17
|
+
this.path = path;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
3
20
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* Format:
|
|
7
|
-
* [GROUP[N]-]...[GROUP[N]-]NAME[N][-FIELD[REPETITION][.COMPONENT[.SUBCOMPONENT]]]
|
|
8
|
-
*
|
|
9
|
-
* **Design Philosophy**: Groups vs Segments are distinguished by POSITION and
|
|
10
|
-
* USAGE, not name length:
|
|
21
|
+
* Canonical HL7 path grammar, every step separated with `.`:
|
|
11
22
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* - **Target (Segments)**: The final name in the path is the query target.
|
|
15
|
-
* Whether it's a segment or group is determined by:
|
|
16
|
-
*
|
|
17
|
-
* 1. Field access (-.digit): Definitively a segment → `ORC-1`, `ORDER-ORC-1`
|
|
18
|
-
* 2. No field access: Query the AST to see what exists → `ORC`, `ORDER`
|
|
19
|
-
*
|
|
20
|
-
* This approach:
|
|
21
|
-
*
|
|
22
|
-
* - Makes no assumptions about name length (works with standard 3-char segments
|
|
23
|
-
* AND edge cases)
|
|
24
|
-
* - Lets the path structure indicate intent (field access = segment internals)
|
|
25
|
-
* - Allows the AST to be the source of truth for what exists
|
|
26
|
-
*
|
|
27
|
-
* Examples:
|
|
28
|
-
*
|
|
29
|
-
* - `MSH-3` → MSH is segment (has field access)
|
|
30
|
-
* - `ORDER-ORC` → ORDER is navigation, ORC is target (could be segment or nested
|
|
31
|
-
* group)
|
|
32
|
-
* - `ORDER-ORC-1` → ORDER is navigation, ORC is segment (has field access)
|
|
33
|
-
*/
|
|
34
|
-
const PATH_REGEX = /^((?:[A-Z][A-Z0-9_]*(?:\[\d+\])?-)*)([A-Z][A-Z0-9_]*)(?:\[(\d+)\])?(?:-(\d+)(?:(?:\[(\d+)\])?(?:\.(\d+)(?:\.(\d+))?)?)?)?$/;
|
|
35
|
-
/**
|
|
36
|
-
* Cache for parsed paths to avoid re-parsing the same path multiple times.
|
|
37
|
-
* No eviction — the realistic set of unique paths in an application is
|
|
38
|
-
* small (50-100 entries) and the memory cost is negligible.
|
|
39
|
-
*/
|
|
40
|
-
const parseCache = /* @__PURE__ */ new Map();
|
|
41
|
-
/**
|
|
42
|
-
* Pre-computed PathParts for frequently accessed MSH fields.
|
|
23
|
+
* [GROUP[N].]...NAME[N][.FIELD[REPETITION][.COMPONENT[.SUBCOMPONENT]]]
|
|
24
|
+
* FIELD[REPETITION][.COMPONENT[.SUBCOMPONENT]]
|
|
43
25
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
26
|
+
* Names start with a letter and positions are numbers from 1, so the first
|
|
27
|
+
* numeric step is the field. The final name is the query target. Field
|
|
28
|
+
* access makes it a segment (`ORDER.ORC.1`); without it the AST decides
|
|
29
|
+
* whether it names a segment or a group (`ORDER.ORC`, `ORDER`). A path that
|
|
30
|
+
* starts with the field names no segment (`5.1`).
|
|
47
31
|
*/
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"MSH-12": {
|
|
54
|
-
field: 12,
|
|
55
|
-
segment: { name: "MSH" }
|
|
56
|
-
},
|
|
57
|
-
"MSH-3": {
|
|
32
|
+
const PATH_REGEX = /^(?:([A-Z][A-Z0-9_]*(?:\[[1-9]\d*\])?(?:\.[A-Z][A-Z0-9_]*(?:\[[1-9]\d*\])?)*)(?:\.(?=[1-9])|$))?(?:([1-9]\d*)(?:\[([1-9]\d*)\])?(?:\.([1-9]\d*)(?:\.([1-9]\d*))?)?)?$/;
|
|
33
|
+
const NAVIGATION_STEP_REGEX = /([A-Z][A-Z0-9_]*)(?:\[(\d+)\])?/g;
|
|
34
|
+
/** Parts of the MSH paths that plugins and lint rules read on every message. */
|
|
35
|
+
const PRECOMPUTED_PATHS = new Map([
|
|
36
|
+
["MSH.3", () => ({
|
|
58
37
|
field: 3,
|
|
59
38
|
segment: { name: "MSH" }
|
|
60
|
-
},
|
|
61
|
-
"MSH
|
|
39
|
+
})],
|
|
40
|
+
["MSH.4", () => ({
|
|
62
41
|
field: 4,
|
|
63
42
|
segment: { name: "MSH" }
|
|
64
|
-
},
|
|
65
|
-
"MSH
|
|
43
|
+
})],
|
|
44
|
+
["MSH.5", () => ({
|
|
66
45
|
field: 5,
|
|
67
46
|
segment: { name: "MSH" }
|
|
68
|
-
},
|
|
69
|
-
"MSH
|
|
47
|
+
})],
|
|
48
|
+
["MSH.6", () => ({
|
|
70
49
|
field: 6,
|
|
71
50
|
segment: { name: "MSH" }
|
|
72
|
-
},
|
|
73
|
-
"MSH
|
|
51
|
+
})],
|
|
52
|
+
["MSH.9", () => ({
|
|
74
53
|
field: 9,
|
|
75
54
|
segment: { name: "MSH" }
|
|
76
|
-
},
|
|
77
|
-
"MSH
|
|
55
|
+
})],
|
|
56
|
+
["MSH.9.1", () => ({
|
|
78
57
|
component: 1,
|
|
79
58
|
field: 9,
|
|
80
59
|
segment: { name: "MSH" }
|
|
81
|
-
},
|
|
82
|
-
"MSH
|
|
60
|
+
})],
|
|
61
|
+
["MSH.9.2", () => ({
|
|
83
62
|
component: 2,
|
|
84
63
|
field: 9,
|
|
85
64
|
segment: { name: "MSH" }
|
|
86
|
-
},
|
|
87
|
-
"MSH
|
|
65
|
+
})],
|
|
66
|
+
["MSH.9.3", () => ({
|
|
88
67
|
component: 3,
|
|
89
68
|
field: 9,
|
|
90
69
|
segment: { name: "MSH" }
|
|
91
|
-
}
|
|
92
|
-
|
|
70
|
+
})],
|
|
71
|
+
["MSH.10", () => ({
|
|
72
|
+
field: 10,
|
|
73
|
+
segment: { name: "MSH" }
|
|
74
|
+
})],
|
|
75
|
+
["MSH.12", () => ({
|
|
76
|
+
field: 12,
|
|
77
|
+
segment: { name: "MSH" }
|
|
78
|
+
})],
|
|
79
|
+
["MSH.12.1", () => ({
|
|
80
|
+
component: 1,
|
|
81
|
+
field: 12,
|
|
82
|
+
segment: { name: "MSH" }
|
|
83
|
+
})]
|
|
84
|
+
]);
|
|
93
85
|
/**
|
|
94
86
|
* Parse an HL7 path string into structured parts.
|
|
95
|
-
*
|
|
96
|
-
*
|
|
87
|
+
*
|
|
88
|
+
* Returns a new object on every call.
|
|
97
89
|
*
|
|
98
90
|
* @example
|
|
99
91
|
* ```typescript
|
|
100
|
-
* parse("PID
|
|
92
|
+
* parse("PID.5[1].2.1");
|
|
101
93
|
* // {
|
|
102
94
|
* // segment: { name: 'PID' },
|
|
103
95
|
* // field: 5,
|
|
@@ -111,231 +103,168 @@ const HOT_PATHS = {
|
|
|
111
103
|
* @returns Structured path components
|
|
112
104
|
*/
|
|
113
105
|
function parse(path) {
|
|
114
|
-
const
|
|
115
|
-
if (
|
|
116
|
-
|
|
117
|
-
if (cached) return cached;
|
|
118
|
-
const result = parseImpl(path);
|
|
119
|
-
parseCache.set(path, result);
|
|
120
|
-
return result;
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Internal implementation of path parsing.
|
|
124
|
-
*/
|
|
125
|
-
function parseImpl(path) {
|
|
126
|
-
if (!path || typeof path !== "string") throw new Error(`Path must be a non-empty string, got: ${path}`);
|
|
127
|
-
if (path.trim() !== path) throw new Error(`Path cannot contain leading/trailing spaces: "${path}"`);
|
|
106
|
+
const precomputed = PRECOMPUTED_PATHS.get(path);
|
|
107
|
+
if (precomputed) return precomputed();
|
|
108
|
+
if (path === "") throw new QueryError("EMPTY_PATH", path);
|
|
128
109
|
const match = PATH_REGEX.exec(path);
|
|
129
|
-
if (!match) throw new
|
|
130
|
-
const [,
|
|
131
|
-
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
if (
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const group = { name };
|
|
145
|
-
if (repStr) {
|
|
146
|
-
const repetition = Number.parseInt(repStr, 10);
|
|
147
|
-
if (repetition < 1) throw new Error(`Group repetition must be ≥1, got: ${repStr} in "${path}"`);
|
|
148
|
-
group.repetition = repetition;
|
|
149
|
-
}
|
|
150
|
-
groups.push(group);
|
|
151
|
-
}
|
|
152
|
-
if (groups.length > 0) parts.groups = groups;
|
|
153
|
-
}
|
|
154
|
-
if (fieldStr) {
|
|
155
|
-
const field = Number.parseInt(fieldStr, 10);
|
|
156
|
-
if (field < 1) throw new Error(`Field number must be ≥1, got: ${fieldStr}`);
|
|
157
|
-
parts.field = field;
|
|
158
|
-
}
|
|
159
|
-
if (repetitionStr) {
|
|
160
|
-
const repetition = Number.parseInt(repetitionStr, 10);
|
|
161
|
-
if (repetition < 1) throw new Error(`Repetition number must be ≥1, got: ${repetitionStr}`);
|
|
162
|
-
parts.repetition = repetition;
|
|
163
|
-
}
|
|
164
|
-
if (componentStr) {
|
|
165
|
-
const component = Number.parseInt(componentStr, 10);
|
|
166
|
-
if (component < 1) throw new Error(`Component number must be ≥1, got: ${componentStr}`);
|
|
167
|
-
parts.component = component;
|
|
168
|
-
}
|
|
169
|
-
if (subcomponentStr) {
|
|
170
|
-
const subcomponent = Number.parseInt(subcomponentStr, 10);
|
|
171
|
-
if (subcomponent < 1) throw new Error(`Subcomponent number must be ≥1, got: ${subcomponentStr}`);
|
|
172
|
-
parts.subcomponent = subcomponent;
|
|
173
|
-
}
|
|
110
|
+
if (!match) throw new QueryError("INVALID_PATH", path);
|
|
111
|
+
const [, navigation = "", field, repetition, component, subcomponent] = match;
|
|
112
|
+
const steps = [];
|
|
113
|
+
for (const [, name, position] of navigation.matchAll(NAVIGATION_STEP_REGEX)) steps.push(position === void 0 ? { name } : {
|
|
114
|
+
name,
|
|
115
|
+
repetition: Number(position)
|
|
116
|
+
});
|
|
117
|
+
const parts = {};
|
|
118
|
+
const segment = steps.pop();
|
|
119
|
+
if (segment !== void 0) parts.segment = segment;
|
|
120
|
+
if (steps.length > 0) parts.groups = steps;
|
|
121
|
+
if (field !== void 0) parts.field = Number(field);
|
|
122
|
+
if (repetition !== void 0) parts.repetition = Number(repetition);
|
|
123
|
+
if (component !== void 0) parts.component = Number(component);
|
|
124
|
+
if (subcomponent !== void 0) parts.subcomponent = Number(subcomponent);
|
|
174
125
|
return parts;
|
|
175
126
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
const matchedGroups = collectGroups(scope, targetName, ancestors);
|
|
188
|
-
if (matchedGroups.length > 0) {
|
|
189
|
-
const match = matchedGroups[(targetRepetition ?? 1) - 1];
|
|
190
|
-
if (match) return [match.group, match.ancestors];
|
|
127
|
+
/** The name a path gives a node: a segment's name, or a group's ID. */
|
|
128
|
+
const keyOf = (node) => {
|
|
129
|
+
switch (node.type) {
|
|
130
|
+
case "root":
|
|
131
|
+
case "field":
|
|
132
|
+
case "field-repetition":
|
|
133
|
+
case "component":
|
|
134
|
+
case "subcomponent": return;
|
|
135
|
+
case "segment": return node.name;
|
|
136
|
+
case "group": return node.id;
|
|
191
137
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
if (!match) return null;
|
|
202
|
-
return [match.segment, match.ancestors];
|
|
203
|
-
}
|
|
204
|
-
function followGroups(root, groups, ancestorChain) {
|
|
205
|
-
let children = filterSegmentsAndGroups(root.children);
|
|
206
|
-
for (const locator of groups) {
|
|
207
|
-
const matchedGroups = children.filter((node) => node.type === "group" && node.id === locator.name);
|
|
208
|
-
if (matchedGroups.length === 0) return null;
|
|
209
|
-
const selected = matchedGroups[(locator.repetition ?? 1) - 1];
|
|
210
|
-
if (!selected) return null;
|
|
211
|
-
ancestorChain.push(selected);
|
|
212
|
-
children = filterSegmentsAndGroups(selected.children);
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* The `position`th of `children` (1-based) when given; otherwise every one
|
|
141
|
+
* when `every` is set, or the first.
|
|
142
|
+
*/
|
|
143
|
+
function pick(children, position, every) {
|
|
144
|
+
if (position !== void 0) {
|
|
145
|
+
const child = children[position - 1];
|
|
146
|
+
return child === void 0 ? [] : [child];
|
|
213
147
|
}
|
|
214
|
-
return children;
|
|
148
|
+
return every ? children : children.slice(0, 1);
|
|
215
149
|
}
|
|
216
|
-
|
|
150
|
+
/**
|
|
151
|
+
* The children of `parent` a path step names `name`, segments and groups
|
|
152
|
+
* together: the `position`th (1-based) when given; otherwise every one when
|
|
153
|
+
* `every` is set, or the first.
|
|
154
|
+
*/
|
|
155
|
+
function stepChildren(parent, name, position, every) {
|
|
217
156
|
const result = [];
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
if (node.type === "group") {
|
|
226
|
-
const nextAncestors = [...ancestors, node];
|
|
227
|
-
result.push(...collectSegments(filterSegmentsAndGroups(node.children), targetSegmentName, nextAncestors));
|
|
157
|
+
const target = position ?? 1;
|
|
158
|
+
let count = 0;
|
|
159
|
+
for (const child of parent.children) {
|
|
160
|
+
if (keyOf(child) !== name) continue;
|
|
161
|
+
if (every && position === void 0) {
|
|
162
|
+
result.push(child);
|
|
163
|
+
continue;
|
|
228
164
|
}
|
|
165
|
+
count += 1;
|
|
166
|
+
if (count === target) return [child];
|
|
229
167
|
}
|
|
230
168
|
return result;
|
|
231
169
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
170
|
+
/** The children of each scope that `step` names, with their ancestors. */
|
|
171
|
+
function advance(scopes, step, every) {
|
|
172
|
+
const next = [];
|
|
173
|
+
for (const scope of scopes) for (const node of stepChildren(scope.node, step.name, step.repetition, every)) next.push({
|
|
174
|
+
ancestors: [...scope.ancestors, scope.node],
|
|
175
|
+
node
|
|
176
|
+
});
|
|
177
|
+
return next;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* The field, repetitions, components, or subcomponents `parts` addresses in
|
|
181
|
+
* `segment`.
|
|
182
|
+
*/
|
|
183
|
+
function resolveField(segment, ancestors, fieldNumber, parts, every) {
|
|
184
|
+
const field = segment.children[fieldNumber - 1];
|
|
185
|
+
if (!field) return [];
|
|
186
|
+
const fieldAncestors = [...ancestors, segment];
|
|
187
|
+
if (parts.repetition === void 0 && parts.component === void 0) return [{
|
|
188
|
+
ancestors: fieldAncestors,
|
|
189
|
+
node: field
|
|
190
|
+
}];
|
|
191
|
+
const matches = [];
|
|
192
|
+
for (const repetition of pick(field.children ?? [], parts.repetition, every)) {
|
|
193
|
+
const repetitionAncestors = [...fieldAncestors, field];
|
|
194
|
+
if (parts.component === void 0) {
|
|
195
|
+
matches.push({
|
|
196
|
+
ancestors: repetitionAncestors,
|
|
197
|
+
node: repetition
|
|
198
|
+
});
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
const component = repetition.children?.[parts.component - 1];
|
|
202
|
+
if (!component) continue;
|
|
203
|
+
const componentAncestors = [...repetitionAncestors, repetition];
|
|
204
|
+
if (parts.subcomponent === void 0) {
|
|
205
|
+
matches.push({
|
|
206
|
+
ancestors: componentAncestors,
|
|
207
|
+
node: component
|
|
208
|
+
});
|
|
209
|
+
continue;
|
|
242
210
|
}
|
|
211
|
+
const subcomponent = component.children?.[parts.subcomponent - 1];
|
|
212
|
+
if (subcomponent) matches.push({
|
|
213
|
+
ancestors: [...componentAncestors, component],
|
|
214
|
+
node: subcomponent
|
|
215
|
+
});
|
|
243
216
|
}
|
|
244
|
-
return
|
|
245
|
-
}
|
|
246
|
-
function locateField(segment, fieldNum, parentAncestors) {
|
|
247
|
-
const field = getFields(segment)[fieldNum - 1];
|
|
248
|
-
if (!field) return null;
|
|
249
|
-
return [field, [...parentAncestors, segment]];
|
|
250
|
-
}
|
|
251
|
-
function locateRepetition(field, repetition, parentAncestors) {
|
|
252
|
-
if (repetition < 1) return null;
|
|
253
|
-
const node = field.children?.[repetition - 1];
|
|
254
|
-
if (!node) return null;
|
|
255
|
-
return [node, [...parentAncestors, field]];
|
|
256
|
-
}
|
|
257
|
-
function locateComponent(repetition, componentNum, parentAncestors) {
|
|
258
|
-
if (componentNum < 1) return null;
|
|
259
|
-
const component = repetition.children?.[componentNum - 1];
|
|
260
|
-
if (!component) return null;
|
|
261
|
-
return [component, [...parentAncestors, repetition]];
|
|
262
|
-
}
|
|
263
|
-
function locateSubcomponent(component, subcomponentNum, parentAncestors) {
|
|
264
|
-
if (subcomponentNum < 1) return null;
|
|
265
|
-
const node = component.children?.[subcomponentNum - 1];
|
|
266
|
-
if (!node) return null;
|
|
267
|
-
return [node, [...parentAncestors, component]];
|
|
268
|
-
}
|
|
269
|
-
function getSegmentName(segment) {
|
|
270
|
-
return segment.name;
|
|
271
|
-
}
|
|
272
|
-
function getFields(segment) {
|
|
273
|
-
return segment.children;
|
|
217
|
+
return matches;
|
|
274
218
|
}
|
|
275
|
-
|
|
276
|
-
|
|
219
|
+
/**
|
|
220
|
+
* The nodes `parts` addresses under `start`, in document order, each with its
|
|
221
|
+
* own ancestors array, which begins at `start`.
|
|
222
|
+
*
|
|
223
|
+
* Every step names a direct child of the node before it; the first step
|
|
224
|
+
* names a direct child of `start`. A step's `[n]` counts the children with
|
|
225
|
+
* that name, segments and groups together. A step without `[n]` matches the
|
|
226
|
+
* first such child, or every one when `every` is set; so does a field
|
|
227
|
+
* without a repetition when the path names a component.
|
|
228
|
+
*/
|
|
229
|
+
function resolve(start, parts, every) {
|
|
230
|
+
let scopes = [{
|
|
231
|
+
ancestors: [],
|
|
232
|
+
node: start
|
|
233
|
+
}];
|
|
234
|
+
for (const group of parts.groups ?? []) scopes = advance(scopes, group, every);
|
|
235
|
+
if (parts.segment !== void 0) scopes = advance(scopes, parts.segment, every);
|
|
236
|
+
if (parts.field === void 0) return scopes;
|
|
237
|
+
const matches = [];
|
|
238
|
+
for (const { node, ancestors } of scopes) {
|
|
239
|
+
if (node.type !== "segment") continue;
|
|
240
|
+
for (const match of resolveField(node, ancestors, parts.field, parts, every)) matches.push(match);
|
|
241
|
+
}
|
|
242
|
+
return matches;
|
|
277
243
|
}
|
|
278
244
|
/**
|
|
279
|
-
*
|
|
280
|
-
*
|
|
245
|
+
* The node `path` addresses under `node`, with its ancestors from `node`, or
|
|
246
|
+
* `null`.
|
|
281
247
|
*
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
*
|
|
248
|
+
* Every step of `path` names a direct child of the node before it; the first
|
|
249
|
+
* step names a direct child of `node`, so a path read from a segment starts
|
|
250
|
+
* with the field. A step without `[n]` names the first such child, so
|
|
251
|
+
* `select` returns `null` when that child does not lead to a match, even if a
|
|
252
|
+
* later one does; `selectAll` returns every match.
|
|
285
253
|
*
|
|
286
254
|
* @example
|
|
287
255
|
* ```typescript
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
*
|
|
291
|
-
* result.ancestors; // [Root, Segment]
|
|
292
|
-
* }
|
|
256
|
+
* select(root, "PID.5"); // { node: Field, ancestors: [Root, Segment] }
|
|
257
|
+
* select(root, "PATIENT_RESULT.PATIENT.PID.5");
|
|
258
|
+
* select(segment, "5.1"); // { node: Component, ancestors: [Segment, Field, FieldRepetition] }
|
|
293
259
|
* ```;
|
|
294
260
|
*
|
|
295
|
-
* @param
|
|
296
|
-
* @param path - The
|
|
297
|
-
* @returns
|
|
261
|
+
* @param node - The message, group, or segment to read from.
|
|
262
|
+
* @param path - The path to the node.
|
|
263
|
+
* @returns The node and its ancestors, or `null` when nothing matches.
|
|
298
264
|
*/
|
|
299
|
-
function select(
|
|
300
|
-
const
|
|
301
|
-
|
|
302
|
-
const result = locateSegmentOrGroup(root, parts);
|
|
303
|
-
if (!result) return null;
|
|
304
|
-
return {
|
|
305
|
-
ancestors: result[1],
|
|
306
|
-
node: result[0]
|
|
307
|
-
};
|
|
308
|
-
}
|
|
309
|
-
const segmentResult = locateSegment(root, parts);
|
|
310
|
-
if (!segmentResult) return null;
|
|
311
|
-
const [segment, segmentAncestors] = segmentResult;
|
|
312
|
-
const fieldResult = locateField(segment, parts.field, segmentAncestors);
|
|
313
|
-
if (!fieldResult) return null;
|
|
314
|
-
const [field, fieldAncestors] = fieldResult;
|
|
315
|
-
if (parts.component === void 0 && parts.subcomponent === void 0 && parts.repetition === void 0) return {
|
|
316
|
-
ancestors: fieldAncestors,
|
|
317
|
-
node: field
|
|
318
|
-
};
|
|
319
|
-
const repetitionResult = locateRepetition(field, parts.repetition ?? 1, fieldAncestors);
|
|
320
|
-
if (!repetitionResult) return null;
|
|
321
|
-
const [repetitionNode, repetitionAncestors] = repetitionResult;
|
|
322
|
-
if (parts.component === void 0) return {
|
|
323
|
-
ancestors: repetitionAncestors,
|
|
324
|
-
node: repetitionNode
|
|
325
|
-
};
|
|
326
|
-
const componentResult = locateComponent(repetitionNode, parts.component, repetitionAncestors);
|
|
327
|
-
if (!componentResult) return null;
|
|
328
|
-
const [componentNode, componentAncestors] = componentResult;
|
|
329
|
-
if (parts.subcomponent === void 0) return {
|
|
330
|
-
ancestors: componentAncestors,
|
|
331
|
-
node: componentNode
|
|
332
|
-
};
|
|
333
|
-
const subResult = locateSubcomponent(componentNode, parts.subcomponent, componentAncestors);
|
|
334
|
-
if (!subResult) return null;
|
|
335
|
-
return {
|
|
336
|
-
ancestors: subResult[1],
|
|
337
|
-
node: subResult[0]
|
|
338
|
-
};
|
|
265
|
+
function select(node, path) {
|
|
266
|
+
const [match] = resolve(node, parse(path), false);
|
|
267
|
+
return match ?? null;
|
|
339
268
|
}
|
|
340
269
|
/**
|
|
341
270
|
* Get the string value at the path, drilling down through single-child nodes
|
|
@@ -344,7 +273,7 @@ function select(root, path) {
|
|
|
344
273
|
* This is a convenience function that automatically traverses through container
|
|
345
274
|
* nodes (Field → FieldRepetition → Component → Subcomponent) to extract the
|
|
346
275
|
* primary string value. When a container has multiple children, the first child
|
|
347
|
-
* is selected (e.g., `value(tree, "MSH
|
|
276
|
+
* is selected (e.g., `value(tree, "MSH.12")` returns the first component of a
|
|
348
277
|
* composite VID field).
|
|
349
278
|
*
|
|
350
279
|
* Nodes with no children return `value: null` to differentiate between empty
|
|
@@ -352,42 +281,51 @@ function select(root, path) {
|
|
|
352
281
|
*
|
|
353
282
|
* @example
|
|
354
283
|
* ```typescript
|
|
355
|
-
* const result = value(root, "PID
|
|
284
|
+
* const result = value(root, "PID.5.1");
|
|
356
285
|
* if (result) {
|
|
357
286
|
* console.log(result.value); // string | null
|
|
358
287
|
* console.log(result.node.type); // 'subcomponent'
|
|
359
288
|
* console.log(result.ancestors); // [Root, Segment, Field, ...]
|
|
360
289
|
* }
|
|
290
|
+
*
|
|
291
|
+
* value(segment, "5.1"); // the same value, read from the PID segment
|
|
361
292
|
* ```;
|
|
362
293
|
*
|
|
363
|
-
* @param
|
|
294
|
+
* @param node - The message, group, or segment to read from
|
|
364
295
|
* @param path - The HL7 path string
|
|
365
|
-
* @returns Object containing the value, node, and ancestors
|
|
366
|
-
* found
|
|
296
|
+
* @returns Object containing the value, node, and ancestors from `node`, or
|
|
297
|
+
* null if not found
|
|
367
298
|
*/
|
|
368
|
-
function value(
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
299
|
+
function value(node, path) {
|
|
300
|
+
const selected = select(node, path);
|
|
301
|
+
return selected ? drill(selected.node, selected.ancestors) : null;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* The first subcomponent under `node`, with its value, or `node` with value
|
|
305
|
+
* `null` when a field, repetition, or component on the way has no children.
|
|
306
|
+
* `null` for a root, group, or segment.
|
|
307
|
+
*/
|
|
308
|
+
function drill(node, ancestors) {
|
|
309
|
+
switch (node.type) {
|
|
310
|
+
case "root":
|
|
311
|
+
case "group":
|
|
312
|
+
case "segment": return null;
|
|
313
|
+
case "subcomponent": return {
|
|
314
|
+
ancestors,
|
|
378
315
|
node,
|
|
379
|
-
value:
|
|
316
|
+
value: node.value
|
|
380
317
|
};
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
318
|
+
case "field":
|
|
319
|
+
case "field-repetition":
|
|
320
|
+
case "component": {
|
|
321
|
+
const first = node.children?.[0];
|
|
322
|
+
return first ? drill(first, [...ancestors, node]) : {
|
|
323
|
+
ancestors,
|
|
324
|
+
node,
|
|
325
|
+
value: null
|
|
326
|
+
};
|
|
327
|
+
}
|
|
385
328
|
}
|
|
386
|
-
return {
|
|
387
|
-
ancestors,
|
|
388
|
-
node,
|
|
389
|
-
value: node.value
|
|
390
|
-
};
|
|
391
329
|
}
|
|
392
330
|
/** Keys of MSH-2 encoding characters in positional order. */
|
|
393
331
|
const MSH2_KEYS = [
|
|
@@ -410,9 +348,9 @@ const MSH2_KEYS = [
|
|
|
410
348
|
*/
|
|
411
349
|
function delimiters(root) {
|
|
412
350
|
const result = { ...DEFAULT_DELIMITERS };
|
|
413
|
-
const msh1 = value(root, "MSH
|
|
351
|
+
const msh1 = value(root, "MSH.1")?.value;
|
|
414
352
|
if (msh1 && msh1.length === 1) result.field = msh1;
|
|
415
|
-
const msh2 = value(root, "MSH
|
|
353
|
+
const msh2 = value(root, "MSH.2")?.value;
|
|
416
354
|
if (msh2) {
|
|
417
355
|
const chars = [...msh2];
|
|
418
356
|
for (const [i, key] of MSH2_KEYS.entries()) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["queryDelimiters","delimiters","unsupported"],"sources":["../../util-query/dist/index.js","../src/index.ts"],"sourcesContent":["import { DEFAULT_DELIMITERS } from \"@glion/utils\";\n//#region src/parse.ts\n/**\n* Regular expression for canonical HL7 paths.\n*\n* Format:\n* [GROUP[N]-]...[GROUP[N]-]NAME[N][-FIELD[REPETITION][.COMPONENT[.SUBCOMPONENT]]]\n*\n* **Design Philosophy**: Groups vs Segments are distinguished by POSITION and\n* USAGE, not name length:\n*\n* - **Navigation (Groups)**: Names appearing as prefixes (before the final name)\n* are treated as group navigation: `ORDER-ORC`, `ORDER-TIMING-TQ1`\n* - **Target (Segments)**: The final name in the path is the query target.\n* Whether it's a segment or group is determined by:\n*\n* 1. Field access (-.digit): Definitively a segment → `ORC-1`, `ORDER-ORC-1`\n* 2. No field access: Query the AST to see what exists → `ORC`, `ORDER`\n*\n* This approach:\n*\n* - Makes no assumptions about name length (works with standard 3-char segments\n* AND edge cases)\n* - Lets the path structure indicate intent (field access = segment internals)\n* - Allows the AST to be the source of truth for what exists\n*\n* Examples:\n*\n* - `MSH-3` → MSH is segment (has field access)\n* - `ORDER-ORC` → ORDER is navigation, ORC is target (could be segment or nested\n* group)\n* - `ORDER-ORC-1` → ORDER is navigation, ORC is segment (has field access)\n*/\nconst PATH_REGEX = /^((?:[A-Z][A-Z0-9_]*(?:\\[\\d+\\])?-)*)([A-Z][A-Z0-9_]*)(?:\\[(\\d+)\\])?(?:-(\\d+)(?:(?:\\[(\\d+)\\])?(?:\\.(\\d+)(?:\\.(\\d+))?)?)?)?$/;\n/**\n* Cache for parsed paths to avoid re-parsing the same path multiple times.\n* No eviction — the realistic set of unique paths in an application is\n* small (50-100 entries) and the memory cost is negligible.\n*/\nconst parseCache = /* @__PURE__ */ new Map();\n/**\n* Pre-computed PathParts for frequently accessed MSH fields.\n*\n* Multiple plugins and lint rules read MSH-9 (message type) and MSH-12\n* (version) on every message. Skipping regex parsing and cache lookups\n* for these paths eliminates ~100ns per call.\n*/\nconst HOT_PATHS = {\n\t\"MSH-10\": {\n\t\tfield: 10,\n\t\tsegment: { name: \"MSH\" }\n\t},\n\t\"MSH-12\": {\n\t\tfield: 12,\n\t\tsegment: { name: \"MSH\" }\n\t},\n\t\"MSH-3\": {\n\t\tfield: 3,\n\t\tsegment: { name: \"MSH\" }\n\t},\n\t\"MSH-4\": {\n\t\tfield: 4,\n\t\tsegment: { name: \"MSH\" }\n\t},\n\t\"MSH-5\": {\n\t\tfield: 5,\n\t\tsegment: { name: \"MSH\" }\n\t},\n\t\"MSH-6\": {\n\t\tfield: 6,\n\t\tsegment: { name: \"MSH\" }\n\t},\n\t\"MSH-9\": {\n\t\tfield: 9,\n\t\tsegment: { name: \"MSH\" }\n\t},\n\t\"MSH-9.1\": {\n\t\tcomponent: 1,\n\t\tfield: 9,\n\t\tsegment: { name: \"MSH\" }\n\t},\n\t\"MSH-9.2\": {\n\t\tcomponent: 2,\n\t\tfield: 9,\n\t\tsegment: { name: \"MSH\" }\n\t},\n\t\"MSH-9.3\": {\n\t\tcomponent: 3,\n\t\tfield: 9,\n\t\tsegment: { name: \"MSH\" }\n\t}\n};\n/**\n* Parse an HL7 path string into structured parts.\n* Results are memoized for performance. Common MSH paths use\n* pre-computed constants to skip parsing entirely.\n*\n* @example\n* ```typescript\n* parse(\"PID-5[1].2.1\");\n* // {\n* // segment: { name: 'PID' },\n* // field: 5,\n* // repetition: 1,\n* // component: 2,\n* // subcomponent: 1\n* // }\n* ```;\n*\n* @param path - HL7 path string to parse\n* @returns Structured path components\n*/\nfunction parse(path) {\n\tconst hot = HOT_PATHS[path];\n\tif (hot) return hot;\n\tconst cached = parseCache.get(path);\n\tif (cached) return cached;\n\tconst result = parseImpl(path);\n\tparseCache.set(path, result);\n\treturn result;\n}\n/**\n* Internal implementation of path parsing.\n*/\nfunction parseImpl(path) {\n\tif (!path || typeof path !== \"string\") throw new Error(`Path must be a non-empty string, got: ${path}`);\n\tif (path.trim() !== path) throw new Error(`Path cannot contain leading/trailing spaces: \"${path}\"`);\n\tconst match = PATH_REGEX.exec(path);\n\tif (!match) throw new Error(`Invalid HL7 path format: \"${path}\". Expected [GROUP[N]-]...NAME[N][-FIELD[REPETITION][.COMPONENT[.SUBCOMPONENT]]].`);\n\tconst [, groupsRaw, segmentName, segmentRep, fieldStr, repetitionStr, componentStr, subcomponentStr] = match;\n\tif (!segmentName) throw new Error(`Path must include a segment identifier: \"${path}\"`);\n\tconst parts = { segment: { name: segmentName } };\n\tif (segmentRep) {\n\t\tconst repetition = Number.parseInt(segmentRep, 10);\n\t\tif (repetition < 1) throw new Error(`Segment repetition must be ≥1, got: ${segmentRep} in \"${path}\"`);\n\t\tparts.segment.repetition = repetition;\n\t}\n\tif (groupsRaw) {\n\t\tconst groups = [];\n\t\tfor (const groupMatch of groupsRaw.matchAll(/([A-Z][A-Z0-9_]*)(?:\\[(\\d+)\\])?-/g)) {\n\t\t\tconst name = groupMatch[1];\n\t\t\tif (!name) continue;\n\t\t\tconst repStr = groupMatch[2];\n\t\t\tconst group = { name };\n\t\t\tif (repStr) {\n\t\t\t\tconst repetition = Number.parseInt(repStr, 10);\n\t\t\t\tif (repetition < 1) throw new Error(`Group repetition must be ≥1, got: ${repStr} in \"${path}\"`);\n\t\t\t\tgroup.repetition = repetition;\n\t\t\t}\n\t\t\tgroups.push(group);\n\t\t}\n\t\tif (groups.length > 0) parts.groups = groups;\n\t}\n\tif (fieldStr) {\n\t\tconst field = Number.parseInt(fieldStr, 10);\n\t\tif (field < 1) throw new Error(`Field number must be ≥1, got: ${fieldStr}`);\n\t\tparts.field = field;\n\t}\n\tif (repetitionStr) {\n\t\tconst repetition = Number.parseInt(repetitionStr, 10);\n\t\tif (repetition < 1) throw new Error(`Repetition number must be ≥1, got: ${repetitionStr}`);\n\t\tparts.repetition = repetition;\n\t}\n\tif (componentStr) {\n\t\tconst component = Number.parseInt(componentStr, 10);\n\t\tif (component < 1) throw new Error(`Component number must be ≥1, got: ${componentStr}`);\n\t\tparts.component = component;\n\t}\n\tif (subcomponentStr) {\n\t\tconst subcomponent = Number.parseInt(subcomponentStr, 10);\n\t\tif (subcomponent < 1) throw new Error(`Subcomponent number must be ≥1, got: ${subcomponentStr}`);\n\t\tparts.subcomponent = subcomponent;\n\t}\n\treturn parts;\n}\n//#endregion\n//#region src/utils.ts\nfunction locateSegmentOrGroup(root, parts) {\n\tconst ancestors = [root];\n\tconst scope = followGroups(root, parts.groups ?? [], ancestors);\n\tif (!scope) return null;\n\tconst targetName = parts.segment.name;\n\tconst targetRepetition = parts.segment.repetition;\n\tconst matchedSegments = collectSegments(scope, targetName, ancestors);\n\tif (matchedSegments.length > 0) {\n\t\tconst match = matchedSegments[(targetRepetition ?? 1) - 1];\n\t\tif (match) return [match.segment, match.ancestors];\n\t}\n\tconst matchedGroups = collectGroups(scope, targetName, ancestors);\n\tif (matchedGroups.length > 0) {\n\t\tconst match = matchedGroups[(targetRepetition ?? 1) - 1];\n\t\tif (match) return [match.group, match.ancestors];\n\t}\n\treturn null;\n}\nfunction locateSegment(root, parts) {\n\tconst ancestors = [root];\n\tconst scope = followGroups(root, parts.groups ?? [], ancestors);\n\tif (!scope) return null;\n\tconst matchedSegments = collectSegments(scope, parts.segment.name, ancestors);\n\tif (matchedSegments.length === 0) return null;\n\tconst match = matchedSegments[(parts.segment.repetition ?? 1) - 1];\n\tif (!match) return null;\n\treturn [match.segment, match.ancestors];\n}\nfunction followGroups(root, groups, ancestorChain) {\n\tlet children = filterSegmentsAndGroups(root.children);\n\tfor (const locator of groups) {\n\t\tconst matchedGroups = children.filter((node) => node.type === \"group\" && node.id === locator.name);\n\t\tif (matchedGroups.length === 0) return null;\n\t\tconst selected = matchedGroups[(locator.repetition ?? 1) - 1];\n\t\tif (!selected) return null;\n\t\tancestorChain.push(selected);\n\t\tchildren = filterSegmentsAndGroups(selected.children);\n\t}\n\treturn children;\n}\n/**\n* Collect all possible scopes when groups can match multiple instances.\n* Used by selectAll to find nodes across all matching groups.\n*/\nfunction collectAllScopes(root, groups) {\n\tif (groups.length === 0) return [{\n\t\tancestors: [root],\n\t\tscope: filterSegmentsAndGroups(root.children)\n\t}];\n\tconst results = [];\n\tconst firstLocator = groups[0];\n\tconst remainingGroups = groups.slice(1);\n\tif (!firstLocator) return [{\n\t\tancestors: [root],\n\t\tscope: filterSegmentsAndGroups(root.children)\n\t}];\n\tconst matchingGroups = filterSegmentsAndGroups(root.children).filter((node) => node.type === \"group\" && node.id === firstLocator.name);\n\tif (firstLocator.repetition !== void 0) {\n\t\tconst selected = matchingGroups[firstLocator.repetition - 1];\n\t\tif (!selected) return [];\n\t\tconst ancestors = [root, selected];\n\t\treturn collectAllScopesRecursive(selected.children, remainingGroups, ancestors);\n\t}\n\tfor (const group of matchingGroups) {\n\t\tconst ancestors = [root, group];\n\t\tconst subScopes = collectAllScopesRecursive(group.children, remainingGroups, ancestors);\n\t\tresults.push(...subScopes);\n\t}\n\treturn results;\n}\nfunction collectAllScopesRecursive(children, groups, ancestors) {\n\tif (groups.length === 0) return [{\n\t\tancestors,\n\t\tscope: filterSegmentsAndGroups(children)\n\t}];\n\tconst results = [];\n\tconst firstLocator = groups[0];\n\tconst remainingGroups = groups.slice(1);\n\tif (!firstLocator) return [{\n\t\tancestors,\n\t\tscope: filterSegmentsAndGroups(children)\n\t}];\n\tconst matchingGroups = filterSegmentsAndGroups(children).filter((node) => node.type === \"group\" && node.id === firstLocator.name);\n\tif (firstLocator.repetition !== void 0) {\n\t\tconst selected = matchingGroups[firstLocator.repetition - 1];\n\t\tif (!selected) return [];\n\t\tconst newAncestors = [...ancestors, selected];\n\t\treturn collectAllScopesRecursive(selected.children, remainingGroups, newAncestors);\n\t}\n\tfor (const group of matchingGroups) {\n\t\tconst newAncestors = [...ancestors, group];\n\t\tconst subScopes = collectAllScopesRecursive(group.children, remainingGroups, newAncestors);\n\t\tresults.push(...subScopes);\n\t}\n\treturn results;\n}\nfunction collectSegments(nodes, targetSegmentName, ancestors) {\n\tconst result = [];\n\tfor (const node of nodes) {\n\t\tif (node.type === \"segment\") {\n\t\t\tif (getSegmentName(node) === targetSegmentName) result.push({\n\t\t\t\tancestors: [...ancestors],\n\t\t\t\tsegment: node\n\t\t\t});\n\t\t}\n\t\tif (node.type === \"group\") {\n\t\t\tconst nextAncestors = [...ancestors, node];\n\t\t\tresult.push(...collectSegments(filterSegmentsAndGroups(node.children), targetSegmentName, nextAncestors));\n\t\t}\n\t}\n\treturn result;\n}\nfunction collectGroups(nodes, targetGroupId, ancestors) {\n\tconst result = [];\n\tfor (const node of nodes) {\n\t\tif (node.type === \"group\" && node.id === targetGroupId) result.push({\n\t\t\tancestors: [...ancestors],\n\t\t\tgroup: node\n\t\t});\n\t\tif (node.type === \"group\") {\n\t\t\tconst nextAncestors = [...ancestors, node];\n\t\t\tresult.push(...collectGroups(filterSegmentsAndGroups(node.children), targetGroupId, nextAncestors));\n\t\t}\n\t}\n\treturn result;\n}\nfunction locateField(segment, fieldNum, parentAncestors) {\n\tconst field = getFields(segment)[fieldNum - 1];\n\tif (!field) return null;\n\treturn [field, [...parentAncestors, segment]];\n}\nfunction locateRepetition(field, repetition, parentAncestors) {\n\tif (repetition < 1) return null;\n\tconst node = field.children?.[repetition - 1];\n\tif (!node) return null;\n\treturn [node, [...parentAncestors, field]];\n}\nfunction locateComponent(repetition, componentNum, parentAncestors) {\n\tif (componentNum < 1) return null;\n\tconst component = repetition.children?.[componentNum - 1];\n\tif (!component) return null;\n\treturn [component, [...parentAncestors, repetition]];\n}\nfunction locateSubcomponent(component, subcomponentNum, parentAncestors) {\n\tif (subcomponentNum < 1) return null;\n\tconst node = component.children?.[subcomponentNum - 1];\n\tif (!node) return null;\n\treturn [node, [...parentAncestors, component]];\n}\nfunction getSegmentName(segment) {\n\treturn segment.name;\n}\nfunction getFields(segment) {\n\treturn segment.children;\n}\nfunction filterSegmentsAndGroups(nodes) {\n\treturn nodes.filter((node) => node.type === \"segment\" || node.type === \"group\");\n}\n//#endregion\n//#region src/select.ts\n/**\n* Select the first node at the given path and return it with its ancestor\n* chain.\n*\n* This function finds the first matching node for the given path. For paths\n* that can match multiple nodes (e.g., \"PID\" when multiple PID segments exist),\n* use {@link selectAll} to retrieve all matches.\n*\n* @example\n* ```typescript\n* const result = select(root, \"PID-5\");\n* if (result) {\n* result.node; // Type: Field\n* result.ancestors; // [Root, Segment]\n* }\n* ```;\n*\n* @param root - The root node to search from\n* @param path - The HL7 path string\n* @returns Object containing the node and its ancestors, or null if not found\n*/\nfunction select(root, path) {\n\tconst parts = parse(path);\n\tif (parts.field === void 0) {\n\t\tconst result = locateSegmentOrGroup(root, parts);\n\t\tif (!result) return null;\n\t\treturn {\n\t\t\tancestors: result[1],\n\t\t\tnode: result[0]\n\t\t};\n\t}\n\tconst segmentResult = locateSegment(root, parts);\n\tif (!segmentResult) return null;\n\tconst [segment, segmentAncestors] = segmentResult;\n\tconst fieldResult = locateField(segment, parts.field, segmentAncestors);\n\tif (!fieldResult) return null;\n\tconst [field, fieldAncestors] = fieldResult;\n\tif (parts.component === void 0 && parts.subcomponent === void 0 && parts.repetition === void 0) return {\n\t\tancestors: fieldAncestors,\n\t\tnode: field\n\t};\n\tconst repetitionResult = locateRepetition(field, parts.repetition ?? 1, fieldAncestors);\n\tif (!repetitionResult) return null;\n\tconst [repetitionNode, repetitionAncestors] = repetitionResult;\n\tif (parts.component === void 0) return {\n\t\tancestors: repetitionAncestors,\n\t\tnode: repetitionNode\n\t};\n\tconst componentResult = locateComponent(repetitionNode, parts.component, repetitionAncestors);\n\tif (!componentResult) return null;\n\tconst [componentNode, componentAncestors] = componentResult;\n\tif (parts.subcomponent === void 0) return {\n\t\tancestors: componentAncestors,\n\t\tnode: componentNode\n\t};\n\tconst subResult = locateSubcomponent(componentNode, parts.subcomponent, componentAncestors);\n\tif (!subResult) return null;\n\treturn {\n\t\tancestors: subResult[1],\n\t\tnode: subResult[0]\n\t};\n}\n/**\n* Select all nodes that match the given path.\n*\n* This function returns all matching nodes for paths that can match multiple\n* elements. For example, \"PID\" will return all PID segments in the message, and\n* \"OBX-5\" will return all observation values.\n*\n* @example\n* ```typescript\n* // Get all OBX segments\n* const results = selectAll(root, \"OBX\");\n* for (const { node } of results) {\n* console.log(node.type); // 'segment'\n* }\n*\n* // Get all patient name fields\n* const names = selectAll(root, \"PID-5\");\n* ```;\n*\n* @param root - The root node to search from\n* @param path - The HL7 path string (must not include repetition index)\n* @returns Array of objects containing nodes and their ancestor chains\n*/\nfunction selectAll(root, path) {\n\tconst parts = parse(path);\n\tif (parts.segment.repetition !== void 0 || parts.repetition !== void 0) {\n\t\tconst result = select(root, path);\n\t\treturn result ? [result] : [];\n\t}\n\tconst results = [];\n\tconst scopes = collectAllScopes(root, parts.groups ?? []);\n\tconst segments = [];\n\tconst includeGroups = parts.field === void 0;\n\tconst groups = [];\n\tfor (const { scope, ancestors } of scopes) {\n\t\tconst matchingSegments = collectSegments(scope, parts.segment.name, ancestors);\n\t\tsegments.push(...matchingSegments);\n\t\tif (includeGroups) {\n\t\t\tconst matchingGroups = collectGroups(scope, parts.segment.name, ancestors);\n\t\t\tfor (const { group, ancestors: groupAncestors } of matchingGroups) groups.push({\n\t\t\t\tancestors: groupAncestors,\n\t\t\t\tgroup\n\t\t\t});\n\t\t}\n\t}\n\tif (parts.field === void 0) {\n\t\tfor (const { segment, ancestors } of segments) results.push({\n\t\t\tancestors,\n\t\t\tnode: segment\n\t\t});\n\t\tfor (const { group, ancestors } of groups) results.push({\n\t\t\tancestors,\n\t\t\tnode: group\n\t\t});\n\t\treturn results;\n\t}\n\tfor (const { segment, ancestors: segmentAncestors } of segments) {\n\t\tconst fieldResult = locateField(segment, parts.field, segmentAncestors);\n\t\tif (!fieldResult) continue;\n\t\tconst [field, fieldAncestors] = fieldResult;\n\t\tif (parts.component === void 0 && parts.subcomponent === void 0 && parts.repetition === void 0) {\n\t\t\tresults.push({\n\t\t\t\tancestors: fieldAncestors,\n\t\t\t\tnode: field\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tif (!field.children) continue;\n\t\tfor (const repetitionNode of field.children) {\n\t\t\tconst repetitionAncestors = [...fieldAncestors, field];\n\t\t\tif (parts.component === void 0) {\n\t\t\t\tresults.push({\n\t\t\t\t\tancestors: repetitionAncestors,\n\t\t\t\t\tnode: repetitionNode\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst componentResult = locateComponent(repetitionNode, parts.component, repetitionAncestors);\n\t\t\tif (!componentResult) continue;\n\t\t\tconst [componentNode, componentAncestors] = componentResult;\n\t\t\tif (parts.subcomponent === void 0) {\n\t\t\t\tresults.push({\n\t\t\t\t\tancestors: componentAncestors,\n\t\t\t\t\tnode: componentNode\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst subResult = locateSubcomponent(componentNode, parts.subcomponent, componentAncestors);\n\t\t\tif (subResult) results.push({\n\t\t\t\tancestors: subResult[1],\n\t\t\t\tnode: subResult[0]\n\t\t\t});\n\t\t}\n\t}\n\treturn results;\n}\n//#endregion\n//#region src/value.ts\n/**\n* Get the string value at the path, drilling down through single-child nodes\n* when needed. Also returns the node and ancestor chain for context.\n*\n* This is a convenience function that automatically traverses through container\n* nodes (Field → FieldRepetition → Component → Subcomponent) to extract the\n* primary string value. When a container has multiple children, the first child\n* is selected (e.g., `value(tree, \"MSH-12\")` returns the first component of a\n* composite VID field).\n*\n* Nodes with no children return `value: null` to differentiate between empty\n* strings (\"\") and missing values.\n*\n* @example\n* ```typescript\n* const result = value(root, \"PID-5.1\");\n* if (result) {\n* console.log(result.value); // string | null\n* console.log(result.node.type); // 'subcomponent'\n* console.log(result.ancestors); // [Root, Segment, Field, ...]\n* }\n* ```;\n*\n* @param root - The root node to search from\n* @param path - The HL7 path string\n* @returns Object containing the value, node, and ancestors, or null if not\n* found\n*/\nfunction value(root, path) {\n\tconst selectResult = select(root, path);\n\tif (!selectResult) return null;\n\tlet { node } = selectResult;\n\tlet { ancestors } = selectResult;\n\twhile (node.type !== \"subcomponent\") {\n\t\tif (node.type === \"segment\" || node.type === \"group\" || node.type === \"root\") return null;\n\t\tif (!(\"children\" in node && node.children)) return null;\n\t\tif (node.children.length === 0) return {\n\t\t\tancestors: [...ancestors],\n\t\t\tnode,\n\t\t\tvalue: null\n\t\t};\n\t\tconst next = node.children[0];\n\t\tif (!next) return null;\n\t\tancestors = [...ancestors, node];\n\t\tnode = next;\n\t}\n\treturn {\n\t\tancestors,\n\t\tnode,\n\t\tvalue: node.value\n\t};\n}\n//#endregion\n//#region src/delimiters.ts\n/** Keys of MSH-2 encoding characters in positional order. */\nconst MSH2_KEYS = [\n\t\"component\",\n\t\"repetition\",\n\t\"escape\",\n\t\"subcomponent\"\n];\n/**\n* Extract delimiters from a Root AST by reading MSH-1 and MSH-2.\n*\n* MSH-1 contains the field separator character (e.g., `|`).\n* MSH-2 contains up to 4 encoding characters: component, repetition,\n* escape, and subcomponent (e.g., `^~\\&`).\n*\n* Falls back to DEFAULT_DELIMITERS for any values that cannot be derived.\n*\n* @param root - The Root AST node to extract delimiters from.\n* @returns The resolved Delimiters object.\n*/\nfunction delimiters(root) {\n\tconst result = { ...DEFAULT_DELIMITERS };\n\tconst msh1 = value(root, \"MSH-1\")?.value;\n\tif (msh1 && msh1.length === 1) result.field = msh1;\n\tconst msh2 = value(root, \"MSH-2\")?.value;\n\tif (msh2) {\n\t\tconst chars = [...msh2];\n\t\tfor (const [i, key] of MSH2_KEYS.entries()) {\n\t\t\tconst ch = chars[i];\n\t\t\tif (ch) result[key] = ch;\n\t\t}\n\t}\n\treturn result;\n}\n//#endregion\n//#region src/format.ts\n/** What a path names a node by: a segment's name, or a group's ID. */\nconst keyOf = (node) => node.type === \"group\" ? node.id : node.name;\n/**\n* Format a node and its ancestor chain into a canonical HL7v2 path string.\n*\n* This is the inverse of `select`: given a node and the ancestors\n* returned by `visit` or `select`, it produces the path string that\n* would select that node.\n*\n* @example\n* ```typescript\n* visit(tree, \"field\", (node, ancestors) => {\n* format(node, ancestors); // \"PID-5\"\n* });\n*\n* const result = select(root, \"PID-5.2\");\n* format(result.node, result.ancestors); // \"PID-5.2\"\n* ```;\n*\n* @param node - The target AST node\n* @param ancestors - Ancestor chain from root to parent (as provided by\n* visit/select)\n* @returns Canonical path string (e.g., \"PID-5.2\", \"ORDER-ORC-1\"), or `null` if the\n* ancestor chain contains no segment or group\n*/\nfunction format(node, ancestors) {\n\tlet result = null;\n\tconst chain = [...ancestors, node];\n\tfor (const [i, current] of chain.entries()) {\n\t\tconst parent = chain[i - 1];\n\t\tswitch (current.type) {\n\t\t\tcase \"root\": break;\n\t\t\tcase \"group\":\n\t\t\tcase \"segment\": {\n\t\t\t\tconst pos = positionOf(current, parent);\n\t\t\t\tresult = (result ?? \"\") + keyOf(current);\n\t\t\t\tif (pos > 1) result += `[${pos}]`;\n\t\t\t\tif (current.type === \"group\" && current !== node) result += \"-\";\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"field\":\n\t\t\t\tresult += `-${positionOf(current, parent)}`;\n\t\t\t\tbreak;\n\t\t\tcase \"field-repetition\": {\n\t\t\t\tconst pos = positionOf(current, parent);\n\t\t\t\tif (pos > 1 || current === node) result += `[${pos}]`;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"component\":\n\t\t\t\tresult += `.${positionOf(current, parent)}`;\n\t\t\t\tbreak;\n\t\t\tcase \"subcomponent\":\n\t\t\t\tresult += `.${positionOf(current, parent)}`;\n\t\t\t\tbreak;\n\t\t}\n\t}\n\treturn result;\n}\n/**\n* Compute the 1-based position of a node among its parent's children.\n*\n* For segments and groups, counts only siblings with the same name (a\n* group's ID): the 2nd PID in [MSH, PID, OBX, PID] is PID[2], not PID[4].\n*\n* For positional nodes (fields, repetitions, components, subcomponents),\n* uses the array index directly.\n*/\nfunction positionOf(node, parent) {\n\tif (!parent || !(\"children\" in parent)) return 1;\n\tconst children = parent.children;\n\tif (node.type === \"group\" || node.type === \"segment\") {\n\t\tconst key = keyOf(node);\n\t\tlet count = 0;\n\t\tfor (const child of children) {\n\t\t\tif (child === node) return count + 1;\n\t\t\tif (child.type === node.type && keyOf(child) === key) count++;\n\t\t}\n\t\tthrow new Error(\"format(): node not found in parent's children array\");\n\t}\n\tconst idx = children.indexOf(node);\n\tif (idx === -1) throw new Error(\"format(): node not found in parent's children array\");\n\treturn idx + 1;\n}\n//#endregion\n//#region src/matches.ts\n/**\n* Check if a node exists at the given path.\n*\n* This is a convenience function equivalent to `select(root, path) !== null`,\n* but more semantically clear for existence checks.\n*\n* @example\n* ```typescript\n* if (matches(root, \"PID-5\")) {\n* console.log(\"Patient has a name field\");\n* }\n*\n* if (!matches(root, \"OBX-5\")) {\n* throw new Error(\"Missing observation value\");\n* }\n* ```;\n*\n* @param root - The root node to search from\n* @param path - The HL7 path string\n* @returns True if the path resolves to a node, false otherwise\n*/\nfunction matches(root, path) {\n\treturn select(root, path) !== null;\n}\n//#endregion\n//#region src/set.ts\n/**\n* Set a string value at the given HL7 path, creating all missing intermediate\n* nodes as needed (fields, repetitions, components, subcomponents).\n*\n* This is the write counterpart to {@link value}. It handles the full HL7v2\n* path syntax including group navigation and segment repetitions.\n*\n* Padding nodes are created with empty children arrays — they represent\n* structurally absent nodes, not empty values. Only the target node gets\n* a fully populated chain down to the subcomponent.\n*\n* @example\n* ```typescript\n* // Update existing value\n* set(tree, \"MSH-12\", \"2.7.1\");\n*\n* // Create missing MSH-9.3 (fills gaps with empty components)\n* set(tree, \"MSH-9.3\", \"ADT_A01\");\n*\n* // Set a specific repetition\n* set(tree, \"PID-3[2]\", \"ID-002\");\n*\n* // Set a subcomponent\n* set(tree, \"PID-5.1.2\", \"suffix\");\n* ```;\n*\n* @param root - The root node to modify\n* @param path - The HL7 path string (must include at least a field)\n* @param val - The string value to set\n* @throws When the path has no field specifier (segment-only paths)\n* @throws When the target segment does not exist in the tree\n*/\nfunction set(root, path, val) {\n\tconst parts = parse(path);\n\tif (parts.field === void 0) throw new Error(`Cannot set value on segment-only path: \"${path}\"`);\n\tconst segmentResult = locateSegment(root, parts);\n\tif (!segmentResult) throw new Error(`Segment \"${parts.segment.name}\" not found in tree`);\n\tconst [segment] = segmentResult;\n\tconst fieldIndex = parts.field - 1;\n\tpadArray(segment.children, fieldIndex + 1, stubField);\n\tconst field = segment.children[fieldIndex];\n\tconst repIndex = (parts.repetition ?? 1) - 1;\n\tpadArray(field.children, repIndex + 1, stubRepetition);\n\tconst repetition = field.children[repIndex];\n\tconst compIndex = (parts.component ?? 1) - 1;\n\tpadArray(repetition.children, compIndex + 1, stubComponent);\n\tconst component = repetition.children[compIndex];\n\tconst subIndex = (parts.subcomponent ?? 1) - 1;\n\tpadArray(component.children, subIndex + 1, stubSubcomponent);\n\tcomponent.children[subIndex].value = val;\n}\n/**\n* Pad an array to a target length using a factory function.\n*/\nfunction padArray(arr, targetLength, factory) {\n\twhile (arr.length < targetLength) arr.push(factory());\n}\n/**\n* Stub nodes for padding — created with empty children arrays to represent\n* structurally absent nodes. These are distinguishable from nodes with empty\n* values (which have a subcomponent with value \"\").\n*/\nfunction stubField() {\n\treturn {\n\t\tchildren: [],\n\t\ttype: \"field\"\n\t};\n}\nfunction stubRepetition() {\n\treturn {\n\t\tchildren: [],\n\t\ttype: \"field-repetition\"\n\t};\n}\nfunction stubComponent() {\n\treturn {\n\t\tchildren: [],\n\t\ttype: \"component\"\n\t};\n}\nfunction stubSubcomponent() {\n\treturn {\n\t\ttype: \"subcomponent\",\n\t\tvalue: \"\"\n\t};\n}\n//#endregion\nexport { delimiters, format, matches, parse, select, selectAll, set, value };\n\n//# sourceMappingURL=index.js.map","import type {\n Component,\n Delimiters,\n Field,\n FieldRepetition,\n Group,\n Nodes,\n Root,\n Segment,\n Subcomponent,\n} from \"@glion/ast\";\nimport { delimiters as queryDelimiters } from \"@glion/util-query\";\nimport { DEFAULT_DELIMITERS } from \"@glion/utils\";\nimport type { Plugin } from \"unified\";\nimport type { Node } from \"unist\";\nimport type { VFile } from \"vfile\";\n\nexport interface Hl7v2ToHl7v2Options {\n /** Append a field delimiter after the last field in each segment. */\n trailingDelimiter?: boolean;\n}\n\n/**\n * Unified compiler plugin: HL7v2 AST → HL7v2 string.\n *\n * Reads `file.data.delimiters` if set by hl7v2-annotate-delimiters,\n * otherwise derives from MSH-1/MSH-2 via `delimiters()` for standalone use.\n */\nexport const hl7v2ToHl7v2: Plugin<[Hl7v2ToHl7v2Options?], Root, string> =\n function hl7v2ToHl7v2(options?: Hl7v2ToHl7v2Options): void {\n // biome-ignore lint/complexity/noUselessThisAlias: unified plugin shape\n const self = this;\n self.compiler = (tree: Node, file: VFile): string =>\n toHl7v2(\n tree as Nodes,\n file.data.delimiters as Delimiters | undefined,\n options\n );\n };\n\n/**\n * Serialize an HL7v2 AST node back to its wire format.\n *\n * Works on any node in the tree — a full Root, a single Segment, or\n * even a lone Field. Delimiters default to the standard set unless\n * overridden or derivable from an MSH segment in the tree.\n */\nexport function toHl7v2(\n node: Nodes,\n delimiters?: Partial<Delimiters>,\n options?: Hl7v2ToHl7v2Options\n): string {\n const d = {\n ...(node.type === \"root\" ? queryDelimiters(node) : DEFAULT_DELIMITERS),\n ...delimiters,\n };\n const trailing = options?.trailingDelimiter === true;\n\n // -- leaf & field-level serializers (no options needed) ----------------\n\n const sub = (s: Subcomponent): string => s.value ?? \"\";\n\n const comp = (c: Component): string =>\n ((c.children || []) as Subcomponent[]).map(sub).join(d.subcomponent);\n\n const rep = (r: FieldRepetition): string =>\n (r.children as Component[]).map(comp).join(d.component);\n\n const field = (f: Field): string =>\n (f.children as FieldRepetition[]).map(rep).join(d.repetition);\n\n // -- segment-level serializers ----------------------------------------\n\n const fields = (parts: string[]): string => {\n const joined = parts.join(d.field);\n return trailing && joined.length > 0 ? `${joined}${d.field}` : joined;\n };\n\n const segment = (seg: Segment): string => {\n const body = fields(seg.children.map(field));\n if (!seg.name) {\n return body;\n }\n return body ? `${seg.name}${d.field}${body}` : seg.name;\n };\n\n // MSH-1 is the field separator itself — skip it and emit structurally.\n const msh = (seg: Segment): string => {\n const tail = fields(seg.children.slice(1).map(field));\n return tail.length ? `MSH${d.field}${tail}` : `MSH${d.field}`;\n };\n\n const line = (seg: Segment): string =>\n seg.name === \"MSH\" ? msh(seg) : segment(seg);\n\n const lines = (nodes: readonly (Segment | Group)[]): string[] =>\n nodes.flatMap((child) =>\n child.type === \"group\" ? lines(child.children) : [line(child)]\n );\n\n // -- dispatch ----------------------------------------------------------\n\n switch (node.type) {\n case \"root\":\n case \"group\": {\n return lines(node.children as (Segment | Group)[]).join(d.segment);\n }\n case \"segment\": {\n return line(node);\n }\n case \"field\": {\n return field(node);\n }\n case \"field-repetition\": {\n return rep(node);\n }\n case \"component\": {\n return comp(node);\n }\n case \"subcomponent\": {\n return sub(node);\n }\n default: {\n const unsupported: never = node;\n throw new Error(`Unsupported node type: ${(unsupported as Node).type}`);\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["queryDelimiters","delimiters","unsupported"],"sources":["../../util-query/dist/index.js","../src/index.ts"],"sourcesContent":["import { DEFAULT_DELIMITERS } from \"@glion/utils\";\n//#region src/errors.ts\n/**\n* The typed failure for `@glion/util-query`. Branch on `code`; each code is\n* one cause.\n*\n* @module\n*/\n/**\n* Machine-readable codes for what a path got wrong:\n*\n* - `EMPTY_PATH` — the path is empty.\n* - `INVALID_PATH` — the path does not follow the path grammar.\n*/\nconst QueryErrorCode = {\n\tEMPTY_PATH: \"EMPTY_PATH\",\n\tINVALID_PATH: \"INVALID_PATH\"\n};\nfunction sentence(code, path) {\n\tswitch (code) {\n\t\tcase \"EMPTY_PATH\": return \"The path is empty; a path is `[GROUP[N].]...NAME[N][.FIELD[REPETITION][.COMPONENT[.SUBCOMPONENT]]]`, or `FIELD[REPETITION][.COMPONENT[.SUBCOMPONENT]]` read from a segment, with positions from 1, such as `PID.5.1` or `5.1`.\";\n\t\tcase \"INVALID_PATH\": return `Path \\`${path}\\` does not follow the path grammar; a path is \\`[GROUP[N].]...NAME[N][.FIELD[REPETITION][.COMPONENT[.SUBCOMPONENT]]]\\`, or \\`FIELD[REPETITION][.COMPONENT[.SUBCOMPONENT]]\\` read from a segment, with positions from 1, such as \\`PID.5.1\\` or \\`5.1\\`.`;\n\t}\n}\n/** A path that `@glion/util-query` cannot read. */\nvar QueryError = class extends Error {\n\tname = \"QueryError\";\n\tcode;\n\tpath;\n\tconstructor(code, path) {\n\t\tsuper(sentence(code, path));\n\t\tthis.code = code;\n\t\tthis.path = path;\n\t}\n};\n//#endregion\n//#region src/parse.ts\n/**\n* Canonical HL7 path grammar, every step separated with `.`:\n*\n* [GROUP[N].]...NAME[N][.FIELD[REPETITION][.COMPONENT[.SUBCOMPONENT]]]\n* FIELD[REPETITION][.COMPONENT[.SUBCOMPONENT]]\n*\n* Names start with a letter and positions are numbers from 1, so the first\n* numeric step is the field. The final name is the query target. Field\n* access makes it a segment (`ORDER.ORC.1`); without it the AST decides\n* whether it names a segment or a group (`ORDER.ORC`, `ORDER`). A path that\n* starts with the field names no segment (`5.1`).\n*/\nconst PATH_REGEX = /^(?:([A-Z][A-Z0-9_]*(?:\\[[1-9]\\d*\\])?(?:\\.[A-Z][A-Z0-9_]*(?:\\[[1-9]\\d*\\])?)*)(?:\\.(?=[1-9])|$))?(?:([1-9]\\d*)(?:\\[([1-9]\\d*)\\])?(?:\\.([1-9]\\d*)(?:\\.([1-9]\\d*))?)?)?$/;\nconst NAVIGATION_STEP_REGEX = /([A-Z][A-Z0-9_]*)(?:\\[(\\d+)\\])?/g;\n/** Parts of the MSH paths that plugins and lint rules read on every message. */\nconst PRECOMPUTED_PATHS = new Map([\n\t[\"MSH.3\", () => ({\n\t\tfield: 3,\n\t\tsegment: { name: \"MSH\" }\n\t})],\n\t[\"MSH.4\", () => ({\n\t\tfield: 4,\n\t\tsegment: { name: \"MSH\" }\n\t})],\n\t[\"MSH.5\", () => ({\n\t\tfield: 5,\n\t\tsegment: { name: \"MSH\" }\n\t})],\n\t[\"MSH.6\", () => ({\n\t\tfield: 6,\n\t\tsegment: { name: \"MSH\" }\n\t})],\n\t[\"MSH.9\", () => ({\n\t\tfield: 9,\n\t\tsegment: { name: \"MSH\" }\n\t})],\n\t[\"MSH.9.1\", () => ({\n\t\tcomponent: 1,\n\t\tfield: 9,\n\t\tsegment: { name: \"MSH\" }\n\t})],\n\t[\"MSH.9.2\", () => ({\n\t\tcomponent: 2,\n\t\tfield: 9,\n\t\tsegment: { name: \"MSH\" }\n\t})],\n\t[\"MSH.9.3\", () => ({\n\t\tcomponent: 3,\n\t\tfield: 9,\n\t\tsegment: { name: \"MSH\" }\n\t})],\n\t[\"MSH.10\", () => ({\n\t\tfield: 10,\n\t\tsegment: { name: \"MSH\" }\n\t})],\n\t[\"MSH.12\", () => ({\n\t\tfield: 12,\n\t\tsegment: { name: \"MSH\" }\n\t})],\n\t[\"MSH.12.1\", () => ({\n\t\tcomponent: 1,\n\t\tfield: 12,\n\t\tsegment: { name: \"MSH\" }\n\t})]\n]);\n/**\n* Parse an HL7 path string into structured parts.\n*\n* Returns a new object on every call.\n*\n* @example\n* ```typescript\n* parse(\"PID.5[1].2.1\");\n* // {\n* // segment: { name: 'PID' },\n* // field: 5,\n* // repetition: 1,\n* // component: 2,\n* // subcomponent: 1\n* // }\n* ```;\n*\n* @param path - HL7 path string to parse\n* @returns Structured path components\n*/\nfunction parse(path) {\n\tconst precomputed = PRECOMPUTED_PATHS.get(path);\n\tif (precomputed) return precomputed();\n\tif (path === \"\") throw new QueryError(\"EMPTY_PATH\", path);\n\tconst match = PATH_REGEX.exec(path);\n\tif (!match) throw new QueryError(\"INVALID_PATH\", path);\n\tconst [, navigation = \"\", field, repetition, component, subcomponent] = match;\n\tconst steps = [];\n\tfor (const [, name, position] of navigation.matchAll(NAVIGATION_STEP_REGEX)) steps.push(position === void 0 ? { name } : {\n\t\tname,\n\t\trepetition: Number(position)\n\t});\n\tconst parts = {};\n\tconst segment = steps.pop();\n\tif (segment !== void 0) parts.segment = segment;\n\tif (steps.length > 0) parts.groups = steps;\n\tif (field !== void 0) parts.field = Number(field);\n\tif (repetition !== void 0) parts.repetition = Number(repetition);\n\tif (component !== void 0) parts.component = Number(component);\n\tif (subcomponent !== void 0) parts.subcomponent = Number(subcomponent);\n\treturn parts;\n}\n//#endregion\n//#region src/resolve.ts\n/** The name a path gives a node: a segment's name, or a group's ID. */\nconst keyOf = (node) => {\n\tswitch (node.type) {\n\t\tcase \"root\":\n\t\tcase \"field\":\n\t\tcase \"field-repetition\":\n\t\tcase \"component\":\n\t\tcase \"subcomponent\": return;\n\t\tcase \"segment\": return node.name;\n\t\tcase \"group\": return node.id;\n\t}\n};\n/**\n* The `position`th of `children` (1-based) when given; otherwise every one\n* when `every` is set, or the first.\n*/\nfunction pick(children, position, every) {\n\tif (position !== void 0) {\n\t\tconst child = children[position - 1];\n\t\treturn child === void 0 ? [] : [child];\n\t}\n\treturn every ? children : children.slice(0, 1);\n}\n/**\n* The children of `parent` a path step names `name`, segments and groups\n* together: the `position`th (1-based) when given; otherwise every one when\n* `every` is set, or the first.\n*/\nfunction stepChildren(parent, name, position, every) {\n\tconst result = [];\n\tconst target = position ?? 1;\n\tlet count = 0;\n\tfor (const child of parent.children) {\n\t\tif (keyOf(child) !== name) continue;\n\t\tif (every && position === void 0) {\n\t\t\tresult.push(child);\n\t\t\tcontinue;\n\t\t}\n\t\tcount += 1;\n\t\tif (count === target) return [child];\n\t}\n\treturn result;\n}\n/** The children of each scope that `step` names, with their ancestors. */\nfunction advance(scopes, step, every) {\n\tconst next = [];\n\tfor (const scope of scopes) for (const node of stepChildren(scope.node, step.name, step.repetition, every)) next.push({\n\t\tancestors: [...scope.ancestors, scope.node],\n\t\tnode\n\t});\n\treturn next;\n}\n/**\n* The field, repetitions, components, or subcomponents `parts` addresses in\n* `segment`.\n*/\nfunction resolveField(segment, ancestors, fieldNumber, parts, every) {\n\tconst field = segment.children[fieldNumber - 1];\n\tif (!field) return [];\n\tconst fieldAncestors = [...ancestors, segment];\n\tif (parts.repetition === void 0 && parts.component === void 0) return [{\n\t\tancestors: fieldAncestors,\n\t\tnode: field\n\t}];\n\tconst matches = [];\n\tfor (const repetition of pick(field.children ?? [], parts.repetition, every)) {\n\t\tconst repetitionAncestors = [...fieldAncestors, field];\n\t\tif (parts.component === void 0) {\n\t\t\tmatches.push({\n\t\t\t\tancestors: repetitionAncestors,\n\t\t\t\tnode: repetition\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst component = repetition.children?.[parts.component - 1];\n\t\tif (!component) continue;\n\t\tconst componentAncestors = [...repetitionAncestors, repetition];\n\t\tif (parts.subcomponent === void 0) {\n\t\t\tmatches.push({\n\t\t\t\tancestors: componentAncestors,\n\t\t\t\tnode: component\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst subcomponent = component.children?.[parts.subcomponent - 1];\n\t\tif (subcomponent) matches.push({\n\t\t\tancestors: [...componentAncestors, component],\n\t\t\tnode: subcomponent\n\t\t});\n\t}\n\treturn matches;\n}\n/**\n* The nodes `parts` addresses under `start`, in document order, each with its\n* own ancestors array, which begins at `start`.\n*\n* Every step names a direct child of the node before it; the first step\n* names a direct child of `start`. A step's `[n]` counts the children with\n* that name, segments and groups together. A step without `[n]` matches the\n* first such child, or every one when `every` is set; so does a field\n* without a repetition when the path names a component.\n*/\nfunction resolve(start, parts, every) {\n\tlet scopes = [{\n\t\tancestors: [],\n\t\tnode: start\n\t}];\n\tfor (const group of parts.groups ?? []) scopes = advance(scopes, group, every);\n\tif (parts.segment !== void 0) scopes = advance(scopes, parts.segment, every);\n\tif (parts.field === void 0) return scopes;\n\tconst matches = [];\n\tfor (const { node, ancestors } of scopes) {\n\t\tif (node.type !== \"segment\") continue;\n\t\tfor (const match of resolveField(node, ancestors, parts.field, parts, every)) matches.push(match);\n\t}\n\treturn matches;\n}\n//#endregion\n//#region src/select.ts\n/**\n* The node `path` addresses under `node`, with its ancestors from `node`, or\n* `null`.\n*\n* Every step of `path` names a direct child of the node before it; the first\n* step names a direct child of `node`, so a path read from a segment starts\n* with the field. A step without `[n]` names the first such child, so\n* `select` returns `null` when that child does not lead to a match, even if a\n* later one does; `selectAll` returns every match.\n*\n* @example\n* ```typescript\n* select(root, \"PID.5\"); // { node: Field, ancestors: [Root, Segment] }\n* select(root, \"PATIENT_RESULT.PATIENT.PID.5\");\n* select(segment, \"5.1\"); // { node: Component, ancestors: [Segment, Field, FieldRepetition] }\n* ```;\n*\n* @param node - The message, group, or segment to read from.\n* @param path - The path to the node.\n* @returns The node and its ancestors, or `null` when nothing matches.\n*/\nfunction select(node, path) {\n\tconst [match] = resolve(node, parse(path), false);\n\treturn match ?? null;\n}\n/**\n* Every node `path` addresses under `node`, with its ancestors from `node`, in\n* document order.\n*\n* Every step of `path` names a direct child of the node before it; the first\n* step names a direct child of `node`, so a path read from a segment starts\n* with the field. A step without `[n]` matches every such child, and so does\n* a field without a repetition when `path` names a component.\n*\n* @example\n* ```typescript\n* selectAll(root, \"OBX.5\"); // OBX-5 of every top-level OBX\n* selectAll(root, \"OBX.1[2]\"); // the second repetition of OBX-1 in every OBX\n* selectAll(segment, \"3.1\"); // the first component of every repetition of field 3\n* ```;\n*\n* @param node - The message, group, or segment to read from.\n* @param path - The path to the nodes.\n* @returns The nodes and their ancestors; empty when nothing matches.\n*/\nfunction selectAll(node, path) {\n\treturn resolve(node, parse(path), true);\n}\n//#endregion\n//#region src/value.ts\n/**\n* Get the string value at the path, drilling down through single-child nodes\n* when needed. Also returns the node and ancestor chain for context.\n*\n* This is a convenience function that automatically traverses through container\n* nodes (Field → FieldRepetition → Component → Subcomponent) to extract the\n* primary string value. When a container has multiple children, the first child\n* is selected (e.g., `value(tree, \"MSH.12\")` returns the first component of a\n* composite VID field).\n*\n* Nodes with no children return `value: null` to differentiate between empty\n* strings (\"\") and missing values.\n*\n* @example\n* ```typescript\n* const result = value(root, \"PID.5.1\");\n* if (result) {\n* console.log(result.value); // string | null\n* console.log(result.node.type); // 'subcomponent'\n* console.log(result.ancestors); // [Root, Segment, Field, ...]\n* }\n*\n* value(segment, \"5.1\"); // the same value, read from the PID segment\n* ```;\n*\n* @param node - The message, group, or segment to read from\n* @param path - The HL7 path string\n* @returns Object containing the value, node, and ancestors from `node`, or\n* null if not found\n*/\nfunction value(node, path) {\n\tconst selected = select(node, path);\n\treturn selected ? drill(selected.node, selected.ancestors) : null;\n}\n/**\n* The first subcomponent under `node`, with its value, or `node` with value\n* `null` when a field, repetition, or component on the way has no children.\n* `null` for a root, group, or segment.\n*/\nfunction drill(node, ancestors) {\n\tswitch (node.type) {\n\t\tcase \"root\":\n\t\tcase \"group\":\n\t\tcase \"segment\": return null;\n\t\tcase \"subcomponent\": return {\n\t\t\tancestors,\n\t\t\tnode,\n\t\t\tvalue: node.value\n\t\t};\n\t\tcase \"field\":\n\t\tcase \"field-repetition\":\n\t\tcase \"component\": {\n\t\t\tconst first = node.children?.[0];\n\t\t\treturn first ? drill(first, [...ancestors, node]) : {\n\t\t\t\tancestors,\n\t\t\t\tnode,\n\t\t\t\tvalue: null\n\t\t\t};\n\t\t}\n\t}\n}\n//#endregion\n//#region src/delimiters.ts\n/** Keys of MSH-2 encoding characters in positional order. */\nconst MSH2_KEYS = [\n\t\"component\",\n\t\"repetition\",\n\t\"escape\",\n\t\"subcomponent\"\n];\n/**\n* Extract delimiters from a Root AST by reading MSH-1 and MSH-2.\n*\n* MSH-1 contains the field separator character (e.g., `|`).\n* MSH-2 contains up to 4 encoding characters: component, repetition,\n* escape, and subcomponent (e.g., `^~\\&`).\n*\n* Falls back to DEFAULT_DELIMITERS for any values that cannot be derived.\n*\n* @param root - The Root AST node to extract delimiters from.\n* @returns The resolved Delimiters object.\n*/\nfunction delimiters(root) {\n\tconst result = { ...DEFAULT_DELIMITERS };\n\tconst msh1 = value(root, \"MSH.1\")?.value;\n\tif (msh1 && msh1.length === 1) result.field = msh1;\n\tconst msh2 = value(root, \"MSH.2\")?.value;\n\tif (msh2) {\n\t\tconst chars = [...msh2];\n\t\tfor (const [i, key] of MSH2_KEYS.entries()) {\n\t\t\tconst ch = chars[i];\n\t\t\tif (ch) result[key] = ch;\n\t\t}\n\t}\n\treturn result;\n}\n//#endregion\n//#region src/format.ts\n/**\n* Format a node and its ancestor chain into a canonical HL7v2 path string.\n*\n* When `ancestors` starts at the root, `select(root, path)` returns `node`:\n* the path names every group, and `[n]` counts the siblings with the same\n* name, segments and groups together.\n*\n* @example\n* ```typescript\n* visit(tree, \"field\", (node, ancestors) => {\n* format(node, ancestors); // \"PID.5\"\n* });\n*\n* const result = select(root, \"PID.5.2\");\n* format(result.node, result.ancestors); // \"PID.5.2\"\n* ```;\n*\n* @param node - The target AST node\n* @param ancestors - Ancestor chain from root to parent (as provided by\n* visit/select)\n* @returns Canonical path string (e.g., \"PID.5.2\", \"ORDER.ORC.1\"), or `null` if the\n* ancestor chain contains no segment or group, or an ancestor does not\n* hold the next node in the chain\n*/\nfunction format(node, ancestors) {\n\tconst chain = [...ancestors, node];\n\tconst steps = [];\n\tlet positions = \"\";\n\tfor (const [index, current] of chain.entries()) {\n\t\tconst position = positionOf(current, chain[index - 1]);\n\t\tif (position === 0) return null;\n\t\tswitch (current.type) {\n\t\t\tcase \"root\": break;\n\t\t\tcase \"group\":\n\t\t\tcase \"segment\":\n\t\t\t\tsteps.push(position > 1 ? `${keyOf(current)}[${position}]` : `${keyOf(current)}`);\n\t\t\t\tbreak;\n\t\t\tcase \"field-repetition\":\n\t\t\t\tif (position > 1 || current === node) positions += `[${position}]`;\n\t\t\t\tbreak;\n\t\t\tcase \"field\":\n\t\t\tcase \"component\":\n\t\t\tcase \"subcomponent\":\n\t\t\t\tpositions += `.${position}`;\n\t\t\t\tbreak;\n\t\t}\n\t}\n\treturn steps.length === 0 ? null : steps.join(\".\") + positions;\n}\n/**\n* The 1-based position of `node` among the children of `parent`: for a\n* segment or group, its `[n]` counted as `select` counts it; otherwise its\n* index. 1 without a parent; 0 when `parent` does not hold `node`.\n*/\nfunction positionOf(node, parent) {\n\tif (parent === void 0 || !(\"children\" in parent)) return 1;\n\tswitch (node.type) {\n\t\tcase \"group\":\n\t\tcase \"segment\": return stepChildren(parent, keyOf(node), void 0, true).indexOf(node) + 1;\n\t\tcase \"root\":\n\t\tcase \"field\":\n\t\tcase \"field-repetition\":\n\t\tcase \"component\":\n\t\tcase \"subcomponent\": return parent.children.indexOf(node) + 1;\n\t}\n}\n//#endregion\n//#region src/matches.ts\n/**\n* Whether `select(node, path)` finds a node.\n*\n* A step without `[n]` names the first such child, so `matches` is `false`\n* when that child does not lead to a match, even if a later one does.\n*\n* @example\n* ```typescript\n* if (matches(root, \"PID.5\")) {\n* console.log(\"Patient has a name field\");\n* }\n*\n* if (!matches(root, \"OBX.5\")) {\n* throw new Error(\"Missing observation value\");\n* }\n* ```;\n*\n* @param node - The message, group, or segment to read from\n* @param path - The HL7 path string\n* @returns True if the path resolves to a node, false otherwise\n*/\nfunction matches(node, path) {\n\treturn select(node, path) !== null;\n}\n//#endregion\nexport { QueryError, QueryErrorCode, delimiters, format, matches, parse, select, selectAll, value };\n\n//# sourceMappingURL=index.js.map","import type {\n Component,\n Delimiters,\n Field,\n FieldRepetition,\n Group,\n Nodes,\n Root,\n Segment,\n Subcomponent,\n} from \"@glion/ast\";\nimport { delimiters as queryDelimiters } from \"@glion/util-query\";\nimport { DEFAULT_DELIMITERS } from \"@glion/utils\";\nimport type { Plugin } from \"unified\";\nimport type { Node } from \"unist\";\nimport type { VFile } from \"vfile\";\n\nexport interface Hl7v2ToHl7v2Options {\n /** Append a field delimiter after the last field in each segment. */\n trailingDelimiter?: boolean;\n}\n\n/**\n * Unified compiler plugin: HL7v2 AST → HL7v2 string.\n *\n * Reads `file.data.delimiters` if set by hl7v2-annotate-delimiters,\n * otherwise derives from MSH-1/MSH-2 via `delimiters()` for standalone use.\n */\nexport const hl7v2ToHl7v2: Plugin<[Hl7v2ToHl7v2Options?], Root, string> =\n function hl7v2ToHl7v2(options?: Hl7v2ToHl7v2Options): void {\n // biome-ignore lint/complexity/noUselessThisAlias: unified plugin shape\n const self = this;\n self.compiler = (tree: Node, file: VFile): string =>\n toHl7v2(\n tree as Nodes,\n file.data.delimiters as Delimiters | undefined,\n options\n );\n };\n\n/**\n * Serialize an HL7v2 AST node back to its wire format.\n *\n * Works on any node in the tree — a full Root, a single Segment, or\n * even a lone Field. Delimiters default to the standard set unless\n * overridden or derivable from an MSH segment in the tree.\n */\nexport function toHl7v2(\n node: Nodes,\n delimiters?: Partial<Delimiters>,\n options?: Hl7v2ToHl7v2Options\n): string {\n const d = {\n ...(node.type === \"root\" ? queryDelimiters(node) : DEFAULT_DELIMITERS),\n ...delimiters,\n };\n const trailing = options?.trailingDelimiter === true;\n\n // -- leaf & field-level serializers (no options needed) ----------------\n\n const sub = (s: Subcomponent): string => s.value ?? \"\";\n\n const comp = (c: Component): string =>\n ((c.children || []) as Subcomponent[]).map(sub).join(d.subcomponent);\n\n const rep = (r: FieldRepetition): string =>\n (r.children as Component[]).map(comp).join(d.component);\n\n const field = (f: Field): string =>\n (f.children as FieldRepetition[]).map(rep).join(d.repetition);\n\n // -- segment-level serializers ----------------------------------------\n\n const fields = (parts: string[]): string => {\n const joined = parts.join(d.field);\n return trailing && joined.length > 0 ? `${joined}${d.field}` : joined;\n };\n\n const segment = (seg: Segment): string => {\n const body = fields(seg.children.map(field));\n if (!seg.name) {\n return body;\n }\n return body ? `${seg.name}${d.field}${body}` : seg.name;\n };\n\n // MSH-1 is the field separator itself — skip it and emit structurally.\n const msh = (seg: Segment): string => {\n const tail = fields(seg.children.slice(1).map(field));\n return tail.length ? `MSH${d.field}${tail}` : `MSH${d.field}`;\n };\n\n const line = (seg: Segment): string =>\n seg.name === \"MSH\" ? msh(seg) : segment(seg);\n\n const lines = (nodes: readonly (Segment | Group)[]): string[] =>\n nodes.flatMap((child) =>\n child.type === \"group\" ? lines(child.children) : [line(child)]\n );\n\n // -- dispatch ----------------------------------------------------------\n\n switch (node.type) {\n case \"root\":\n case \"group\": {\n return lines(node.children as (Segment | Group)[]).join(d.segment);\n }\n case \"segment\": {\n return line(node);\n }\n case \"field\": {\n return field(node);\n }\n case \"field-repetition\": {\n return rep(node);\n }\n case \"component\": {\n return comp(node);\n }\n case \"subcomponent\": {\n return sub(node);\n }\n default: {\n const unsupported: never = node;\n throw new Error(`Unsupported node type: ${(unsupported as Node).type}`);\n }\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glion/to-hl7v2",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "hl7v2 plugin to transform hl7v2 messages to a hl7v2. Useful for sanitizing messages.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"health",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"unified": "11.0.5",
|
|
37
37
|
"unist-util-visit": "5.1.0",
|
|
38
38
|
"unist-util-visit-parents": "6.0.2",
|
|
39
|
-
"@glion/utils": "0.
|
|
39
|
+
"@glion/utils": "0.27.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@stryker-mutator/core": "10.0.0",
|
|
@@ -50,12 +50,12 @@
|
|
|
50
50
|
"unist-builder": "^4.0.0",
|
|
51
51
|
"vfile": "^6.0.3",
|
|
52
52
|
"vitest": "4.1.11",
|
|
53
|
-
"@glion/ast": "0.
|
|
54
|
-
"@glion/builder": "0.
|
|
55
|
-
"@glion/testing": "0.18.0",
|
|
53
|
+
"@glion/ast": "0.27.0",
|
|
54
|
+
"@glion/builder": "0.27.0",
|
|
56
55
|
"@glion/check-readme": "0.18.0",
|
|
57
|
-
"@glion/
|
|
58
|
-
"@glion/util-query": "0.
|
|
56
|
+
"@glion/testing": "0.18.0",
|
|
57
|
+
"@glion/util-query": "0.27.0",
|
|
58
|
+
"@glion/tsconfig": "0.18.0"
|
|
59
59
|
},
|
|
60
60
|
"engines": {
|
|
61
61
|
"node": ">=22"
|