@cosyte/hl7 0.0.1 → 0.0.3
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/CHANGELOG.md +559 -147
- package/README.md +154 -91
- package/TRADEMARKS.md +37 -0
- package/dist/index.cjs +1535 -143
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2216 -646
- package/dist/index.d.ts +2216 -646
- package/dist/index.mjs +1510 -144
- package/dist/index.mjs.map +1 -1
- package/package.json +15 -6
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { randomBytes } from 'crypto';
|
|
2
2
|
import { Buffer } from 'buffer';
|
|
3
3
|
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
|
|
4
10
|
// src/parser/errors.ts
|
|
5
11
|
var FATAL_CODES = {
|
|
6
12
|
NO_MSH_SEGMENT: "NO_MSH_SEGMENT",
|
|
@@ -30,7 +36,7 @@ var ProfileDefinitionError = class extends Error {
|
|
|
30
36
|
profileName;
|
|
31
37
|
/**
|
|
32
38
|
* Construct a new `ProfileDefinitionError`. `profileName` is optional so
|
|
33
|
-
*
|
|
39
|
+
* callers may omit it when the offending profile cannot be named
|
|
34
40
|
* (e.g. during initial validation before a name is parsed).
|
|
35
41
|
*
|
|
36
42
|
* @internal
|
|
@@ -66,7 +72,7 @@ function readDelimiters(firstSegment) {
|
|
|
66
72
|
if (firstSegment.length < 3 || firstSegment.slice(0, 3) !== "MSH") {
|
|
67
73
|
throw new Hl7ParseError(
|
|
68
74
|
FATAL_CODES.NO_MSH_SEGMENT,
|
|
69
|
-
"First segment is not MSH
|
|
75
|
+
"First segment is not MSH: HL7 v2 messages must begin with an MSH segment.",
|
|
70
76
|
fatalPosition,
|
|
71
77
|
snip
|
|
72
78
|
);
|
|
@@ -74,7 +80,7 @@ function readDelimiters(firstSegment) {
|
|
|
74
80
|
if (firstSegment.length < 8) {
|
|
75
81
|
throw new Hl7ParseError(
|
|
76
82
|
FATAL_CODES.MSH_TOO_SHORT,
|
|
77
|
-
"MSH segment is truncated
|
|
83
|
+
"MSH segment is truncated: cannot read encoding characters.",
|
|
78
84
|
fatalPosition,
|
|
79
85
|
snip
|
|
80
86
|
);
|
|
@@ -83,7 +89,7 @@ function readDelimiters(firstSegment) {
|
|
|
83
89
|
if (/\s/u.test(field)) {
|
|
84
90
|
throw new Hl7ParseError(
|
|
85
91
|
FATAL_CODES.INVALID_ENCODING_CHARACTERS,
|
|
86
|
-
"MSH-1 field separator is whitespace
|
|
92
|
+
"MSH-1 field separator is whitespace: refusing to parse.",
|
|
87
93
|
fatalPosition,
|
|
88
94
|
snip
|
|
89
95
|
);
|
|
@@ -267,7 +273,8 @@ var WARNING_CODES = {
|
|
|
267
273
|
ACK_NO_CORRELATION_ID: "ACK_NO_CORRELATION_ID",
|
|
268
274
|
MERGE_MISSING_PRIOR_OR_SURVIVOR: "MERGE_MISSING_PRIOR_OR_SURVIVOR",
|
|
269
275
|
BATCH_COUNT_MISMATCH: "BATCH_COUNT_MISMATCH",
|
|
270
|
-
BATCH_MISSING_TRAILER: "BATCH_MISSING_TRAILER"
|
|
276
|
+
BATCH_MISSING_TRAILER: "BATCH_MISSING_TRAILER",
|
|
277
|
+
UNTERMINATED_STREAM_MESSAGE: "UNTERMINATED_STREAM_MESSAGE"
|
|
271
278
|
};
|
|
272
279
|
function mllpFramingStripped(position) {
|
|
273
280
|
return {
|
|
@@ -345,7 +352,7 @@ function extraFields(position, segmentName2, extraCount) {
|
|
|
345
352
|
function unknownSegment(position, segmentName2) {
|
|
346
353
|
return {
|
|
347
354
|
code: WARNING_CODES.UNKNOWN_SEGMENT,
|
|
348
|
-
message: `Unknown segment "${segmentName2}"
|
|
355
|
+
message: `Unknown segment "${segmentName2}": not in HL7 spec and no profile claim.`,
|
|
349
356
|
position
|
|
350
357
|
};
|
|
351
358
|
}
|
|
@@ -430,7 +437,14 @@ function batchCountMismatch(position, unit, declared, actual) {
|
|
|
430
437
|
function batchMissingTrailer(position, header, expectedTrailer) {
|
|
431
438
|
return {
|
|
432
439
|
code: WARNING_CODES.BATCH_MISSING_TRAILER,
|
|
433
|
-
message: `Batch envelope header "${header}" has no matching "${expectedTrailer}" trailer; splitBatch surfaces this but does not reject
|
|
440
|
+
message: `Batch envelope header "${header}" has no matching "${expectedTrailer}" trailer; splitBatch surfaces this but does not reject: a profile that mandates the full envelope may.`,
|
|
441
|
+
position
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
function unterminatedStreamMessage(position) {
|
|
445
|
+
return {
|
|
446
|
+
code: WARNING_CODES.UNTERMINATED_STREAM_MESSAGE,
|
|
447
|
+
message: "The final message in the stream ended without a segment terminator; it is still yielded in full. If the source terminates every segment, this may indicate a truncated feed.",
|
|
434
448
|
position
|
|
435
449
|
};
|
|
436
450
|
}
|
|
@@ -586,7 +600,7 @@ var RECOGNIZED_PRESERVED_SET = /* @__PURE__ */ new Set([
|
|
|
586
600
|
"H",
|
|
587
601
|
// begin highlighting (§2.7.1)
|
|
588
602
|
"N",
|
|
589
|
-
// normal text
|
|
603
|
+
// normal text: end highlighting (§2.7.1)
|
|
590
604
|
".sp",
|
|
591
605
|
// vertical skip (§2.7.6)
|
|
592
606
|
".in",
|
|
@@ -773,7 +787,7 @@ function tokenizeComponent(raw, enc, emit, position) {
|
|
|
773
787
|
var MESSAGE_STRUCTURE_DEFINITIONS = Object.freeze([
|
|
774
788
|
// ── ADT (Ch. 3): patient identification (PID) + visit (PV1) are Required
|
|
775
789
|
// for these admit/transfer/discharge/register/update/cancel events.
|
|
776
|
-
// EVN is intentionally excluded
|
|
790
|
+
// EVN is intentionally excluded: real senders omit it freely, making it
|
|
777
791
|
// a weak (false-positive-prone) signal.
|
|
778
792
|
Object.freeze({
|
|
779
793
|
messageCode: "ADT",
|
|
@@ -785,7 +799,7 @@ var MESSAGE_STRUCTURE_DEFINITIONS = Object.freeze([
|
|
|
785
799
|
}),
|
|
786
800
|
// ── ORU^R01 (Ch. 7): the OBR/OBX result group is the Required payload.
|
|
787
801
|
// PID is excluded (the patient-result group's PID is R within the group,
|
|
788
|
-
// but a result-only relay can legitimately omit it at the top
|
|
802
|
+
// but a result-only relay can legitimately omit it at the top: keep the
|
|
789
803
|
// anchor on the result segments themselves, the true truncation signal).
|
|
790
804
|
Object.freeze({
|
|
791
805
|
messageCode: "ORU",
|
|
@@ -795,7 +809,7 @@ var MESSAGE_STRUCTURE_DEFINITIONS = Object.freeze([
|
|
|
795
809
|
])
|
|
796
810
|
}),
|
|
797
811
|
// ── Orders (Ch. 4): ORC is the Required common-order segment across the
|
|
798
|
-
// order message family. OBR is excluded
|
|
812
|
+
// order message family. OBR is excluded: it is Optional in several of
|
|
799
813
|
// these (OML/OMG/OMI carry it inside an optional observation-request
|
|
800
814
|
// group), so anchoring only on ORC avoids a false positive.
|
|
801
815
|
Object.freeze({
|
|
@@ -858,7 +872,7 @@ var MESSAGE_STRUCTURE_DEFINITIONS = Object.freeze([
|
|
|
858
872
|
Object.freeze({ name: "schedule", anchorSegments: Object.freeze(["SCH"]) })
|
|
859
873
|
])
|
|
860
874
|
}),
|
|
861
|
-
// ── MDM (Ch. 9): document management
|
|
875
|
+
// ── MDM (Ch. 9): document management: PID + the TXA document header are
|
|
862
876
|
// Required for T02 (original document) and T06 (document addendum).
|
|
863
877
|
Object.freeze({
|
|
864
878
|
messageCode: "MDM",
|
|
@@ -868,7 +882,7 @@ var MESSAGE_STRUCTURE_DEFINITIONS = Object.freeze([
|
|
|
868
882
|
Object.freeze({ name: "document", anchorSegments: Object.freeze(["TXA"]) })
|
|
869
883
|
])
|
|
870
884
|
}),
|
|
871
|
-
// ── DFT^P03 (Ch. 6): financial transaction
|
|
885
|
+
// ── DFT^P03 (Ch. 6): financial transaction: PID + at least one FT1
|
|
872
886
|
// financial-transaction segment are Required.
|
|
873
887
|
Object.freeze({
|
|
874
888
|
messageCode: "DFT",
|
|
@@ -878,7 +892,7 @@ var MESSAGE_STRUCTURE_DEFINITIONS = Object.freeze([
|
|
|
878
892
|
Object.freeze({ name: "financial", anchorSegments: Object.freeze(["FT1"]) })
|
|
879
893
|
])
|
|
880
894
|
}),
|
|
881
|
-
// ── VXU^V04 (CDC IG): immunization update
|
|
895
|
+
// ── VXU^V04 (CDC IG): immunization update: PID is Required. RXA is
|
|
882
896
|
// excluded: it lives in the Optional order group of the CDC IG, so a
|
|
883
897
|
// query-shaped VXU with no administered vaccine must not warn.
|
|
884
898
|
Object.freeze({
|
|
@@ -888,7 +902,7 @@ var MESSAGE_STRUCTURE_DEFINITIONS = Object.freeze([
|
|
|
888
902
|
Object.freeze({ name: "patient", anchorSegments: Object.freeze(["PID"]) })
|
|
889
903
|
])
|
|
890
904
|
}),
|
|
891
|
-
// ── ACK (Ch. 2): a general acknowledgment
|
|
905
|
+
// ── ACK (Ch. 2): a general acknowledgment: MSA (message acknowledgment) is
|
|
892
906
|
// Required. Matched on message code alone (no trigger event in MSH-9.2).
|
|
893
907
|
Object.freeze({
|
|
894
908
|
messageCode: "ACK",
|
|
@@ -1018,7 +1032,7 @@ function parsePath(path) {
|
|
|
1018
1032
|
}
|
|
1019
1033
|
if (i !== path.length) {
|
|
1020
1034
|
throw new TypeError(
|
|
1021
|
-
`Invalid HL7 dot-path: "${path}" (trailing content at position ${String(i)}
|
|
1035
|
+
`Invalid HL7 dot-path: "${path}" (trailing content at position ${String(i)}: too deep or malformed).`
|
|
1022
1036
|
);
|
|
1023
1037
|
}
|
|
1024
1038
|
return freezeDotPath(out);
|
|
@@ -1144,6 +1158,127 @@ function emitSegment(seg, enc) {
|
|
|
1144
1158
|
return parts.join(enc.field);
|
|
1145
1159
|
}
|
|
1146
1160
|
|
|
1161
|
+
// src/text/render.ts
|
|
1162
|
+
var FORMATTING_RE = /^\.(br|sp|in|ti|fi|nf|ce|sk)[ +]?([+-]?\d+)?$/u;
|
|
1163
|
+
var DEFAULT_TRUNCATION_CHAR2 = "#";
|
|
1164
|
+
var MAX_FORMAT_REPEAT = 100;
|
|
1165
|
+
function normalizeBreaks(s, newline) {
|
|
1166
|
+
return s.replace(/\r\n|\r|\n/gu, newline);
|
|
1167
|
+
}
|
|
1168
|
+
function clampCount(arg) {
|
|
1169
|
+
if (arg === void 0) return 1;
|
|
1170
|
+
const n = Math.trunc(Number(arg));
|
|
1171
|
+
if (!Number.isFinite(n) || n < 1) return 1;
|
|
1172
|
+
return Math.min(n, MAX_FORMAT_REPEAT);
|
|
1173
|
+
}
|
|
1174
|
+
function renderText(input, enc = DEFAULT_ENCODING_CHARACTERS, opts) {
|
|
1175
|
+
const esc = enc.escape;
|
|
1176
|
+
const newline = opts?.newline ?? "\n";
|
|
1177
|
+
const runs = [];
|
|
1178
|
+
const unrendered = [];
|
|
1179
|
+
let highlighted = false;
|
|
1180
|
+
let current = "";
|
|
1181
|
+
const flush = () => {
|
|
1182
|
+
if (current !== "") {
|
|
1183
|
+
runs.push({ text: current, highlighted });
|
|
1184
|
+
current = "";
|
|
1185
|
+
}
|
|
1186
|
+
};
|
|
1187
|
+
let i = 0;
|
|
1188
|
+
const len = input.length;
|
|
1189
|
+
while (i < len) {
|
|
1190
|
+
const ch = input.charAt(i);
|
|
1191
|
+
if (ch === "\r" || ch === "\n") {
|
|
1192
|
+
current += newline;
|
|
1193
|
+
i += ch === "\r" && input.charAt(i + 1) === "\n" ? 2 : 1;
|
|
1194
|
+
continue;
|
|
1195
|
+
}
|
|
1196
|
+
if (ch !== esc) {
|
|
1197
|
+
current += ch;
|
|
1198
|
+
i++;
|
|
1199
|
+
continue;
|
|
1200
|
+
}
|
|
1201
|
+
const close = input.indexOf(esc, i + 1);
|
|
1202
|
+
if (close === -1) {
|
|
1203
|
+
const tail = input.slice(i);
|
|
1204
|
+
current += tail;
|
|
1205
|
+
unrendered.push(tail);
|
|
1206
|
+
break;
|
|
1207
|
+
}
|
|
1208
|
+
const body = input.slice(i + 1, close);
|
|
1209
|
+
const literal = esc + body + esc;
|
|
1210
|
+
if (body === "H") {
|
|
1211
|
+
flush();
|
|
1212
|
+
highlighted = true;
|
|
1213
|
+
} else if (body === "N") {
|
|
1214
|
+
flush();
|
|
1215
|
+
highlighted = false;
|
|
1216
|
+
} else {
|
|
1217
|
+
const decoded = decodeBody(body, enc, newline);
|
|
1218
|
+
if (decoded !== null) {
|
|
1219
|
+
current += decoded;
|
|
1220
|
+
} else {
|
|
1221
|
+
current += literal;
|
|
1222
|
+
unrendered.push(literal);
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
i = close + 1;
|
|
1226
|
+
}
|
|
1227
|
+
flush();
|
|
1228
|
+
const text = runs.reduce((acc, r) => acc + r.text, "");
|
|
1229
|
+
return { text, runs, unrenderedSequences: unrendered };
|
|
1230
|
+
}
|
|
1231
|
+
function decodeBody(body, enc, newline) {
|
|
1232
|
+
switch (body) {
|
|
1233
|
+
case "F":
|
|
1234
|
+
return enc.field;
|
|
1235
|
+
case "S":
|
|
1236
|
+
return enc.component;
|
|
1237
|
+
case "T":
|
|
1238
|
+
return enc.subcomponent;
|
|
1239
|
+
case "R":
|
|
1240
|
+
return enc.repetition;
|
|
1241
|
+
case "E":
|
|
1242
|
+
return enc.escape;
|
|
1243
|
+
case "P":
|
|
1244
|
+
return enc.truncation ?? DEFAULT_TRUNCATION_CHAR2;
|
|
1245
|
+
}
|
|
1246
|
+
if (body.charAt(0) === ".") {
|
|
1247
|
+
const m = FORMATTING_RE.exec(body);
|
|
1248
|
+
if (m !== null) return renderFormatting(m[1] ?? "", m[2], newline);
|
|
1249
|
+
return null;
|
|
1250
|
+
}
|
|
1251
|
+
if (body.charAt(0) === "X") {
|
|
1252
|
+
const hex = body.slice(1);
|
|
1253
|
+
if (hex.length === 0 || hex.length % 2 !== 0 || !/^[0-9A-Fa-f]+$/u.test(hex)) {
|
|
1254
|
+
return null;
|
|
1255
|
+
}
|
|
1256
|
+
let out = "";
|
|
1257
|
+
for (let j = 0; j < hex.length; j += 2) {
|
|
1258
|
+
out += String.fromCharCode(parseInt(hex.slice(j, j + 2), 16));
|
|
1259
|
+
}
|
|
1260
|
+
return normalizeBreaks(out, newline);
|
|
1261
|
+
}
|
|
1262
|
+
return null;
|
|
1263
|
+
}
|
|
1264
|
+
function renderFormatting(cmd, arg, newline) {
|
|
1265
|
+
switch (cmd) {
|
|
1266
|
+
case "br":
|
|
1267
|
+
case "ce":
|
|
1268
|
+
return newline;
|
|
1269
|
+
case "sp":
|
|
1270
|
+
return newline.repeat(clampCount(arg));
|
|
1271
|
+
case "sk":
|
|
1272
|
+
return " ".repeat(clampCount(arg));
|
|
1273
|
+
case "in":
|
|
1274
|
+
case "ti":
|
|
1275
|
+
case "fi":
|
|
1276
|
+
case "nf":
|
|
1277
|
+
default:
|
|
1278
|
+
return "";
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1147
1282
|
// src/model/types/_shared.ts
|
|
1148
1283
|
function readSubcomponent(component, index, _enc) {
|
|
1149
1284
|
if (component === void 0) return void 0;
|
|
@@ -1722,15 +1857,15 @@ function parseXtn(rep, enc) {
|
|
|
1722
1857
|
// src/model/field.ts
|
|
1723
1858
|
var DEFAULT_POSITION = { segmentIndex: 0 };
|
|
1724
1859
|
var Field = class {
|
|
1725
|
-
/** HL7 null indicator
|
|
1860
|
+
/** HL7 null indicator: `true` iff the underlying field was the two-char literal `""`. */
|
|
1726
1861
|
isNull;
|
|
1727
1862
|
/** Reference to the underlying `RawField.repetitions` (no defensive copy). */
|
|
1728
1863
|
repetitions;
|
|
1729
|
-
/** The 5 encoding characters for this message. Exposed for composite parsers
|
|
1864
|
+
/** The 5 encoding characters for this message. Exposed for composite parsers. @internal */
|
|
1730
1865
|
enc;
|
|
1731
|
-
/** Position of this field in the parent message
|
|
1866
|
+
/** Position of this field in the parent message: used for position-aware error messages. @internal */
|
|
1732
1867
|
position;
|
|
1733
|
-
/** The full `RawField` this wrapper wraps. Exposed for composite parsers
|
|
1868
|
+
/** The full `RawField` this wrapper wraps. Exposed for composite parsers. @internal */
|
|
1734
1869
|
raw;
|
|
1735
1870
|
/**
|
|
1736
1871
|
* Construct a new `Field`. Called internally by `Segment.field(n)`; user
|
|
@@ -1746,8 +1881,8 @@ var Field = class {
|
|
|
1746
1881
|
}
|
|
1747
1882
|
/**
|
|
1748
1883
|
* First-repetition, first-component, first-subcomponent value as a decoded
|
|
1749
|
-
* string
|
|
1750
|
-
* (never re-unescaped
|
|
1884
|
+
* string: unescaped ONCE by the tokenizer on parse, returned verbatim here
|
|
1885
|
+
* (never re-unescaped). Returns `""` when the field is
|
|
1751
1886
|
* empty or HL7 null. Equivalent to `msg.get('SEG.N')` for a top-level access.
|
|
1752
1887
|
*
|
|
1753
1888
|
* @example
|
|
@@ -1767,18 +1902,18 @@ var Field = class {
|
|
|
1767
1902
|
return sub;
|
|
1768
1903
|
}
|
|
1769
1904
|
/**
|
|
1770
|
-
* The field's **canonical wire text
|
|
1905
|
+
* The field's **canonical wire text**: the full field re-serialized with
|
|
1771
1906
|
* the active delimiters and re-escaped content (repetitions, components,
|
|
1772
1907
|
* and subcomponents included). Contrast with {@link value}, which
|
|
1773
1908
|
* returns only the first subcomponent of the first component of the first
|
|
1774
|
-
* repetition (decoded once at parse
|
|
1909
|
+
* repetition (decoded once at parse: never re-unescaped).
|
|
1775
1910
|
*
|
|
1776
|
-
* Use this when a field must be compared or echoed as a whole
|
|
1911
|
+
* Use this when a field must be compared or echoed as a whole: e.g.
|
|
1777
1912
|
* correlating an ACK's MSA-2 against the inbound MSH-10, where a
|
|
1778
1913
|
* vendor-quirk control id containing an unescaped delimiter (`ID^X`) must
|
|
1779
1914
|
* not be truncated to its first component.
|
|
1780
1915
|
*
|
|
1781
|
-
* **Byte-verbatim for parsed content
|
|
1916
|
+
* **Byte-verbatim for parsed content.** The parse pipeline stores
|
|
1782
1917
|
* *decoded* content, but also records the original wire bytes of any escape
|
|
1783
1918
|
* whose decode is not byte-faithful (`RawComponent.rawSubcomponents`), so
|
|
1784
1919
|
* re-serialization preserves the sender's exact escape bytes: hex escapes
|
|
@@ -1792,7 +1927,7 @@ var Field = class {
|
|
|
1792
1927
|
*
|
|
1793
1928
|
* **MSH-1/MSH-2 caveat.** Like {@link value}, calling this on MSH-1 or
|
|
1794
1929
|
* MSH-2 (the delimiter-definition fields) re-escapes the encoding
|
|
1795
|
-
* characters themselves and produces garbage
|
|
1930
|
+
* characters themselves and produces garbage: those two fields are only
|
|
1796
1931
|
* meaningful through `Hl7Message.encodingCharacters`.
|
|
1797
1932
|
*
|
|
1798
1933
|
* @example
|
|
@@ -1807,12 +1942,33 @@ var Field = class {
|
|
|
1807
1942
|
return emitField(this.raw, this.enc);
|
|
1808
1943
|
}
|
|
1809
1944
|
/**
|
|
1810
|
-
*
|
|
1945
|
+
* Render this field's formatted text (HL7 v2 §2.7 highlight + formatting
|
|
1946
|
+
* escapes) into a normalized {@link RenderedText} display model: plain text
|
|
1947
|
+
* plus highlight-aware runs. A **read projection** over the field's
|
|
1948
|
+
* byte-verbatim wire {@link text}: it never mutates the raw value, and it
|
|
1949
|
+
* never fabricates (an unrenderable escape is preserved + flagged). Use this
|
|
1950
|
+
* to surface a clinical narrative (an NTE / OBX-5 note) to a human without
|
|
1951
|
+
* the raw `\.br\` / `\H\` sentinels.
|
|
1952
|
+
*
|
|
1953
|
+
* @param opts - see {@link RenderTextOptions} (e.g. a custom line-break string).
|
|
1954
|
+
* @returns the normalized display model.
|
|
1955
|
+
*
|
|
1956
|
+
* @example
|
|
1957
|
+
* ```ts
|
|
1958
|
+
* const note = msg.segments("OBX")[0]?.field(5);
|
|
1959
|
+
* note?.render().text; // "Specimen received.\nGross exam normal."
|
|
1960
|
+
* ```
|
|
1961
|
+
*/
|
|
1962
|
+
render(opts) {
|
|
1963
|
+
return renderText(this.text, this.enc, opts);
|
|
1964
|
+
}
|
|
1965
|
+
/**
|
|
1966
|
+
* Return a synthetic empty `Field` sentinel: used by `Segment.field(n)` to
|
|
1811
1967
|
* honor MODEL-05's "never throws on missing" contract. The returned Field
|
|
1812
1968
|
* has `isNull === false`, `repetitions === []`, and `value === ""`.
|
|
1813
1969
|
* Referentially stable across calls (same instance returned each time).
|
|
1814
1970
|
*
|
|
1815
|
-
* The `enc` argument is accepted for API symmetry but ignored
|
|
1971
|
+
* The `enc` argument is accepted for API symmetry but ignored: the
|
|
1816
1972
|
* synthetic field carries no content, so unescape would be a no-op
|
|
1817
1973
|
* regardless of the active encoding characters.
|
|
1818
1974
|
*
|
|
@@ -1829,7 +1985,7 @@ var Field = class {
|
|
|
1829
1985
|
/**
|
|
1830
1986
|
* Coerce this field's first repetition to a typed `XPN` (Extended Person
|
|
1831
1987
|
* Name). Absent components are OMITTED from the result
|
|
1832
|
-
* (`exactOptionalPropertyTypes`). Not memoized in v1
|
|
1988
|
+
* (`exactOptionalPropertyTypes`). Not memoized in v1: each call re-parses
|
|
1833
1989
|
* (D-09).
|
|
1834
1990
|
*
|
|
1835
1991
|
* @example
|
|
@@ -1919,7 +2075,7 @@ var Field = class {
|
|
|
1919
2075
|
return parsePl(this.repetitions[0] ?? EMPTY_REP, this.enc);
|
|
1920
2076
|
}
|
|
1921
2077
|
/**
|
|
1922
|
-
* Coerce this field's first repetition to a typed `TS` (Time Stamp)
|
|
2078
|
+
* Coerce this field's first repetition to a typed `TS` (Time Stamp): the
|
|
1923
2079
|
* fidelity `DtmParts` (raw + parts + precision + timezone). `valid` is
|
|
1924
2080
|
* `false` on unparseable input (no throw). Build an absolute instant only on
|
|
1925
2081
|
* explicit request via `dtmToDate(ts)`.
|
|
@@ -1935,7 +2091,7 @@ var Field = class {
|
|
|
1935
2091
|
}
|
|
1936
2092
|
/**
|
|
1937
2093
|
* Coerce this field's first repetition to a typed `NM` (Numeric).
|
|
1938
|
-
* `{ raw, value }
|
|
2094
|
+
* `{ raw, value }`: `value` is `undefined` on non-numeric input.
|
|
1939
2095
|
*
|
|
1940
2096
|
* @example
|
|
1941
2097
|
* ```ts
|
|
@@ -2005,13 +2161,13 @@ var EMPTY_REP = Object.freeze({
|
|
|
2005
2161
|
var Segment = class {
|
|
2006
2162
|
/** Segment name (3 chars, e.g. `"PID"`, `"OBX"`, `"ZPI"`). */
|
|
2007
2163
|
type;
|
|
2008
|
-
/** Reference to the underlying `RawSegment.fields
|
|
2164
|
+
/** Reference to the underlying `RawSegment.fields`: 1-indexed per HL7 convention. */
|
|
2009
2165
|
fields;
|
|
2010
2166
|
/** The 5 encoding characters for this message. Exposed for composite parsers. @internal */
|
|
2011
2167
|
enc;
|
|
2012
2168
|
/** Absolute index of this segment in `Hl7Message.rawSegments[]`. Used for position tracking. @internal */
|
|
2013
2169
|
absoluteIndex;
|
|
2014
|
-
/** The full `RawSegment` this wrapper wraps. Exposed for mutation methods
|
|
2170
|
+
/** The full `RawSegment` this wrapper wraps. Exposed for mutation methods. @internal */
|
|
2015
2171
|
raw;
|
|
2016
2172
|
/**
|
|
2017
2173
|
* Lookup map from profile-declared field name → 1-indexed HL7 position.
|
|
@@ -2021,14 +2177,14 @@ var Segment = class {
|
|
|
2021
2177
|
* @internal
|
|
2022
2178
|
*/
|
|
2023
2179
|
customFields;
|
|
2024
|
-
/** Lazy cache of Field wrappers
|
|
2180
|
+
/** Lazy cache of Field wrappers: one per fields[] position. @internal */
|
|
2025
2181
|
_fieldWrappers;
|
|
2026
2182
|
/**
|
|
2027
2183
|
* Construct a new `Segment`. Called internally by `Hl7Message`; user code
|
|
2028
2184
|
* should obtain `Segment` instances via `msg.segments(type)` or
|
|
2029
2185
|
* `msg.allSegments()`.
|
|
2030
2186
|
*
|
|
2031
|
-
* The optional `customFields` parameter is the per-segment
|
|
2187
|
+
* The optional `customFields` parameter is the per-segment portion of the
|
|
2032
2188
|
* applied profile's merged `customSegments` map (PROF-07 / D-16). When
|
|
2033
2189
|
* supplied, `get(name)` resolves names against it; otherwise `get(name)`
|
|
2034
2190
|
* always returns `undefined`.
|
|
@@ -2044,16 +2200,16 @@ var Segment = class {
|
|
|
2044
2200
|
}
|
|
2045
2201
|
/**
|
|
2046
2202
|
* Return the `Field` wrapper at HL7 position `n`. Indexing follows the HL7
|
|
2047
|
-
* 1-indexed convention
|
|
2203
|
+
* 1-indexed convention: `seg.field(5)` on a PID segment maps to PID-5.
|
|
2048
2204
|
* MSH segments use the same user-facing convention: `msh.field(1)` returns
|
|
2049
2205
|
* the field-separator (MSH-1), `msh.field(2)` returns encoding chars
|
|
2050
|
-
* (MSH-2), `msh.field(3)` returns MSH-3, and so on
|
|
2206
|
+
* (MSH-2), `msh.field(3)` returns MSH-3, and so on: the internal
|
|
2051
2207
|
* `fields[N-1]` offset for MSH segments is applied here (mirrors the
|
|
2052
2208
|
* dot-path resolver in `dot-path.ts`, keeping `msg.segments('MSH')[0].field(3)`
|
|
2053
2209
|
* and `msg.get('MSH.3')` in agreement).
|
|
2054
2210
|
*
|
|
2055
2211
|
* Returns a synthetic empty `Field` (`.isNull === false`, `.value === ""`)
|
|
2056
|
-
* when `n` is out of range
|
|
2212
|
+
* when `n` is out of range: never throws (MODEL-05). Successive calls with
|
|
2057
2213
|
* the same `n` return the same `Field` instance (D-12).
|
|
2058
2214
|
*
|
|
2059
2215
|
* @example
|
|
@@ -2080,13 +2236,13 @@ var Segment = class {
|
|
|
2080
2236
|
/**
|
|
2081
2237
|
* Return the `Field` at the profile-declared position for `name`, or
|
|
2082
2238
|
* `undefined` when no custom mapping exists (PROF-07). Unlike `field(n)`,
|
|
2083
|
-
* missing names return `undefined
|
|
2239
|
+
* missing names return `undefined`, NOT a synthetic empty Field, so
|
|
2084
2240
|
* typos surface instead of silently resolving to an empty string (D-14).
|
|
2085
2241
|
*
|
|
2086
2242
|
* For segments without a profile-declared customSegments slice (most
|
|
2087
2243
|
* non-Z segments, and any Z-segment whose host message had no profile
|
|
2088
2244
|
* applied), this method always returns `undefined` (D-15 defense-in-depth
|
|
2089
|
-
|
|
2245
|
+
*: D-05 already rejects standard-segment overlays at `defineProfile()`
|
|
2090
2246
|
* time).
|
|
2091
2247
|
*
|
|
2092
2248
|
* When the declared position is out of range for the underlying
|
|
@@ -3134,8 +3290,8 @@ function buildMeta(msg) {
|
|
|
3134
3290
|
const out = {};
|
|
3135
3291
|
const msh = msg.segments("MSH")[0];
|
|
3136
3292
|
if (msh !== void 0) {
|
|
3137
|
-
const
|
|
3138
|
-
const firstRep =
|
|
3293
|
+
const typeField2 = msh.field(9);
|
|
3294
|
+
const firstRep = typeField2.repetitions[0];
|
|
3139
3295
|
if (firstRep !== void 0) {
|
|
3140
3296
|
const parts = [];
|
|
3141
3297
|
for (let i = 0; i < firstRep.components.length; i++) {
|
|
@@ -3454,7 +3610,7 @@ function emitJson(msg) {
|
|
|
3454
3610
|
name: seg.name,
|
|
3455
3611
|
fields: seg.fields.map((field) => ({
|
|
3456
3612
|
// D-17 + Claude's-Discretion: `repetitions` is ALWAYS `[]` when the
|
|
3457
|
-
// field has zero repetitions
|
|
3613
|
+
// field has zero repetitions: shape-stable, no conditional omission.
|
|
3458
3614
|
repetitions: field.repetitions.map((rep) => ({
|
|
3459
3615
|
components: rep.components.map((comp) => ({
|
|
3460
3616
|
subcomponents: comp.subcomponents.slice()
|
|
@@ -3473,7 +3629,7 @@ function emitJson(msg) {
|
|
|
3473
3629
|
},
|
|
3474
3630
|
segments,
|
|
3475
3631
|
// D-19: ALWAYS present, even when empty. `msg.warnings` is already frozen
|
|
3476
|
-
// at Hl7Message construction (Phase 2)
|
|
3632
|
+
// at Hl7Message construction (Phase 2): pass-through is safe.
|
|
3477
3633
|
warnings: msg.warnings
|
|
3478
3634
|
};
|
|
3479
3635
|
if (msg.profile !== void 0) {
|
|
@@ -3514,6 +3670,205 @@ function emitMshSegment(seg, enc) {
|
|
|
3514
3670
|
return "MSH" + enc.field + msh2 + enc.field + tail;
|
|
3515
3671
|
}
|
|
3516
3672
|
|
|
3673
|
+
// src/builder/encode-composite.ts
|
|
3674
|
+
function sc(value) {
|
|
3675
|
+
return { subcomponents: [value ?? ""] };
|
|
3676
|
+
}
|
|
3677
|
+
function hdComponent(hd) {
|
|
3678
|
+
if (hd === void 0) return { subcomponents: [] };
|
|
3679
|
+
const subs = [hd.namespaceId ?? "", hd.universalId ?? "", hd.universalIdType ?? ""];
|
|
3680
|
+
while (subs.length > 0 && subs[subs.length - 1] === "") subs.pop();
|
|
3681
|
+
return { subcomponents: subs };
|
|
3682
|
+
}
|
|
3683
|
+
function isEmptyComponent(c) {
|
|
3684
|
+
return c.subcomponents.every((s) => s === "");
|
|
3685
|
+
}
|
|
3686
|
+
function toField(components) {
|
|
3687
|
+
const trimmed = components.slice();
|
|
3688
|
+
while (trimmed.length > 0) {
|
|
3689
|
+
const last = trimmed[trimmed.length - 1];
|
|
3690
|
+
if (last !== void 0 && isEmptyComponent(last)) trimmed.pop();
|
|
3691
|
+
else break;
|
|
3692
|
+
}
|
|
3693
|
+
if (trimmed.length === 0) return { repetitions: [], isNull: false };
|
|
3694
|
+
return { repetitions: [{ components: trimmed }], isNull: false };
|
|
3695
|
+
}
|
|
3696
|
+
function encodeXpn(v) {
|
|
3697
|
+
return toField([
|
|
3698
|
+
sc(v.familyName),
|
|
3699
|
+
sc(v.givenName),
|
|
3700
|
+
sc(v.secondName),
|
|
3701
|
+
sc(v.suffix),
|
|
3702
|
+
sc(v.prefix),
|
|
3703
|
+
sc(v.degree),
|
|
3704
|
+
sc(v.nameTypeCode),
|
|
3705
|
+
sc(v.nameRepresentationCode),
|
|
3706
|
+
sc(v.nameContext),
|
|
3707
|
+
sc(v.nameValidityRange),
|
|
3708
|
+
sc(v.nameAssemblyOrder),
|
|
3709
|
+
sc(v.effectiveDate),
|
|
3710
|
+
sc(v.expirationDate),
|
|
3711
|
+
sc(v.professionalSuffix)
|
|
3712
|
+
]);
|
|
3713
|
+
}
|
|
3714
|
+
function encodeXad(v) {
|
|
3715
|
+
return toField([
|
|
3716
|
+
sc(v.street),
|
|
3717
|
+
sc(v.otherDesignation),
|
|
3718
|
+
sc(v.city),
|
|
3719
|
+
sc(v.stateOrProvince),
|
|
3720
|
+
sc(v.zipOrPostalCode),
|
|
3721
|
+
sc(v.country),
|
|
3722
|
+
sc(v.addressType),
|
|
3723
|
+
sc(v.otherGeographicDesignation),
|
|
3724
|
+
sc(v.countyParishCode),
|
|
3725
|
+
sc(v.censusTract),
|
|
3726
|
+
sc(v.addressRepresentationCode),
|
|
3727
|
+
sc(v.addressValidityRange)
|
|
3728
|
+
]);
|
|
3729
|
+
}
|
|
3730
|
+
function encodeCx(v) {
|
|
3731
|
+
return toField([
|
|
3732
|
+
sc(v.idNumber),
|
|
3733
|
+
sc(v.checkDigit),
|
|
3734
|
+
sc(v.checkDigitScheme),
|
|
3735
|
+
hdComponent(v.assigningAuthority),
|
|
3736
|
+
sc(v.identifierTypeCode),
|
|
3737
|
+
sc(v.assigningFacility),
|
|
3738
|
+
sc(v.effectiveDate),
|
|
3739
|
+
sc(v.expirationDate),
|
|
3740
|
+
sc(v.assigningJurisdiction),
|
|
3741
|
+
sc(v.assigningAgencyOrDepartment)
|
|
3742
|
+
]);
|
|
3743
|
+
}
|
|
3744
|
+
function encodeCwe(v) {
|
|
3745
|
+
const components = [
|
|
3746
|
+
sc(v.identifier),
|
|
3747
|
+
sc(v.text),
|
|
3748
|
+
sc(v.nameOfCodingSystem),
|
|
3749
|
+
sc(v.alternateIdentifier),
|
|
3750
|
+
sc(v.alternateText),
|
|
3751
|
+
sc(v.nameOfAlternateCodingSystem),
|
|
3752
|
+
sc(v.codingSystemVersionId),
|
|
3753
|
+
sc(v.alternateCodingSystemVersionId),
|
|
3754
|
+
sc(v.originalText)
|
|
3755
|
+
];
|
|
3756
|
+
for (const extra of v.extraComponents ?? []) components.push(sc(extra));
|
|
3757
|
+
return toField(components);
|
|
3758
|
+
}
|
|
3759
|
+
function encodeCe(v) {
|
|
3760
|
+
const components = [
|
|
3761
|
+
sc(v.identifier),
|
|
3762
|
+
sc(v.text),
|
|
3763
|
+
sc(v.nameOfCodingSystem),
|
|
3764
|
+
sc(v.alternateIdentifier),
|
|
3765
|
+
sc(v.alternateText),
|
|
3766
|
+
sc(v.nameOfAlternateCodingSystem)
|
|
3767
|
+
];
|
|
3768
|
+
for (const extra of v.extraComponents ?? []) components.push(sc(extra));
|
|
3769
|
+
return toField(components);
|
|
3770
|
+
}
|
|
3771
|
+
function encodeXtn(v) {
|
|
3772
|
+
return toField([
|
|
3773
|
+
sc(v.telephoneNumber),
|
|
3774
|
+
sc(v.telecommunicationUseCode),
|
|
3775
|
+
sc(v.telecommunicationEquipmentType),
|
|
3776
|
+
sc(v.emailAddress),
|
|
3777
|
+
sc(v.countryCode),
|
|
3778
|
+
sc(v.areaCityCode),
|
|
3779
|
+
sc(v.localNumber),
|
|
3780
|
+
sc(v.extension),
|
|
3781
|
+
sc(v.anyText),
|
|
3782
|
+
sc(v.extensionPrefix),
|
|
3783
|
+
sc(v.speedDialCode),
|
|
3784
|
+
sc(v.unformattedTelephoneNumber)
|
|
3785
|
+
]);
|
|
3786
|
+
}
|
|
3787
|
+
function encodePl(v) {
|
|
3788
|
+
return toField([
|
|
3789
|
+
sc(v.pointOfCare),
|
|
3790
|
+
sc(v.room),
|
|
3791
|
+
sc(v.bed),
|
|
3792
|
+
hdComponent(v.facility),
|
|
3793
|
+
sc(v.locationStatus),
|
|
3794
|
+
sc(v.personLocationType),
|
|
3795
|
+
sc(v.building),
|
|
3796
|
+
sc(v.floor),
|
|
3797
|
+
sc(v.locationDescription),
|
|
3798
|
+
sc(v.comprehensiveLocationId),
|
|
3799
|
+
sc(v.assigningAuthorityForLocation)
|
|
3800
|
+
]);
|
|
3801
|
+
}
|
|
3802
|
+
function encodeHd(v) {
|
|
3803
|
+
return toField([sc(v.namespaceId), sc(v.universalId), sc(v.universalIdType)]);
|
|
3804
|
+
}
|
|
3805
|
+
function encodeTs(v) {
|
|
3806
|
+
const raw = typeof v === "string" ? v : v.raw;
|
|
3807
|
+
return toField([sc(raw)]);
|
|
3808
|
+
}
|
|
3809
|
+
function encodeNm(v) {
|
|
3810
|
+
let raw;
|
|
3811
|
+
if (typeof v === "number") raw = String(v);
|
|
3812
|
+
else if (typeof v === "string") raw = v;
|
|
3813
|
+
else raw = v.raw;
|
|
3814
|
+
return toField([sc(raw)]);
|
|
3815
|
+
}
|
|
3816
|
+
function encodeXcn(v) {
|
|
3817
|
+
return toField([
|
|
3818
|
+
sc(v.idNumber),
|
|
3819
|
+
sc(v.familyName),
|
|
3820
|
+
sc(v.givenName),
|
|
3821
|
+
sc(v.secondName),
|
|
3822
|
+
sc(v.suffix),
|
|
3823
|
+
sc(v.prefix),
|
|
3824
|
+
sc(v.degree),
|
|
3825
|
+
sc(v.sourceTable),
|
|
3826
|
+
hdComponent(v.assigningAuthority),
|
|
3827
|
+
sc(v.nameTypeCode),
|
|
3828
|
+
sc(v.identifierCheckDigit),
|
|
3829
|
+
sc(v.checkDigitScheme),
|
|
3830
|
+
sc(v.identifierTypeCode)
|
|
3831
|
+
]);
|
|
3832
|
+
}
|
|
3833
|
+
function encodeComposite(kind, value) {
|
|
3834
|
+
switch (kind) {
|
|
3835
|
+
case "XPN":
|
|
3836
|
+
return encodeXpn(value);
|
|
3837
|
+
case "XAD":
|
|
3838
|
+
return encodeXad(value);
|
|
3839
|
+
case "CX":
|
|
3840
|
+
return encodeCx(value);
|
|
3841
|
+
case "CWE":
|
|
3842
|
+
return encodeCwe(value);
|
|
3843
|
+
case "CE":
|
|
3844
|
+
return encodeCe(value);
|
|
3845
|
+
case "XTN":
|
|
3846
|
+
return encodeXtn(value);
|
|
3847
|
+
case "PL":
|
|
3848
|
+
return encodePl(value);
|
|
3849
|
+
case "TS":
|
|
3850
|
+
return encodeTs(value);
|
|
3851
|
+
case "NM":
|
|
3852
|
+
return encodeNm(value);
|
|
3853
|
+
case "HD":
|
|
3854
|
+
return encodeHd(value);
|
|
3855
|
+
case "XCN":
|
|
3856
|
+
return encodeXcn(value);
|
|
3857
|
+
default: {
|
|
3858
|
+
const never = kind;
|
|
3859
|
+
throw new TypeError(`encodeComposite: unknown composite kind ${JSON.stringify(never)}.`);
|
|
3860
|
+
}
|
|
3861
|
+
}
|
|
3862
|
+
}
|
|
3863
|
+
function encodeCompositeReps(kind, values) {
|
|
3864
|
+
const repetitions = [];
|
|
3865
|
+
for (const value of values) {
|
|
3866
|
+
const encoded = encodeComposite(kind, value);
|
|
3867
|
+
for (const rep of encoded.repetitions) repetitions.push(rep);
|
|
3868
|
+
}
|
|
3869
|
+
return { repetitions, isNull: false };
|
|
3870
|
+
}
|
|
3871
|
+
|
|
3517
3872
|
// src/model/message.ts
|
|
3518
3873
|
var SEGMENT_NAME_RE2 = /^[A-Z][A-Z0-9]{2}$/u;
|
|
3519
3874
|
function toMutableArray(arr) {
|
|
@@ -3523,9 +3878,8 @@ var Hl7Message = class {
|
|
|
3523
3878
|
/**
|
|
3524
3879
|
* Raw positional tree produced by the parser. 1-indexed per HL7 convention
|
|
3525
3880
|
* (`fields[0]` is the segment-name / MSH separator placeholder slot). Use
|
|
3526
|
-
* `segments(type)` / `allSegments()` for typed wrapper access
|
|
3527
|
-
* is exposed for advanced callers that need the raw tree directly
|
|
3528
|
-
* future serialization phase 5).
|
|
3881
|
+
* `segments(type)` / `allSegments()` for typed wrapper access: this field
|
|
3882
|
+
* is exposed for advanced callers that need the raw tree directly.
|
|
3529
3883
|
*/
|
|
3530
3884
|
rawSegments;
|
|
3531
3885
|
encodingCharacters;
|
|
@@ -3533,7 +3887,7 @@ var Hl7Message = class {
|
|
|
3533
3887
|
warnings;
|
|
3534
3888
|
profile;
|
|
3535
3889
|
/**
|
|
3536
|
-
* Merged `dateFormats` list
|
|
3890
|
+
* Merged `dateFormats` list: `options.dateFormats ++ profile.dateFormats`
|
|
3537
3891
|
* deduped first-occurrence per D-21. Empty array when neither source
|
|
3538
3892
|
* supplied any formats. Exposed publicly so helpers (`msg.meta.timestamp`)
|
|
3539
3893
|
* and advanced callers can introspect the active cascade.
|
|
@@ -3541,7 +3895,7 @@ var Hl7Message = class {
|
|
|
3541
3895
|
dateFormats;
|
|
3542
3896
|
/**
|
|
3543
3897
|
* Merged `customSegments` map from the applied profile, stored so
|
|
3544
|
-
* `allSegments()` can hand per-segment
|
|
3898
|
+
* `allSegments()` can hand per-segment portions to `Segment` constructors
|
|
3545
3899
|
* (D-16). Undefined when no profile was applied.
|
|
3546
3900
|
* @internal
|
|
3547
3901
|
*/
|
|
@@ -3550,40 +3904,40 @@ var Hl7Message = class {
|
|
|
3550
3904
|
* Lazily built cache of Segment wrappers keyed by segment type. Built on
|
|
3551
3905
|
* first `segments(type)` call and filtered from `_allSegments` so
|
|
3552
3906
|
* individual Segment instances are identical across both caches (D-11).
|
|
3553
|
-
*
|
|
3907
|
+
* The mutation methods drop this cache wholesale.
|
|
3554
3908
|
* @internal
|
|
3555
3909
|
*/
|
|
3556
3910
|
_segmentsByType;
|
|
3557
3911
|
/**
|
|
3558
3912
|
* Lazily built cache of every Segment wrapper in document order. Built on
|
|
3559
|
-
* first `segments(type)` / `allSegments()` call.
|
|
3913
|
+
* first `segments(type)` / `allSegments()` call. The mutation methods
|
|
3560
3914
|
* drop this cache wholesale.
|
|
3561
3915
|
* @internal
|
|
3562
3916
|
*/
|
|
3563
3917
|
_allSegments;
|
|
3564
3918
|
/**
|
|
3565
|
-
* Lazily built `Meta` view (
|
|
3566
|
-
* by `invalidateCaches`. `Meta` is always defined (D-03
|
|
3919
|
+
* Lazily built `Meta` view (memoized). Dropped wholesale
|
|
3920
|
+
* by `invalidateCaches`. `Meta` is always defined (D-03: MSH absence
|
|
3567
3921
|
* throws `NO_MSH_SEGMENT` at parse time) so no null-sentinel is needed.
|
|
3568
3922
|
* @internal
|
|
3569
3923
|
*/
|
|
3570
3924
|
_meta;
|
|
3571
3925
|
/**
|
|
3572
|
-
* Lazily built `MessageStructure` view
|
|
3573
|
-
* `invalidateCaches`. Always defined
|
|
3926
|
+
* Lazily built `MessageStructure` view. Dropped wholesale by
|
|
3927
|
+
* `invalidateCaches`. Always defined: `analyzeMessageStructure` returns an
|
|
3574
3928
|
* `recognized: false` summary for unmodelled types rather than absence.
|
|
3575
3929
|
* @internal
|
|
3576
3930
|
*/
|
|
3577
3931
|
_structure;
|
|
3578
3932
|
/**
|
|
3579
|
-
* Lazily built `Patient | undefined` view (
|
|
3933
|
+
* Lazily built `Patient | undefined` view (memoized). Uses
|
|
3580
3934
|
* a null-sentinel cache because `undefined` means "not yet computed" while
|
|
3581
3935
|
* `null` means "computed, absent". D-04: no PID → public value `undefined`.
|
|
3582
3936
|
* @internal
|
|
3583
3937
|
*/
|
|
3584
3938
|
_patient;
|
|
3585
3939
|
/**
|
|
3586
|
-
* Lazily built `Visit | undefined` view (
|
|
3940
|
+
* Lazily built `Visit | undefined` view (memoized). Same
|
|
3587
3941
|
* null-sentinel convention as `_patient`. HELPERS-03: no PV1 → public
|
|
3588
3942
|
* value `undefined`.
|
|
3589
3943
|
* @internal
|
|
@@ -3607,9 +3961,9 @@ var Hl7Message = class {
|
|
|
3607
3961
|
}
|
|
3608
3962
|
/**
|
|
3609
3963
|
* Resolve a dot-path (e.g. `PID.5.1`, `OBX[2].5`, `PID.3[0].1`) to its
|
|
3610
|
-
* decoded leaf string (unescaped once at parse
|
|
3611
|
-
*
|
|
3612
|
-
* resolve
|
|
3964
|
+
* decoded leaf string (unescaped once at parse: never re-unescaped on
|
|
3965
|
+
* read). Returns `undefined` when the path doesn't
|
|
3966
|
+
* resolve: never throws on missing path (MODEL-05). Throws `TypeError`
|
|
3613
3967
|
* on malformed path syntax (e.g. `"pid.5"`, empty string).
|
|
3614
3968
|
*
|
|
3615
3969
|
* @example
|
|
@@ -3618,7 +3972,7 @@ var Hl7Message = class {
|
|
|
3618
3972
|
* msg.get("PID.5.1"); // "Smith"
|
|
3619
3973
|
* msg.get("OBX[2].5"); // third OBX's 5th field
|
|
3620
3974
|
* msg.get("NOT.9.9"); // undefined
|
|
3621
|
-
* msg.get("MSH.12"); // "2.5"
|
|
3975
|
+
* msg.get("MSH.12"); // "2.5": HL7 version string
|
|
3622
3976
|
* ```
|
|
3623
3977
|
*/
|
|
3624
3978
|
get(path) {
|
|
@@ -3627,7 +3981,7 @@ var Hl7Message = class {
|
|
|
3627
3981
|
/**
|
|
3628
3982
|
* Return every `Segment` of `segmentType` in document order. Returns `[]`
|
|
3629
3983
|
* (empty array, NEVER `undefined`) when no segment of that type exists
|
|
3630
|
-
* (MODEL-02). Alias for `segments(segmentType)
|
|
3984
|
+
* (MODEL-02). Alias for `segments(segmentType)`: shares the same cache.
|
|
3631
3985
|
*
|
|
3632
3986
|
* @example
|
|
3633
3987
|
* ```ts
|
|
@@ -3643,7 +3997,7 @@ var Hl7Message = class {
|
|
|
3643
3997
|
* Return the cached array of `Segment` wrappers for `segmentType` in
|
|
3644
3998
|
* document order. The returned array identity and the individual Segment
|
|
3645
3999
|
* instances are both stable across calls (D-11). Invalidated wholesale
|
|
3646
|
-
* by
|
|
4000
|
+
* by the mutation methods.
|
|
3647
4001
|
*
|
|
3648
4002
|
* @example
|
|
3649
4003
|
* ```ts
|
|
@@ -3666,7 +4020,7 @@ var Hl7Message = class {
|
|
|
3666
4020
|
* Iterate every `Segment` in document order (MSH first, then every
|
|
3667
4021
|
* subsequent segment). Cached per-message; same array reference and same
|
|
3668
4022
|
* Segment instances on repeat calls (D-11). Invalidated wholesale by
|
|
3669
|
-
*
|
|
4023
|
+
* the mutation methods.
|
|
3670
4024
|
*
|
|
3671
4025
|
* @example
|
|
3672
4026
|
* ```ts
|
|
@@ -3693,14 +4047,14 @@ var Hl7Message = class {
|
|
|
3693
4047
|
}
|
|
3694
4048
|
/**
|
|
3695
4049
|
* MSH-derived message metadata (type, controlId, timestamp, version, etc.).
|
|
3696
|
-
* D-01: plain object. D-02: memoized
|
|
4050
|
+
* D-01: plain object. D-02: memoized: `msg.meta === msg.meta` across
|
|
3697
4051
|
* reads until mutation invalidates. D-03: always defined (MSH absence
|
|
3698
4052
|
* throws `NO_MSH_SEGMENT` at parse time).
|
|
3699
4053
|
*
|
|
3700
4054
|
* @example
|
|
3701
4055
|
* ```ts
|
|
3702
4056
|
* console.log(msg.meta.type); // "ADT^A01"
|
|
3703
|
-
* console.log(msg.meta.timestamp?.raw); // fidelity TS
|
|
4057
|
+
* console.log(msg.meta.timestamp?.raw); // fidelity TS
|
|
3704
4058
|
* console.log(msg.meta.controlId); // "MSG001"
|
|
3705
4059
|
* ```
|
|
3706
4060
|
*/
|
|
@@ -3708,11 +4062,11 @@ var Hl7Message = class {
|
|
|
3708
4062
|
return this._meta ??= buildMeta(this);
|
|
3709
4063
|
}
|
|
3710
4064
|
/**
|
|
3711
|
-
* Structural-conformance summary for the common message types
|
|
3712
|
-
*
|
|
4065
|
+
* Structural-conformance summary for the common message types: a
|
|
4066
|
+
* misroute/truncation safety net, NOT a conformance validator.
|
|
3713
4067
|
* Reports, per the message's recognized (MSH-9.1, MSH-9.2) type, which
|
|
3714
4068
|
* Required segment groups are present and which are entirely absent
|
|
3715
|
-
* (`missingGroups
|
|
4069
|
+
* (`missingGroups`: the same set the parser flags as
|
|
3716
4070
|
* `MISSING_EXPECTED_GROUP` warnings). For an unmodelled type, `recognized`
|
|
3717
4071
|
* is `false` and `missingGroups` is empty. D-02: memoized.
|
|
3718
4072
|
*
|
|
@@ -3727,14 +4081,14 @@ var Hl7Message = class {
|
|
|
3727
4081
|
}
|
|
3728
4082
|
/**
|
|
3729
4083
|
* PID-derived patient view, or `undefined` when no PID segment exists
|
|
3730
|
-
* (D-04). D-02: memoized. HELPERS-07: never throws
|
|
4084
|
+
* (D-04). D-02: memoized. HELPERS-07: never throws: absent fields
|
|
3731
4085
|
* surface as `undefined` on the returned `Patient` object.
|
|
3732
4086
|
*
|
|
3733
4087
|
* @example
|
|
3734
4088
|
* ```ts
|
|
3735
4089
|
* console.log(msg.patient?.mrn);
|
|
3736
4090
|
* console.log(msg.patient?.fullName);
|
|
3737
|
-
* console.log(msg.patient?.dateOfBirth?.raw); // fidelity TS
|
|
4091
|
+
* console.log(msg.patient?.dateOfBirth?.raw); // fidelity TS: e.g. "19800115"
|
|
3738
4092
|
* ```
|
|
3739
4093
|
*/
|
|
3740
4094
|
get patient() {
|
|
@@ -3762,7 +4116,7 @@ var Hl7Message = class {
|
|
|
3762
4116
|
}
|
|
3763
4117
|
/**
|
|
3764
4118
|
* Every OBX segment as a typed Observation in document order. D-05:
|
|
3765
|
-
* returns `[]` when no OBX present. D-06: NOT memoized
|
|
4119
|
+
* returns `[]` when no OBX present. D-06: NOT memoized: each call
|
|
3766
4120
|
* re-walks `rawSegments`. Value type is discriminated per D-13.
|
|
3767
4121
|
*
|
|
3768
4122
|
* @example
|
|
@@ -3777,7 +4131,7 @@ var Hl7Message = class {
|
|
|
3777
4131
|
}
|
|
3778
4132
|
/**
|
|
3779
4133
|
* Every OBR as an Order with its OBX children grouped positionally (D-12) and
|
|
3780
|
-
* its TQ1 / legacy embedded-TQ (ORC-7) `timings` (
|
|
4134
|
+
* its TQ1 / legacy embedded-TQ (ORC-7) `timings` (the repeat pattern is
|
|
3781
4135
|
* surfaced verbatim, never resolved to a schedule). D-05: returns `[]` when no
|
|
3782
4136
|
* OBR present. D-06: not memoized.
|
|
3783
4137
|
*
|
|
@@ -3785,7 +4139,7 @@ var Hl7Message = class {
|
|
|
3785
4139
|
* ```ts
|
|
3786
4140
|
* for (const order of msg.orders()) {
|
|
3787
4141
|
* console.log(order.placerOrderNumber, order.observations.length);
|
|
3788
|
-
* for (const t of order.timings) console.log(t.repeatPattern?.code); // e.g. "Q6H"
|
|
4142
|
+
* for (const t of order.timings) console.log(t.repeatPattern?.code); // e.g. "Q6H": verbatim
|
|
3789
4143
|
* }
|
|
3790
4144
|
* ```
|
|
3791
4145
|
*/
|
|
@@ -3793,11 +4147,11 @@ var Hl7Message = class {
|
|
|
3793
4147
|
return orders(this);
|
|
3794
4148
|
}
|
|
3795
4149
|
/**
|
|
3796
|
-
* Message-level NTE notes
|
|
4150
|
+
* Message-level NTE notes: every NTE segment with no recognized
|
|
3797
4151
|
* preceding parent (not immediately following a `PID`, `ORC`, `OBR`, or
|
|
3798
4152
|
* `OBX`), surfaced verbatim in document order so nothing is dropped. Notes
|
|
3799
4153
|
* that DO attach to a specific patient / order / result are exposed on those
|
|
3800
|
-
* helper outputs (`msg.patient?.notes`, `order.notes`, `observation.notes`)
|
|
4154
|
+
* helper outputs (`msg.patient?.notes`, `order.notes`, `observation.notes`),
|
|
3801
4155
|
* not here. D-05: returns `[]` when there are none. D-06: NOT memoized.
|
|
3802
4156
|
*
|
|
3803
4157
|
* @example
|
|
@@ -3810,7 +4164,7 @@ var Hl7Message = class {
|
|
|
3810
4164
|
}
|
|
3811
4165
|
/**
|
|
3812
4166
|
* Every recognized ADT patient-identity event (merge / move / link /
|
|
3813
|
-
* unlink / person add/update
|
|
4167
|
+
* unlink / person add/update), with the MRG-sourced
|
|
3814
4168
|
* `prior` and PID/PV1-sourced `surviving` parties labelled by role and the
|
|
3815
4169
|
* spec-constant `direction: "MRG_TO_PID"` on merge/move events. Returns
|
|
3816
4170
|
* `[]` when the trigger event is not in the identity family. D-06: not
|
|
@@ -3831,13 +4185,13 @@ var Hl7Message = class {
|
|
|
3831
4185
|
}
|
|
3832
4186
|
/**
|
|
3833
4187
|
* Every RXO/RXE/RXD/RXA as a typed `Medication`, with RXR (route) and RXC
|
|
3834
|
-
* (component) segments grouped positionally under their parent
|
|
3835
|
-
*
|
|
3836
|
-
*
|
|
3837
|
-
*
|
|
4188
|
+
* (component) segments grouped positionally under their parent. D-05:
|
|
4189
|
+
* returns `[]` when no RX* parent present. D-06: not memoized. The give
|
|
4190
|
+
* *amount* and give *strength* are surfaced separately and never
|
|
4191
|
+
* reconciled.
|
|
3838
4192
|
*
|
|
3839
4193
|
* Each medication also carries its TQ1 / legacy embedded-TQ (RXE-1) `timings`
|
|
3840
|
-
* (
|
|
4194
|
+
* (repeat pattern verbatim, never resolved to a schedule).
|
|
3841
4195
|
*
|
|
3842
4196
|
* @example
|
|
3843
4197
|
* ```ts
|
|
@@ -3854,11 +4208,11 @@ var Hl7Message = class {
|
|
|
3854
4208
|
/**
|
|
3855
4209
|
* Every RXA of a VXU^V04 as a typed `Immunization`, with RXR (route/site)
|
|
3856
4210
|
* and OBX children grouped positionally under the RXA and `orderControl`
|
|
3857
|
-
* from the preceding ORC of the VXU order group
|
|
4211
|
+
* from the preceding ORC of the VXU order group. D-05:
|
|
3858
4212
|
* returns `[]` when no RXA present. D-06: not memoized. The vaccine code
|
|
3859
4213
|
* carries its own provenance; the action code (RXA-21) is surfaced verbatim
|
|
3860
4214
|
* and `recordOrigin` (administered vs historical) is derived only from the
|
|
3861
|
-
* well-known NIP001 RXA-9.1 codes
|
|
4215
|
+
* well-known NIP001 RXA-9.1 codes: never guessed.
|
|
3862
4216
|
*
|
|
3863
4217
|
* @example
|
|
3864
4218
|
* ```ts
|
|
@@ -3922,13 +4276,13 @@ var Hl7Message = class {
|
|
|
3922
4276
|
return insurance(this);
|
|
3923
4277
|
}
|
|
3924
4278
|
/**
|
|
3925
|
-
* Every SCH of an SIU message as a typed `Appointment
|
|
4279
|
+
* Every SCH of an SIU message as a typed `Appointment`, with
|
|
3926
4280
|
* the AIS/AIG/AIL/AIP resource segments that follow it grouped positionally
|
|
3927
4281
|
* under that SCH. Surfaces the placer/filler appointment ids, SCH-25 filler
|
|
3928
4282
|
* status (Table 0278), SCH-11 start/end timing, and the resource groups
|
|
3929
4283
|
* (service / general / location / personnel). D-05: returns `[]` when no SCH
|
|
3930
4284
|
* is present. D-06: not memoized. Never throws (HELPERS-07). Not a
|
|
3931
|
-
* scheduling-workflow state machine
|
|
4285
|
+
* scheduling-workflow state machine: see the package known-limitations.
|
|
3932
4286
|
*
|
|
3933
4287
|
* @example
|
|
3934
4288
|
* ```ts
|
|
@@ -3942,10 +4296,10 @@ var Hl7Message = class {
|
|
|
3942
4296
|
return appointments(this);
|
|
3943
4297
|
}
|
|
3944
4298
|
/**
|
|
3945
|
-
* Every TXA of an MDM message as a typed `ClinicalDocument
|
|
4299
|
+
* Every TXA of an MDM message as a typed `ClinicalDocument`,
|
|
3946
4300
|
* with the OBX narrative body grouped positionally under that TXA. The
|
|
3947
4301
|
* completion status (TXA-17) and availability status (TXA-19) are surfaced as
|
|
3948
|
-
* **distinct** fields and never conflated
|
|
4302
|
+
* **distinct** fields and never conflated: a document can be available before
|
|
3949
4303
|
* it is authenticated, and reading a preliminary document as final is the
|
|
3950
4304
|
* harm. D-05: returns `[]` when no TXA is present. D-06: not memoized. Never
|
|
3951
4305
|
* throws (HELPERS-07).
|
|
@@ -3962,10 +4316,10 @@ var Hl7Message = class {
|
|
|
3962
4316
|
return documents(this);
|
|
3963
4317
|
}
|
|
3964
4318
|
/**
|
|
3965
|
-
* Every FT1 of a DFT message as a typed `Charge
|
|
4319
|
+
* Every FT1 of a DFT message as a typed `Charge`, one per
|
|
3966
4320
|
* FT1 in document order. Surfaces billing-critical fields (FT1-6 transaction
|
|
3967
4321
|
* type, FT1-7 code, FT1-11/12 extended/unit amount, FT1-19 diagnosis linkage)
|
|
3968
|
-
* with **no billing logic and no money-as-float
|
|
4322
|
+
* with **no billing logic and no money-as-float**: amounts are the verbatim
|
|
3969
4323
|
* CP wire text. D-05: returns `[]` when no FT1 is present. D-06: not memoized.
|
|
3970
4324
|
* Never throws (HELPERS-07).
|
|
3971
4325
|
*
|
|
@@ -3986,7 +4340,7 @@ var Hl7Message = class {
|
|
|
3986
4340
|
* D-05; MSH-1 and MSH-2 are inlined verbatim from
|
|
3987
4341
|
* `this.encodingCharacters` per D-06; every field string passes through
|
|
3988
4342
|
* `reescape` per D-04. `RawField.isNull === true` is preserved as the
|
|
3989
|
-
* HL7 literal `""` (D-02). Pure
|
|
4343
|
+
* HL7 literal `""` (D-02). Pure: never warns, never throws (D-07).
|
|
3990
4344
|
*
|
|
3991
4345
|
* @example
|
|
3992
4346
|
* ```ts
|
|
@@ -4004,7 +4358,7 @@ var Hl7Message = class {
|
|
|
4004
4358
|
* Re-walks `rawSegments` on every call (D-30 no caching). Mirrors the
|
|
4005
4359
|
* raw tree one-for-one, preserves `isNull`, always includes
|
|
4006
4360
|
* `warnings: []`, and includes `profile: { name, lineage }` only when
|
|
4007
|
-
* `this.profile` is truthy (D-19/D-20). Pure
|
|
4361
|
+
* `this.profile` is truthy (D-19/D-20). Pure: never warns, never throws.
|
|
4008
4362
|
*
|
|
4009
4363
|
* @example
|
|
4010
4364
|
* ```ts
|
|
@@ -4023,16 +4377,16 @@ var Hl7Message = class {
|
|
|
4023
4377
|
* debugging (SER-04). Single opinionated format (D-22 no options):
|
|
4024
4378
|
* header line with type / controlId / timestamp / segment count, then
|
|
4025
4379
|
* one line per segment with labeled `[N]=value` fields (D-23). Composite
|
|
4026
|
-
* values render as their raw HL7 string
|
|
4027
|
-
* (D-24). Pure
|
|
4380
|
+
* values render as their raw HL7 string: depth stops at field level
|
|
4381
|
+
* (D-24). Pure: never warns, never throws (D-26).
|
|
4028
4382
|
*
|
|
4029
4383
|
* **Field values render as their raw HL7 string representation.**
|
|
4030
|
-
* Embedded delimiters in user data appear as escape sequences
|
|
4384
|
+
* Embedded delimiters in user data appear as escape sequences: e.g.
|
|
4031
4385
|
* a patient family name containing `|` renders as `Smith\F\Jones`
|
|
4032
4386
|
* (NOT `Smith|Jones`). This preserves round-trip fidelity: copy-pasting
|
|
4033
4387
|
* prettyPrint output into `parseHL7` yields a structurally equivalent
|
|
4034
4388
|
* message. For un-escaped human display, parse the composite first via
|
|
4035
|
-
* typed accessors (e.g. `msg.patient?.familyName`)
|
|
4389
|
+
* typed accessors (e.g. `msg.patient?.familyName`): those return
|
|
4036
4390
|
* already-decoded strings.
|
|
4037
4391
|
*
|
|
4038
4392
|
* @example
|
|
@@ -4052,13 +4406,13 @@ var Hl7Message = class {
|
|
|
4052
4406
|
* Set the string value at a dot-path. Mutates the underlying tree and
|
|
4053
4407
|
* returns `this` for chaining (D-15). Auto-creates missing repetitions,
|
|
4054
4408
|
* components, and subcomponents WITHIN an existing field, but does NOT
|
|
4055
|
-
* auto-create segments
|
|
4409
|
+
* auto-create segments: callers must `addSegment` first (throws
|
|
4056
4410
|
* `TypeError` with an actionable message otherwise).
|
|
4057
4411
|
*
|
|
4058
4412
|
* The value is accepted verbatim: unescaped delimiter characters are NOT
|
|
4059
|
-
* rejected on input (D-18). Re-escaping
|
|
4413
|
+
* rejected on input (D-18). Re-escaping is the serializer's concern.
|
|
4060
4414
|
*
|
|
4061
|
-
* MSH-1 / MSH-2 follow the user-facing HL7 convention
|
|
4415
|
+
* MSH-1 / MSH-2 follow the user-facing HL7 convention: `setField("MSH.3", ...)`
|
|
4062
4416
|
* targets MSH-3 (sending application), matching `msg.get("MSH.3")`.
|
|
4063
4417
|
*
|
|
4064
4418
|
* Segment/Field wrapper caches are invalidated wholesale on success (D-17).
|
|
@@ -4095,7 +4449,7 @@ var Hl7Message = class {
|
|
|
4095
4449
|
const mutSegments = toMutableArray(this.rawSegments);
|
|
4096
4450
|
const seg = mutSegments[segIdx];
|
|
4097
4451
|
if (seg === void 0) {
|
|
4098
|
-
throw new Error("setField: internal invariant
|
|
4452
|
+
throw new Error("setField: internal invariant, segment disappeared after lookup.");
|
|
4099
4453
|
}
|
|
4100
4454
|
const mutFields = toMutableArray(seg.fields);
|
|
4101
4455
|
while (mutFields.length <= rawFieldIndex) {
|
|
@@ -4103,7 +4457,7 @@ var Hl7Message = class {
|
|
|
4103
4457
|
}
|
|
4104
4458
|
const field = mutFields[rawFieldIndex];
|
|
4105
4459
|
if (field === void 0) {
|
|
4106
|
-
throw new Error("setField: internal invariant
|
|
4460
|
+
throw new Error("setField: internal invariant, field missing after growth.");
|
|
4107
4461
|
}
|
|
4108
4462
|
const mutReps = toMutableArray(field.repetitions);
|
|
4109
4463
|
const repIdx = parsed.repetitionIndex ?? 0;
|
|
@@ -4112,7 +4466,7 @@ var Hl7Message = class {
|
|
|
4112
4466
|
}
|
|
4113
4467
|
const rep = mutReps[repIdx];
|
|
4114
4468
|
if (rep === void 0) {
|
|
4115
|
-
throw new Error("setField: internal invariant
|
|
4469
|
+
throw new Error("setField: internal invariant, repetition missing after growth.");
|
|
4116
4470
|
}
|
|
4117
4471
|
const mutComps = toMutableArray(rep.components);
|
|
4118
4472
|
const compIdx = (parsed.componentIndex ?? 1) - 1;
|
|
@@ -4121,7 +4475,7 @@ var Hl7Message = class {
|
|
|
4121
4475
|
}
|
|
4122
4476
|
const comp = mutComps[compIdx];
|
|
4123
4477
|
if (comp === void 0) {
|
|
4124
|
-
throw new Error("setField: internal invariant
|
|
4478
|
+
throw new Error("setField: internal invariant, component missing after growth.");
|
|
4125
4479
|
}
|
|
4126
4480
|
const mutSubs = toMutableArray(comp.subcomponents);
|
|
4127
4481
|
const subIdx = (parsed.subcomponentIndex ?? 1) - 1;
|
|
@@ -4141,9 +4495,95 @@ var Hl7Message = class {
|
|
|
4141
4495
|
this.invalidateCaches();
|
|
4142
4496
|
return this;
|
|
4143
4497
|
}
|
|
4498
|
+
/**
|
|
4499
|
+
* Set a **typed composite** at a field (or field-repetition) dot-path:
|
|
4500
|
+
* the conservative-emit mirror of the typed read accessors
|
|
4501
|
+
* (`asXpn`/`asCx`/…). The caller passes a structured value (an XPN name, a CX
|
|
4502
|
+
* identifier, a TS timestamp, …) by its {@link CompositeKind}, and the setter
|
|
4503
|
+
* encodes it into a spec-clean field using the encode-safe path: any
|
|
4504
|
+
* delimiter embedded in a component value is **escaped, never injected**, so
|
|
4505
|
+
* a `familyName` of `"Smith^Jr"` re-parses to exactly that string rather than
|
|
4506
|
+
* forging a component boundary. No hand-assembly of `^`/`&`/`~`.
|
|
4507
|
+
*
|
|
4508
|
+
* The path must resolve to a **field** (`"PID.5"`) or a specific
|
|
4509
|
+
* **repetition** of a field (`"PID.11[1]"`). A component/subcomponent-level
|
|
4510
|
+
* path (`"PID.5.1"`) is rejected with `TypeError`: a composite occupies a
|
|
4511
|
+
* whole field, not a single component. Like {@link setField}, the target
|
|
4512
|
+
* segment must already exist (`addSegment` first); the repetition defaults to
|
|
4513
|
+
* index 0 and other repetitions of the field are preserved.
|
|
4514
|
+
*
|
|
4515
|
+
* Never fabricates: an omitted optional composite field encodes to an
|
|
4516
|
+
* empty/absent component, never a defaulted value; an all-empty composite
|
|
4517
|
+
* clears the field. Segment/helper caches are invalidated on success; the
|
|
4518
|
+
* frozen `warnings` array is untouched.
|
|
4519
|
+
*
|
|
4520
|
+
* @example
|
|
4521
|
+
* ```ts
|
|
4522
|
+
* const msg = buildMessage({ type: "ADT^A01" }).addSegment("PID", [""]);
|
|
4523
|
+
* msg.setComposite("PID.5", "XPN", { familyName: "Smith", givenName: "Ann" });
|
|
4524
|
+
* msg.setComposite("PID.3", "CX", { idNumber: "MRN001", identifierTypeCode: "MR" });
|
|
4525
|
+
* msg.setComposite("PID.7", "TS", "19880705");
|
|
4526
|
+
* msg.get("PID.5.1"); // "Smith"
|
|
4527
|
+
* ```
|
|
4528
|
+
*/
|
|
4529
|
+
setComposite(path, kind, value) {
|
|
4530
|
+
const parsed = parsePath(path);
|
|
4531
|
+
if (parsed.componentIndex !== void 0 || parsed.subcomponentIndex !== void 0) {
|
|
4532
|
+
throw new TypeError(
|
|
4533
|
+
`setComposite: path "${path}" targets a component/subcomponent, but a typed composite occupies a whole field. Use a field path (e.g. "PID.5") or a field-repetition path (e.g. "PID.11[1]").`
|
|
4534
|
+
);
|
|
4535
|
+
}
|
|
4536
|
+
let seen = 0;
|
|
4537
|
+
let segIdx = -1;
|
|
4538
|
+
for (let i = 0; i < this.rawSegments.length; i++) {
|
|
4539
|
+
const s = this.rawSegments[i];
|
|
4540
|
+
if (s === void 0) continue;
|
|
4541
|
+
if (s.name === parsed.segmentType) {
|
|
4542
|
+
if (seen === parsed.segmentIndex) {
|
|
4543
|
+
segIdx = i;
|
|
4544
|
+
break;
|
|
4545
|
+
}
|
|
4546
|
+
seen++;
|
|
4547
|
+
}
|
|
4548
|
+
}
|
|
4549
|
+
if (segIdx === -1) {
|
|
4550
|
+
throw new TypeError(
|
|
4551
|
+
`setComposite: segment "${parsed.segmentType}" (occurrence ${String(parsed.segmentIndex)}) not found. Add it first with addSegment("${parsed.segmentType}", [...]).`
|
|
4552
|
+
);
|
|
4553
|
+
}
|
|
4554
|
+
const encoded = encodeComposite(kind, value);
|
|
4555
|
+
const encodedRep = encoded.repetitions[0] ?? { components: [] };
|
|
4556
|
+
const rawFieldIndex = parsed.segmentType === "MSH" ? parsed.fieldIndex - 1 : parsed.fieldIndex;
|
|
4557
|
+
const mutSegments = toMutableArray(this.rawSegments);
|
|
4558
|
+
const seg = mutSegments[segIdx];
|
|
4559
|
+
if (seg === void 0) {
|
|
4560
|
+
throw new Error("setComposite: internal invariant, segment disappeared after lookup.");
|
|
4561
|
+
}
|
|
4562
|
+
const mutFields = toMutableArray(seg.fields);
|
|
4563
|
+
while (mutFields.length <= rawFieldIndex) {
|
|
4564
|
+
mutFields.push({ repetitions: [], isNull: false });
|
|
4565
|
+
}
|
|
4566
|
+
const field = mutFields[rawFieldIndex];
|
|
4567
|
+
if (field === void 0) {
|
|
4568
|
+
throw new Error("setComposite: internal invariant, field missing after growth.");
|
|
4569
|
+
}
|
|
4570
|
+
const mutReps = toMutableArray(field.repetitions);
|
|
4571
|
+
const repIdx = parsed.repetitionIndex ?? 0;
|
|
4572
|
+
while (mutReps.length <= repIdx) {
|
|
4573
|
+
mutReps.push({ components: [] });
|
|
4574
|
+
}
|
|
4575
|
+
mutReps[repIdx] = encodedRep;
|
|
4576
|
+
const newField = { repetitions: mutReps, isNull: false };
|
|
4577
|
+
mutFields[rawFieldIndex] = newField;
|
|
4578
|
+
const newSeg = { name: seg.name, fields: mutFields };
|
|
4579
|
+
mutSegments[segIdx] = newSeg;
|
|
4580
|
+
this.rawSegments = mutSegments;
|
|
4581
|
+
this.invalidateCaches();
|
|
4582
|
+
return this;
|
|
4583
|
+
}
|
|
4144
4584
|
/**
|
|
4145
4585
|
* Append a new segment to the end of the message. `name` must match
|
|
4146
|
-
* `/^(?:[A-Z]{3}|Z[A-Z0-9]{2})$/u
|
|
4586
|
+
* `/^(?:[A-Z]{3}|Z[A-Z0-9]{2})$/u`: throws `TypeError` otherwise (D-19).
|
|
4147
4587
|
*
|
|
4148
4588
|
* `fields` is interpreted in HL7 1-indexed terms: `addSegment("NTE", [a, b, c])`
|
|
4149
4589
|
* produces a segment whose `NTE-1 = a`, `NTE-2 = b`, `NTE-3 = c`. The
|
|
@@ -4193,14 +4633,14 @@ var Hl7Message = class {
|
|
|
4193
4633
|
/**
|
|
4194
4634
|
* Remove segments by type + occurrence or by type + all. Call shapes:
|
|
4195
4635
|
*
|
|
4196
|
-
* - `removeSegment("NTE")
|
|
4197
|
-
* - `removeSegment("OBX", 1)
|
|
4198
|
-
* - `removeSegment("OBX", { all: true })
|
|
4636
|
+
* - `removeSegment("NTE")`: remove the FIRST NTE (occurrence 0).
|
|
4637
|
+
* - `removeSegment("OBX", 1)`: remove the SECOND OBX (0-indexed per D-01).
|
|
4638
|
+
* - `removeSegment("OBX", { all: true })`: remove ALL OBX segments.
|
|
4199
4639
|
*
|
|
4200
|
-
* `MSH` is protected
|
|
4640
|
+
* `MSH` is protected: `removeSegment("MSH")` throws `TypeError` (every
|
|
4201
4641
|
* HL7 message must retain its MSH segment). Unknown segment types are a
|
|
4202
4642
|
* no-op (idempotent; no throw). Segment name must match the D-19 shape
|
|
4203
|
-
* regex
|
|
4643
|
+
* regex: invalid shapes throw `TypeError` for symmetry with `addSegment`.
|
|
4204
4644
|
*
|
|
4205
4645
|
* Invalidates caches on return; warnings untouched (D-16).
|
|
4206
4646
|
*
|
|
@@ -4251,8 +4691,8 @@ var Hl7Message = class {
|
|
|
4251
4691
|
return this;
|
|
4252
4692
|
}
|
|
4253
4693
|
/**
|
|
4254
|
-
* Drop every wrapper AND helper cache wholesale (
|
|
4255
|
-
*
|
|
4694
|
+
* Drop every wrapper AND helper cache wholesale (D-17 + D-02). Called by
|
|
4695
|
+
* every mutation method so subsequent `segments(type)` /
|
|
4256
4696
|
* `allSegments()` / `meta` / `patient` / `visit` reads rebuild from the
|
|
4257
4697
|
* mutated `rawSegments` tree.
|
|
4258
4698
|
* @internal
|
|
@@ -4378,9 +4818,9 @@ function extractVersion(msh) {
|
|
|
4378
4818
|
}
|
|
4379
4819
|
function extractMessageType(msh) {
|
|
4380
4820
|
if (msh === void 0 || msh.name !== "MSH") return { messageCode: "", triggerEvent: "" };
|
|
4381
|
-
const
|
|
4382
|
-
if (
|
|
4383
|
-
const firstRep =
|
|
4821
|
+
const typeField2 = msh.fields[8];
|
|
4822
|
+
if (typeField2 === void 0) return { messageCode: "", triggerEvent: "" };
|
|
4823
|
+
const firstRep = typeField2.repetitions[0];
|
|
4384
4824
|
if (firstRep === void 0) return { messageCode: "", triggerEvent: "" };
|
|
4385
4825
|
const messageCode = firstRep.components[0]?.subcomponents[0] ?? "";
|
|
4386
4826
|
const triggerEvent = firstRep.components[1]?.subcomponents[0] ?? "";
|
|
@@ -4512,6 +4952,24 @@ function parseHL7(raw, optionsOrProfile) {
|
|
|
4512
4952
|
return new Hl7Message(init);
|
|
4513
4953
|
}
|
|
4514
4954
|
|
|
4955
|
+
// src/text/codec.ts
|
|
4956
|
+
function ignore() {
|
|
4957
|
+
}
|
|
4958
|
+
function decodeText(input, enc = DEFAULT_ENCODING_CHARACTERS) {
|
|
4959
|
+
return unescape(input, enc, ignore, { segmentIndex: 0 });
|
|
4960
|
+
}
|
|
4961
|
+
function encodeText(input, enc = DEFAULT_ENCODING_CHARACTERS) {
|
|
4962
|
+
return reescape(input, enc);
|
|
4963
|
+
}
|
|
4964
|
+
|
|
4965
|
+
// src/text/index.ts
|
|
4966
|
+
var text_exports = {};
|
|
4967
|
+
__export(text_exports, {
|
|
4968
|
+
decode: () => decodeText,
|
|
4969
|
+
encode: () => encodeText,
|
|
4970
|
+
render: () => renderText
|
|
4971
|
+
});
|
|
4972
|
+
|
|
4515
4973
|
// src/model/types/namespace.ts
|
|
4516
4974
|
var namespace_exports = {};
|
|
4517
4975
|
var ALNUM_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
@@ -4627,6 +5085,247 @@ function compositeField(typeString) {
|
|
|
4627
5085
|
};
|
|
4628
5086
|
}
|
|
4629
5087
|
|
|
5088
|
+
// src/builder/segment-fields.ts
|
|
5089
|
+
function scalarField2(value) {
|
|
5090
|
+
if (value === void 0 || value === "") return { repetitions: [], isNull: false };
|
|
5091
|
+
return { repetitions: [{ components: [{ subcomponents: [value] }] }], isNull: false };
|
|
5092
|
+
}
|
|
5093
|
+
function absentField2() {
|
|
5094
|
+
return { repetitions: [], isNull: false };
|
|
5095
|
+
}
|
|
5096
|
+
function typeField(typeString) {
|
|
5097
|
+
const components = typeString.split("^").map((p) => ({ subcomponents: [p] }));
|
|
5098
|
+
return { repetitions: [{ components }], isNull: false };
|
|
5099
|
+
}
|
|
5100
|
+
function resolveTimestamp2(ts) {
|
|
5101
|
+
if (ts === void 0) return formatHl7Timestamp(/* @__PURE__ */ new Date());
|
|
5102
|
+
if (typeof ts === "string") return ts;
|
|
5103
|
+
return formatHl7Timestamp(ts);
|
|
5104
|
+
}
|
|
5105
|
+
function buildMshSegment(type, envelope) {
|
|
5106
|
+
const enc = DEFAULT_ENCODING_CHARACTERS;
|
|
5107
|
+
const fields = [
|
|
5108
|
+
scalarField2(enc.field),
|
|
5109
|
+
// fields[0] MSH-1 field separator placeholder
|
|
5110
|
+
scalarField2(
|
|
5111
|
+
enc.component + enc.repetition + enc.escape + enc.subcomponent + (enc.truncation ?? "")
|
|
5112
|
+
),
|
|
5113
|
+
// MSH-2 encoding characters
|
|
5114
|
+
scalarField2(envelope.sendingApp),
|
|
5115
|
+
// MSH-3
|
|
5116
|
+
scalarField2(envelope.sendingFacility),
|
|
5117
|
+
// MSH-4
|
|
5118
|
+
scalarField2(envelope.receivingApp),
|
|
5119
|
+
// MSH-5
|
|
5120
|
+
scalarField2(envelope.receivingFacility),
|
|
5121
|
+
// MSH-6
|
|
5122
|
+
scalarField2(resolveTimestamp2(envelope.timestamp)),
|
|
5123
|
+
// MSH-7
|
|
5124
|
+
absentField2(),
|
|
5125
|
+
// MSH-8
|
|
5126
|
+
typeField(type),
|
|
5127
|
+
// MSH-9
|
|
5128
|
+
scalarField2(envelope.controlId ?? generateControlId()),
|
|
5129
|
+
// MSH-10
|
|
5130
|
+
scalarField2(envelope.processingId ?? "P"),
|
|
5131
|
+
// MSH-11
|
|
5132
|
+
scalarField2(envelope.version ?? "2.5")
|
|
5133
|
+
// MSH-12
|
|
5134
|
+
];
|
|
5135
|
+
return { name: "MSH", fields };
|
|
5136
|
+
}
|
|
5137
|
+
function assembleSegment(name, positions) {
|
|
5138
|
+
let max = 0;
|
|
5139
|
+
for (const [pos, field] of positions) {
|
|
5140
|
+
if (field !== void 0 && pos > max) max = pos;
|
|
5141
|
+
}
|
|
5142
|
+
const fields = [absentField2()];
|
|
5143
|
+
for (let i = 1; i <= max; i++) {
|
|
5144
|
+
fields.push(positions.get(i) ?? absentField2());
|
|
5145
|
+
}
|
|
5146
|
+
return { name, fields };
|
|
5147
|
+
}
|
|
5148
|
+
|
|
5149
|
+
// src/builder/build-adt.ts
|
|
5150
|
+
function repField(kind, value) {
|
|
5151
|
+
if (value === void 0) return { repetitions: [], isNull: false };
|
|
5152
|
+
if (Array.isArray(value)) {
|
|
5153
|
+
return encodeCompositeReps(kind, value);
|
|
5154
|
+
}
|
|
5155
|
+
return encodeComposite(kind, value);
|
|
5156
|
+
}
|
|
5157
|
+
function buildAdt(event, init) {
|
|
5158
|
+
if (typeof event !== "string" || event.trim().length === 0) {
|
|
5159
|
+
throw new TypeError(
|
|
5160
|
+
`buildAdt: \`event\` (the ADT trigger, e.g. "A01") is required and must be a non-empty string. Received: ${JSON.stringify(event)}.`
|
|
5161
|
+
);
|
|
5162
|
+
}
|
|
5163
|
+
if (init === null || init === void 0 || init.patient === void 0) {
|
|
5164
|
+
throw new TypeError(
|
|
5165
|
+
"buildAdt: `patient` is required. An ADT patient event is never emitted with a fabricated patient. Supply at least one identifier or a name."
|
|
5166
|
+
);
|
|
5167
|
+
}
|
|
5168
|
+
const enc = DEFAULT_ENCODING_CHARACTERS;
|
|
5169
|
+
const version = init.version ?? "2.5";
|
|
5170
|
+
const segments = [buildMshSegment(`ADT^${event}`, init)];
|
|
5171
|
+
const evn = init.event;
|
|
5172
|
+
segments.push(
|
|
5173
|
+
assembleSegment(
|
|
5174
|
+
"EVN",
|
|
5175
|
+
/* @__PURE__ */ new Map([
|
|
5176
|
+
[1, scalarField2(event)],
|
|
5177
|
+
[
|
|
5178
|
+
2,
|
|
5179
|
+
evn?.recordedDateTime !== void 0 ? encodeComposite("TS", evn.recordedDateTime) : void 0
|
|
5180
|
+
],
|
|
5181
|
+
[
|
|
5182
|
+
6,
|
|
5183
|
+
evn?.eventOccurred !== void 0 ? encodeComposite("TS", evn.eventOccurred) : void 0
|
|
5184
|
+
]
|
|
5185
|
+
])
|
|
5186
|
+
)
|
|
5187
|
+
);
|
|
5188
|
+
const p = init.patient;
|
|
5189
|
+
segments.push(
|
|
5190
|
+
assembleSegment(
|
|
5191
|
+
"PID",
|
|
5192
|
+
/* @__PURE__ */ new Map([
|
|
5193
|
+
[1, p.setId !== void 0 ? scalarField2(p.setId) : void 0],
|
|
5194
|
+
[3, p.identifiers !== void 0 ? repField("CX", p.identifiers) : void 0],
|
|
5195
|
+
[5, p.name !== void 0 ? repField("XPN", p.name) : void 0],
|
|
5196
|
+
[
|
|
5197
|
+
6,
|
|
5198
|
+
p.mothersMaidenName !== void 0 ? encodeComposite("XPN", p.mothersMaidenName) : void 0
|
|
5199
|
+
],
|
|
5200
|
+
[7, p.birthDateTime !== void 0 ? encodeComposite("TS", p.birthDateTime) : void 0],
|
|
5201
|
+
[8, p.administrativeSex !== void 0 ? scalarField2(p.administrativeSex) : void 0],
|
|
5202
|
+
[11, p.address !== void 0 ? repField("XAD", p.address) : void 0],
|
|
5203
|
+
[13, p.phoneHome !== void 0 ? repField("XTN", p.phoneHome) : void 0],
|
|
5204
|
+
[18, p.accountNumber !== void 0 ? encodeComposite("CX", p.accountNumber) : void 0]
|
|
5205
|
+
])
|
|
5206
|
+
)
|
|
5207
|
+
);
|
|
5208
|
+
const v = init.visit;
|
|
5209
|
+
segments.push(
|
|
5210
|
+
assembleSegment(
|
|
5211
|
+
"PV1",
|
|
5212
|
+
/* @__PURE__ */ new Map([
|
|
5213
|
+
[1, v?.setId !== void 0 ? scalarField2(v.setId) : void 0],
|
|
5214
|
+
[2, v?.patientClass !== void 0 ? scalarField2(v.patientClass) : void 0],
|
|
5215
|
+
[
|
|
5216
|
+
3,
|
|
5217
|
+
v?.assignedLocation !== void 0 ? encodeComposite("PL", v.assignedLocation) : void 0
|
|
5218
|
+
],
|
|
5219
|
+
[7, v?.attendingDoctor !== void 0 ? repField("XCN", v.attendingDoctor) : void 0],
|
|
5220
|
+
[8, v?.referringDoctor !== void 0 ? repField("XCN", v.referringDoctor) : void 0],
|
|
5221
|
+
[19, v?.visitNumber !== void 0 ? encodeComposite("CX", v.visitNumber) : void 0],
|
|
5222
|
+
[44, v?.admitDateTime !== void 0 ? encodeComposite("TS", v.admitDateTime) : void 0]
|
|
5223
|
+
])
|
|
5224
|
+
)
|
|
5225
|
+
);
|
|
5226
|
+
return new Hl7Message({
|
|
5227
|
+
segments,
|
|
5228
|
+
encodingCharacters: enc,
|
|
5229
|
+
version,
|
|
5230
|
+
warnings: []
|
|
5231
|
+
});
|
|
5232
|
+
}
|
|
5233
|
+
|
|
5234
|
+
// src/builder/build-oru.ts
|
|
5235
|
+
function repField2(kind, value) {
|
|
5236
|
+
if (value === void 0) return { repetitions: [], isNull: false };
|
|
5237
|
+
if (Array.isArray(value)) {
|
|
5238
|
+
return encodeCompositeReps(kind, value);
|
|
5239
|
+
}
|
|
5240
|
+
return encodeComposite(kind, value);
|
|
5241
|
+
}
|
|
5242
|
+
function buildOru(init) {
|
|
5243
|
+
if (init === null || init === void 0 || init.patient === void 0) {
|
|
5244
|
+
throw new TypeError(
|
|
5245
|
+
"buildOru: `patient` is required. An ORU is never emitted with a fabricated subject."
|
|
5246
|
+
);
|
|
5247
|
+
}
|
|
5248
|
+
if (init.observations === void 0 || init.observations.length === 0) {
|
|
5249
|
+
throw new TypeError(
|
|
5250
|
+
"buildOru: at least one `observations` entry (OBX) is required. An ORU with no result is a typed error, never a fabricated observation."
|
|
5251
|
+
);
|
|
5252
|
+
}
|
|
5253
|
+
const enc = DEFAULT_ENCODING_CHARACTERS;
|
|
5254
|
+
const version = init.version ?? "2.5";
|
|
5255
|
+
const segments = [buildMshSegment("ORU^R01", init)];
|
|
5256
|
+
const p = init.patient;
|
|
5257
|
+
segments.push(
|
|
5258
|
+
assembleSegment(
|
|
5259
|
+
"PID",
|
|
5260
|
+
/* @__PURE__ */ new Map([
|
|
5261
|
+
[1, p.setId !== void 0 ? scalarField2(p.setId) : void 0],
|
|
5262
|
+
[3, p.identifiers !== void 0 ? repField2("CX", p.identifiers) : void 0],
|
|
5263
|
+
[5, p.name !== void 0 ? repField2("XPN", p.name) : void 0],
|
|
5264
|
+
[
|
|
5265
|
+
6,
|
|
5266
|
+
p.mothersMaidenName !== void 0 ? encodeComposite("XPN", p.mothersMaidenName) : void 0
|
|
5267
|
+
],
|
|
5268
|
+
[7, p.birthDateTime !== void 0 ? encodeComposite("TS", p.birthDateTime) : void 0],
|
|
5269
|
+
[8, p.administrativeSex !== void 0 ? scalarField2(p.administrativeSex) : void 0],
|
|
5270
|
+
[11, p.address !== void 0 ? repField2("XAD", p.address) : void 0],
|
|
5271
|
+
[13, p.phoneHome !== void 0 ? repField2("XTN", p.phoneHome) : void 0],
|
|
5272
|
+
[18, p.accountNumber !== void 0 ? encodeComposite("CX", p.accountNumber) : void 0]
|
|
5273
|
+
])
|
|
5274
|
+
)
|
|
5275
|
+
);
|
|
5276
|
+
const o = init.order;
|
|
5277
|
+
segments.push(
|
|
5278
|
+
assembleSegment(
|
|
5279
|
+
"OBR",
|
|
5280
|
+
/* @__PURE__ */ new Map([
|
|
5281
|
+
[1, o?.setId !== void 0 ? scalarField2(o.setId) : void 0],
|
|
5282
|
+
[2, o?.placerOrderNumber !== void 0 ? scalarField2(o.placerOrderNumber) : void 0],
|
|
5283
|
+
[3, o?.fillerOrderNumber !== void 0 ? scalarField2(o.fillerOrderNumber) : void 0],
|
|
5284
|
+
[
|
|
5285
|
+
4,
|
|
5286
|
+
o?.universalServiceId !== void 0 ? encodeComposite("CWE", o.universalServiceId) : void 0
|
|
5287
|
+
],
|
|
5288
|
+
[
|
|
5289
|
+
7,
|
|
5290
|
+
o?.observationDateTime !== void 0 ? encodeComposite("TS", o.observationDateTime) : void 0
|
|
5291
|
+
],
|
|
5292
|
+
[16, o?.orderingProvider !== void 0 ? repField2("XCN", o.orderingProvider) : void 0],
|
|
5293
|
+
[25, o?.resultStatus !== void 0 ? scalarField2(o.resultStatus) : void 0]
|
|
5294
|
+
])
|
|
5295
|
+
)
|
|
5296
|
+
);
|
|
5297
|
+
for (const obs of init.observations) {
|
|
5298
|
+
segments.push(
|
|
5299
|
+
assembleSegment(
|
|
5300
|
+
"OBX",
|
|
5301
|
+
/* @__PURE__ */ new Map([
|
|
5302
|
+
[1, obs.setId !== void 0 ? scalarField2(obs.setId) : void 0],
|
|
5303
|
+
[2, obs.valueType !== void 0 ? scalarField2(obs.valueType) : void 0],
|
|
5304
|
+
[3, obs.identifier !== void 0 ? encodeComposite("CWE", obs.identifier) : void 0],
|
|
5305
|
+
[5, obs.value !== void 0 ? scalarField2(obs.value) : void 0],
|
|
5306
|
+
[6, obs.units !== void 0 ? encodeComposite("CWE", obs.units) : void 0],
|
|
5307
|
+
[7, obs.referenceRange !== void 0 ? scalarField2(obs.referenceRange) : void 0],
|
|
5308
|
+
[8, obs.abnormalFlags !== void 0 ? scalarField2(obs.abnormalFlags) : void 0],
|
|
5309
|
+
[
|
|
5310
|
+
11,
|
|
5311
|
+
obs.observationResultStatus !== void 0 ? scalarField2(obs.observationResultStatus) : void 0
|
|
5312
|
+
],
|
|
5313
|
+
[
|
|
5314
|
+
14,
|
|
5315
|
+
obs.observationDateTime !== void 0 ? encodeComposite("TS", obs.observationDateTime) : void 0
|
|
5316
|
+
]
|
|
5317
|
+
])
|
|
5318
|
+
)
|
|
5319
|
+
);
|
|
5320
|
+
}
|
|
5321
|
+
return new Hl7Message({
|
|
5322
|
+
segments,
|
|
5323
|
+
encodingCharacters: enc,
|
|
5324
|
+
version,
|
|
5325
|
+
warnings: []
|
|
5326
|
+
});
|
|
5327
|
+
}
|
|
5328
|
+
|
|
4630
5329
|
// src/builder/ack-tables.ts
|
|
4631
5330
|
var ACK_CODES = {
|
|
4632
5331
|
AA: "AA",
|
|
@@ -4709,7 +5408,7 @@ function buildAck(inbound, options) {
|
|
|
4709
5408
|
const enc = DEFAULT_ENCODING_CHARACTERS;
|
|
4710
5409
|
const meta = inbound.meta;
|
|
4711
5410
|
const msh = inbound.segments("MSH")[0];
|
|
4712
|
-
const inboundMsh = (n) => msh?.field(n).raw ??
|
|
5411
|
+
const inboundMsh = (n) => msh?.field(n).raw ?? absentField3();
|
|
4713
5412
|
const sameEnc = encodingsEqual(inbound.encodingCharacters, enc);
|
|
4714
5413
|
const rawControlId = sameEnc ? inboundMsh(10) : stripEscapeOverlay(inboundMsh(10));
|
|
4715
5414
|
const hasCorrelation = rawFieldHasContent(rawControlId);
|
|
@@ -4718,8 +5417,8 @@ function buildAck(inbound, options) {
|
|
|
4718
5417
|
const version = meta.version ?? "2.5";
|
|
4719
5418
|
const processingId = meta.processingId ?? "P";
|
|
4720
5419
|
const mshFields = [
|
|
4721
|
-
|
|
4722
|
-
|
|
5420
|
+
scalarField3(enc.field),
|
|
5421
|
+
scalarField3(
|
|
4723
5422
|
enc.component + enc.repetition + enc.escape + enc.subcomponent + (enc.truncation ?? "")
|
|
4724
5423
|
),
|
|
4725
5424
|
inboundMsh(5),
|
|
@@ -4730,26 +5429,26 @@ function buildAck(inbound, options) {
|
|
|
4730
5429
|
// MSH-5 receivingApp = inbound MSH-3 (sendingApp)
|
|
4731
5430
|
inboundMsh(4),
|
|
4732
5431
|
// MSH-6 receivingFacility = inbound MSH-4 (sendingFacility)
|
|
4733
|
-
|
|
5432
|
+
scalarField3(formatHl7Timestamp(/* @__PURE__ */ new Date())),
|
|
4734
5433
|
// MSH-7
|
|
4735
|
-
|
|
5434
|
+
absentField3(),
|
|
4736
5435
|
// MSH-8
|
|
4737
5436
|
compositeField2(ackType),
|
|
4738
5437
|
// MSH-9
|
|
4739
|
-
|
|
5438
|
+
scalarField3(generateControlId()),
|
|
4740
5439
|
// MSH-10
|
|
4741
|
-
|
|
5440
|
+
scalarField3(processingId),
|
|
4742
5441
|
// MSH-11
|
|
4743
|
-
|
|
5442
|
+
scalarField3(version)
|
|
4744
5443
|
// MSH-12
|
|
4745
5444
|
];
|
|
4746
5445
|
const segments = [{ name: "MSH", fields: mshFields }];
|
|
4747
5446
|
segments.push({
|
|
4748
5447
|
name: "MSA",
|
|
4749
5448
|
fields: [
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
hasCorrelation ? rawControlId :
|
|
5449
|
+
absentField3(),
|
|
5450
|
+
scalarField3(emittedCode),
|
|
5451
|
+
hasCorrelation ? rawControlId : absentField3()
|
|
4753
5452
|
]
|
|
4754
5453
|
});
|
|
4755
5454
|
for (const detail of normalizeErrors(options.error)) {
|
|
@@ -4789,24 +5488,24 @@ function buildErrSegment(detail) {
|
|
|
4789
5488
|
return {
|
|
4790
5489
|
name: "ERR",
|
|
4791
5490
|
fields: [
|
|
4792
|
-
|
|
4793
|
-
// fields[0]
|
|
4794
|
-
|
|
5491
|
+
absentField3(),
|
|
5492
|
+
// fields[0]: segment-name/separator placeholder slot
|
|
5493
|
+
absentField3(),
|
|
4795
5494
|
// ERR-1 (deprecated v2.4 / withdrawn v2.7)
|
|
4796
|
-
detail.location !== void 0 ? compositeField2(detail.location) :
|
|
5495
|
+
detail.location !== void 0 ? compositeField2(detail.location) : absentField3(),
|
|
4797
5496
|
// ERR-2 (ERL)
|
|
4798
5497
|
err3,
|
|
4799
5498
|
// ERR-3
|
|
4800
|
-
|
|
5499
|
+
scalarField3(severity)
|
|
4801
5500
|
// ERR-4
|
|
4802
5501
|
]
|
|
4803
5502
|
};
|
|
4804
5503
|
}
|
|
4805
|
-
function
|
|
5504
|
+
function scalarField3(value) {
|
|
4806
5505
|
if (value === "") return { repetitions: [], isNull: false };
|
|
4807
5506
|
return { repetitions: [{ components: [{ subcomponents: [value] }] }], isNull: false };
|
|
4808
5507
|
}
|
|
4809
|
-
function
|
|
5508
|
+
function absentField3() {
|
|
4810
5509
|
return { repetitions: [], isNull: false };
|
|
4811
5510
|
}
|
|
4812
5511
|
function encodingsEqual(a, b) {
|
|
@@ -5066,7 +5765,7 @@ function validateCustomSegments(map, profileName) {
|
|
|
5066
5765
|
for (const key of Object.keys(map)) {
|
|
5067
5766
|
if (!Z_SEGMENT_RE.test(key)) {
|
|
5068
5767
|
throw new ProfileDefinitionError(
|
|
5069
|
-
`Profile '${profileName}' declares customSegments for '${key}'
|
|
5768
|
+
`Profile '${profileName}' declares customSegments for '${key}': only Z-segments (Z[A-Z0-9]{2}) are allowed in v1. Typed overlays are a v2 feature.`,
|
|
5070
5769
|
profileName
|
|
5071
5770
|
);
|
|
5072
5771
|
}
|
|
@@ -5093,7 +5792,7 @@ function validateDateFormats(formats, profileName) {
|
|
|
5093
5792
|
const f = formats[i] ?? "";
|
|
5094
5793
|
if (!TOKEN_MATCH_RE.test(f)) {
|
|
5095
5794
|
throw new ProfileDefinitionError(
|
|
5096
|
-
`Profile '${profileName}' dateFormats[${String(i)}] = ${JSON.stringify(f)} is malformed
|
|
5795
|
+
`Profile '${profileName}' dateFormats[${String(i)}] = ${JSON.stringify(f)} is malformed: must contain at least one of ${SUPPORTED_DATE_TOKENS.join("/")}.`,
|
|
5097
5796
|
profileName
|
|
5098
5797
|
);
|
|
5099
5798
|
}
|
|
@@ -5151,7 +5850,7 @@ function defineProfile(opts) {
|
|
|
5151
5850
|
// src/profiles/athena.ts
|
|
5152
5851
|
var athena = defineProfile({
|
|
5153
5852
|
name: "athena",
|
|
5154
|
-
description: "athenahealth Interop
|
|
5853
|
+
description: "athenahealth Interop: US-short-date format and care-team Z-segment",
|
|
5155
5854
|
dateFormats: ["MM/DD/YYYY"],
|
|
5156
5855
|
customSegments: {
|
|
5157
5856
|
ZCA: { fields: { careTeamRole: 3, providerId: 5, providerName: 6 } }
|
|
@@ -5161,7 +5860,7 @@ var athena = defineProfile({
|
|
|
5161
5860
|
// src/profiles/cerner.ts
|
|
5162
5861
|
var cerner = defineProfile({
|
|
5163
5862
|
name: "cerner",
|
|
5164
|
-
description: "Cerner Millennium
|
|
5863
|
+
description: "Cerner Millennium: ISO-style timestamps and common Z-segments",
|
|
5165
5864
|
dateFormats: ["YYYY-MM-DDTHH:mm:ss", "YYYY-MM-DD"],
|
|
5166
5865
|
customSegments: {
|
|
5167
5866
|
ZDS: { fields: { summaryText: 3 } },
|
|
@@ -5172,7 +5871,7 @@ var cerner = defineProfile({
|
|
|
5172
5871
|
// src/profiles/epic.ts
|
|
5173
5872
|
var epic = defineProfile({
|
|
5174
5873
|
name: "epic",
|
|
5175
|
-
description: "Epic Bridges Interconnect
|
|
5874
|
+
description: "Epic Bridges Interconnect: ADT-style date formats and common Z-segments",
|
|
5176
5875
|
dateFormats: ["MM/DD/YYYY HH:mm:ss", "MM/DD/YYYY"],
|
|
5177
5876
|
customSegments: {
|
|
5178
5877
|
ZDP: { fields: { departmentCode: 3, departmentName: 4 } },
|
|
@@ -5183,7 +5882,7 @@ var epic = defineProfile({
|
|
|
5183
5882
|
// src/profiles/genericLab.ts
|
|
5184
5883
|
var genericLab = defineProfile({
|
|
5185
5884
|
name: "genericLab",
|
|
5186
|
-
description: "Generic reference-laboratory
|
|
5885
|
+
description: "Generic reference-laboratory: ASTM-era + ISO-date formats + lab Z-segments",
|
|
5187
5886
|
dateFormats: ["YYYYMMDD HHmm", "YYYY-MM-DD"],
|
|
5188
5887
|
customSegments: {
|
|
5189
5888
|
ZLB: { fields: { specimenOverride: 3, methodOverride: 5 } },
|
|
@@ -5194,10 +5893,122 @@ var genericLab = defineProfile({
|
|
|
5194
5893
|
// src/profiles/meditech.ts
|
|
5195
5894
|
var meditech = defineProfile({
|
|
5196
5895
|
name: "meditech",
|
|
5197
|
-
description: "
|
|
5896
|
+
description: "MEDITECH MAGIC/6.x/Expanse: minute-precision timestamps and DFT charge Z-segments (ZF1/ZF2)",
|
|
5198
5897
|
dateFormats: ["YYYYMMDDHHmm"],
|
|
5199
5898
|
customSegments: {
|
|
5200
|
-
|
|
5899
|
+
ZF1: {
|
|
5900
|
+
fields: {
|
|
5901
|
+
providerEncounter: 1,
|
|
5902
|
+
misServiceGroup: 2,
|
|
5903
|
+
serviceGroupCopay: 3,
|
|
5904
|
+
visitCopay: 4,
|
|
5905
|
+
copayMinimum: 5,
|
|
5906
|
+
copayMaximum: 6
|
|
5907
|
+
}
|
|
5908
|
+
},
|
|
5909
|
+
ZF2: {
|
|
5910
|
+
fields: {
|
|
5911
|
+
setId: 1,
|
|
5912
|
+
providerEncounter: 2,
|
|
5913
|
+
encounterDate: 3,
|
|
5914
|
+
encounterProcedure: 4,
|
|
5915
|
+
encounterProcedureQuantity: 5,
|
|
5916
|
+
encounterProcedureCharge: 6,
|
|
5917
|
+
prvProcedureAmountPaid: 7,
|
|
5918
|
+
prvProcedureAmountDue: 8
|
|
5919
|
+
}
|
|
5920
|
+
}
|
|
5921
|
+
}
|
|
5922
|
+
});
|
|
5923
|
+
|
|
5924
|
+
// src/profiles/philips.ts
|
|
5925
|
+
var philips = defineProfile({
|
|
5926
|
+
name: "philips",
|
|
5927
|
+
description: "Philips Vue PACS (IS Link) imaging: ZDS/ZLK/ZAO/ZEB/ZAP/ZAV order/patient/visit-filler Z-segments",
|
|
5928
|
+
customSegments: {
|
|
5929
|
+
// §5.11 ZDS: Order Filler: DICOM Study Instance UID (RP, comp 1).
|
|
5930
|
+
ZDS: { fields: { studyInstanceUid: 1 } },
|
|
5931
|
+
// §5.12 ZLK: Order Filler: study/order linking ids.
|
|
5932
|
+
ZLK: { fields: { externalWorkitemId: 1, orderLinkId: 2 } },
|
|
5933
|
+
// §5.13 ZAO: Order Filler: order additional details (note: no field 7).
|
|
5934
|
+
ZAO: {
|
|
5935
|
+
fields: {
|
|
5936
|
+
orderAdditionalDetails: 1,
|
|
5937
|
+
orderWithNoImages: 2,
|
|
5938
|
+
modality: 3,
|
|
5939
|
+
bodyPart: 4,
|
|
5940
|
+
resultTransferStatus: 5,
|
|
5941
|
+
departmentId: 6,
|
|
5942
|
+
device: 8,
|
|
5943
|
+
section: 9,
|
|
5944
|
+
orderCustomString1: 10,
|
|
5945
|
+
orderCustomString2: 11,
|
|
5946
|
+
orderCustomString3: 12,
|
|
5947
|
+
orderCustomString4: 13,
|
|
5948
|
+
orderCustomString5: 14,
|
|
5949
|
+
orderCustomString6: 15,
|
|
5950
|
+
orderCustomString7: 16,
|
|
5951
|
+
orderCustomNumber1: 17,
|
|
5952
|
+
orderCustomNumber2: 18,
|
|
5953
|
+
orderCustomDate1: 19,
|
|
5954
|
+
orderCustomDate2: 20,
|
|
5955
|
+
orderCustomDate3: 21,
|
|
5956
|
+
technicianFamilyName: 22,
|
|
5957
|
+
technicianGivenName: 23,
|
|
5958
|
+
technicianMiddleName: 24,
|
|
5959
|
+
technicianId: 25,
|
|
5960
|
+
radiologistFamilyName: 26,
|
|
5961
|
+
radiologistGivenName: 27,
|
|
5962
|
+
radiologistMiddleName: 28,
|
|
5963
|
+
radiologistId: 29,
|
|
5964
|
+
orderCreatedBy: 30,
|
|
5965
|
+
orderUpdatedBy: 31,
|
|
5966
|
+
acquisitionStatus: 32
|
|
5967
|
+
}
|
|
5968
|
+
},
|
|
5969
|
+
// §5.14 ZEB: Patient Filler: encrypted patient-info blob (PHI-bearing).
|
|
5970
|
+
ZEB: { fields: { encryptedPatientInfo: 1 } },
|
|
5971
|
+
// §5.15 ZAP: Patient Filler: patient additional details (note: no field 2).
|
|
5972
|
+
ZAP: {
|
|
5973
|
+
fields: {
|
|
5974
|
+
patientAdditionalDetails: 1,
|
|
5975
|
+
patientCustomString1: 3,
|
|
5976
|
+
patientCustomString2: 4,
|
|
5977
|
+
patientCustomString3: 5,
|
|
5978
|
+
patientCustomString4: 6,
|
|
5979
|
+
patientCustomString5: 7,
|
|
5980
|
+
patientCustomString6: 8,
|
|
5981
|
+
patientCustomString7: 9,
|
|
5982
|
+
patientCustomNumber1: 10,
|
|
5983
|
+
patientCustomNumber2: 11,
|
|
5984
|
+
patientCustomDate1: 12,
|
|
5985
|
+
patientCustomDate2: 13,
|
|
5986
|
+
patientCustomDate3: 14
|
|
5987
|
+
}
|
|
5988
|
+
},
|
|
5989
|
+
// §5.16 ZAV: Visit Filler: visit additional details.
|
|
5990
|
+
ZAV: { fields: { visitAdditionalDetails: 1 } }
|
|
5991
|
+
}
|
|
5992
|
+
});
|
|
5993
|
+
|
|
5994
|
+
// src/profiles/va.ts
|
|
5995
|
+
var va = defineProfile({
|
|
5996
|
+
name: "va",
|
|
5997
|
+
description: "VA VistA Radiology/Nuclear Medicine imaging: ZDS DICOM Study Instance UID segment (ORM + ORU, IHE RAD)",
|
|
5998
|
+
customSegments: {
|
|
5999
|
+
// ZDS-1 = Study Instance UID (RP), UID in the first component (1.1 Pointer).
|
|
6000
|
+
// VA Radiology/Nuclear Medicine 5.0 HL7 IS v3.6 (June 2024): "ZDS Segment
|
|
6001
|
+
// Fields in ORU and ORM".
|
|
6002
|
+
ZDS: { fields: { studyInstanceUid: 1 } }
|
|
6003
|
+
}
|
|
6004
|
+
});
|
|
6005
|
+
|
|
6006
|
+
// src/profiles/visage.ts
|
|
6007
|
+
var visage = defineProfile({
|
|
6008
|
+
name: "visage",
|
|
6009
|
+
description: "Visage 7 imaging/PACS: ZDS DICOM Study Instance UID segment (IHE RAD)",
|
|
6010
|
+
customSegments: {
|
|
6011
|
+
ZDS: { fields: { studyInstanceUid: 1 } }
|
|
5201
6012
|
}
|
|
5202
6013
|
});
|
|
5203
6014
|
|
|
@@ -5207,7 +6018,10 @@ var profiles = Object.freeze({
|
|
|
5207
6018
|
cerner,
|
|
5208
6019
|
epic,
|
|
5209
6020
|
genericLab,
|
|
5210
|
-
meditech
|
|
6021
|
+
meditech,
|
|
6022
|
+
philips,
|
|
6023
|
+
va,
|
|
6024
|
+
visage
|
|
5211
6025
|
});
|
|
5212
6026
|
|
|
5213
6027
|
// src/model/coding-system.ts
|
|
@@ -5439,9 +6253,561 @@ function splitBatch(raw, optionsOrProfile) {
|
|
|
5439
6253
|
return Object.freeze(result);
|
|
5440
6254
|
}
|
|
5441
6255
|
|
|
6256
|
+
// src/conformance/types.ts
|
|
6257
|
+
var USAGE_CODES = Object.freeze(["R", "RE", "C", "CE", "O", "X"]);
|
|
6258
|
+
var FINDING_CODES = {
|
|
6259
|
+
/** A Required (`R`) segment or field is absent (or present-but-empty). */
|
|
6260
|
+
PROFILE_REQUIRED_ABSENT: "PROFILE_REQUIRED_ABSENT",
|
|
6261
|
+
/** A Not-permitted (`X`) segment or field is present. */
|
|
6262
|
+
PROFILE_NOT_PERMITTED: "PROFILE_NOT_PERMITTED",
|
|
6263
|
+
/** A segment-occurrence or field-repetition count is outside its cardinality. */
|
|
6264
|
+
PROFILE_CARDINALITY: "PROFILE_CARDINALITY",
|
|
6265
|
+
/** A checked component value exceeds the declared maximum length. */
|
|
6266
|
+
PROFILE_LENGTH: "PROFILE_LENGTH",
|
|
6267
|
+
/** A checked component value is not a member of the consumer-supplied value set. */
|
|
6268
|
+
PROFILE_VALUE_NOT_IN_SET: "PROFILE_VALUE_NOT_IN_SET",
|
|
6269
|
+
/** The profile ITSELF is structurally malformed (a diagnostic, not a message finding). */
|
|
6270
|
+
PROFILE_MALFORMED: "PROFILE_MALFORMED"
|
|
6271
|
+
};
|
|
6272
|
+
|
|
6273
|
+
// src/conformance/findings.ts
|
|
6274
|
+
function describeLocus(locus) {
|
|
6275
|
+
let s = locus.segment;
|
|
6276
|
+
if (locus.occurrence !== void 0 && locus.occurrence > 0) {
|
|
6277
|
+
s += `[occurrence ${String(locus.occurrence)}]`;
|
|
6278
|
+
}
|
|
6279
|
+
if (locus.field !== void 0) {
|
|
6280
|
+
s += `-${String(locus.field)}`;
|
|
6281
|
+
}
|
|
6282
|
+
if (locus.repetition !== void 0) {
|
|
6283
|
+
s += ` rep ${String(locus.repetition)}`;
|
|
6284
|
+
}
|
|
6285
|
+
if (locus.component !== void 0) {
|
|
6286
|
+
s += ` component ${String(locus.component)}`;
|
|
6287
|
+
}
|
|
6288
|
+
return s;
|
|
6289
|
+
}
|
|
6290
|
+
function requiredAbsent(locus, severity) {
|
|
6291
|
+
const kind = locus.field === void 0 ? "segment" : "field";
|
|
6292
|
+
return {
|
|
6293
|
+
code: FINDING_CODES.PROFILE_REQUIRED_ABSENT,
|
|
6294
|
+
severity,
|
|
6295
|
+
locus,
|
|
6296
|
+
message: `Required ${kind} ${describeLocus(locus)} is absent or empty (usage R).`
|
|
6297
|
+
};
|
|
6298
|
+
}
|
|
6299
|
+
function notPermitted(locus, severity) {
|
|
6300
|
+
const kind = locus.field === void 0 ? "segment" : "field";
|
|
6301
|
+
return {
|
|
6302
|
+
code: FINDING_CODES.PROFILE_NOT_PERMITTED,
|
|
6303
|
+
severity,
|
|
6304
|
+
locus,
|
|
6305
|
+
message: `${kind === "segment" ? "Segment" : "Field"} ${describeLocus(
|
|
6306
|
+
locus
|
|
6307
|
+
)} is present but the profile marks it not-permitted (usage X).`
|
|
6308
|
+
};
|
|
6309
|
+
}
|
|
6310
|
+
function cardinality(locus, actual, bound, unit, severity) {
|
|
6311
|
+
const parts = [];
|
|
6312
|
+
if (bound.min !== void 0) parts.push(`min ${String(bound.min)}`);
|
|
6313
|
+
if (bound.max !== void 0) parts.push(`max ${String(bound.max)}`);
|
|
6314
|
+
return {
|
|
6315
|
+
code: FINDING_CODES.PROFILE_CARDINALITY,
|
|
6316
|
+
severity,
|
|
6317
|
+
locus,
|
|
6318
|
+
message: `${describeLocus(locus)} has ${String(actual)} ${unit}(s), outside the declared cardinality (${parts.join(
|
|
6319
|
+
", "
|
|
6320
|
+
)}).`
|
|
6321
|
+
};
|
|
6322
|
+
}
|
|
6323
|
+
function length(locus, actualLength, maxLength, severity) {
|
|
6324
|
+
return {
|
|
6325
|
+
code: FINDING_CODES.PROFILE_LENGTH,
|
|
6326
|
+
severity,
|
|
6327
|
+
locus,
|
|
6328
|
+
message: `${describeLocus(locus)} value length ${String(
|
|
6329
|
+
actualLength
|
|
6330
|
+
)} exceeds the declared maximum of ${String(maxLength)}.`
|
|
6331
|
+
};
|
|
6332
|
+
}
|
|
6333
|
+
function valueNotInSet(locus, valueSetSize, severity) {
|
|
6334
|
+
return {
|
|
6335
|
+
code: FINDING_CODES.PROFILE_VALUE_NOT_IN_SET,
|
|
6336
|
+
severity,
|
|
6337
|
+
locus,
|
|
6338
|
+
message: `${describeLocus(
|
|
6339
|
+
locus
|
|
6340
|
+
)} value is not in the profile value set (${String(valueSetSize)} permitted code(s)).`
|
|
6341
|
+
};
|
|
6342
|
+
}
|
|
6343
|
+
function malformed(locus, detail) {
|
|
6344
|
+
return {
|
|
6345
|
+
code: FINDING_CODES.PROFILE_MALFORMED,
|
|
6346
|
+
severity: "error",
|
|
6347
|
+
locus,
|
|
6348
|
+
message: `Malformed conformance profile: ${detail}`
|
|
6349
|
+
};
|
|
6350
|
+
}
|
|
6351
|
+
|
|
6352
|
+
// src/conformance/profile-shape.ts
|
|
6353
|
+
var SEGMENT_NAME_RE3 = /^[A-Z][A-Z0-9]{2}$/u;
|
|
6354
|
+
var SEVERITIES = ["error", "warning", "info"];
|
|
6355
|
+
function isObject(v) {
|
|
6356
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
6357
|
+
}
|
|
6358
|
+
function checkCardinality(card, locus, out) {
|
|
6359
|
+
if (card === void 0) return;
|
|
6360
|
+
if (!isObject(card)) {
|
|
6361
|
+
out.push({ locus, detail: `${describe(locus)} cardinality must be an object.` });
|
|
6362
|
+
return;
|
|
6363
|
+
}
|
|
6364
|
+
const min = card["min"];
|
|
6365
|
+
const max = card["max"];
|
|
6366
|
+
if (min !== void 0 && (typeof min !== "number" || !Number.isInteger(min) || min < 0)) {
|
|
6367
|
+
out.push({
|
|
6368
|
+
locus,
|
|
6369
|
+
detail: `${describe(locus)} cardinality.min must be a non-negative integer.`
|
|
6370
|
+
});
|
|
6371
|
+
}
|
|
6372
|
+
if (max !== void 0 && max !== "*" && (typeof max !== "number" || !Number.isInteger(max) || max < 0)) {
|
|
6373
|
+
out.push({
|
|
6374
|
+
locus,
|
|
6375
|
+
detail: `${describe(locus)} cardinality.max must be a non-negative integer or "*".`
|
|
6376
|
+
});
|
|
6377
|
+
}
|
|
6378
|
+
if (typeof min === "number" && typeof max === "number" && Number.isInteger(min) && Number.isInteger(max) && max < min) {
|
|
6379
|
+
out.push({
|
|
6380
|
+
locus,
|
|
6381
|
+
detail: `${describe(locus)} cardinality.max (${String(max)}) is less than min (${String(min)}).`
|
|
6382
|
+
});
|
|
6383
|
+
}
|
|
6384
|
+
}
|
|
6385
|
+
function describe(locus) {
|
|
6386
|
+
if (locus.segment === "(profile)") return "profile";
|
|
6387
|
+
let s = `segment "${locus.segment}"`;
|
|
6388
|
+
if (locus.field !== void 0) s += ` field ${String(locus.field)}`;
|
|
6389
|
+
return s;
|
|
6390
|
+
}
|
|
6391
|
+
function collectProfileDefects(profile) {
|
|
6392
|
+
const out = [];
|
|
6393
|
+
const root = { segment: "(profile)" };
|
|
6394
|
+
if (!isObject(profile)) {
|
|
6395
|
+
out.push({ locus: root, detail: "profile must be an object with `name` and `segments`." });
|
|
6396
|
+
return out;
|
|
6397
|
+
}
|
|
6398
|
+
if (typeof profile["name"] !== "string" || profile["name"].trim().length === 0) {
|
|
6399
|
+
out.push({ locus: root, detail: "profile.name must be a non-empty string." });
|
|
6400
|
+
}
|
|
6401
|
+
const segments = profile["segments"];
|
|
6402
|
+
if (!Array.isArray(segments)) {
|
|
6403
|
+
out.push({ locus: root, detail: "profile.segments must be an array of segment rules." });
|
|
6404
|
+
return out;
|
|
6405
|
+
}
|
|
6406
|
+
for (let i = 0; i < segments.length; i++) {
|
|
6407
|
+
const seg = segments[i];
|
|
6408
|
+
if (!isObject(seg)) {
|
|
6409
|
+
out.push({ locus: root, detail: `segments[${String(i)}] must be an object.` });
|
|
6410
|
+
continue;
|
|
6411
|
+
}
|
|
6412
|
+
const name = seg["segment"];
|
|
6413
|
+
if (typeof name !== "string" || !SEGMENT_NAME_RE3.test(name)) {
|
|
6414
|
+
out.push({
|
|
6415
|
+
locus: root,
|
|
6416
|
+
detail: `segments[${String(i)}].segment must be a valid segment name ([A-Z][A-Z0-9]{2}).`
|
|
6417
|
+
});
|
|
6418
|
+
continue;
|
|
6419
|
+
}
|
|
6420
|
+
const segLocus = { segment: name };
|
|
6421
|
+
checkUsage(seg["usage"], segLocus, out);
|
|
6422
|
+
checkSeverity(seg["severity"], segLocus, out);
|
|
6423
|
+
checkCardinality(seg["cardinality"], segLocus, out);
|
|
6424
|
+
const fields = seg["fields"];
|
|
6425
|
+
if (fields !== void 0) {
|
|
6426
|
+
if (!Array.isArray(fields)) {
|
|
6427
|
+
out.push({ locus: segLocus, detail: `segment "${name}" fields must be an array.` });
|
|
6428
|
+
continue;
|
|
6429
|
+
}
|
|
6430
|
+
for (let j = 0; j < fields.length; j++) {
|
|
6431
|
+
checkFieldRule(fields[j], name, j, out);
|
|
6432
|
+
}
|
|
6433
|
+
}
|
|
6434
|
+
}
|
|
6435
|
+
return out;
|
|
6436
|
+
}
|
|
6437
|
+
function checkUsage(usage, locus, out) {
|
|
6438
|
+
if (usage === void 0) return;
|
|
6439
|
+
if (typeof usage !== "string" || !USAGE_CODES.includes(usage)) {
|
|
6440
|
+
out.push({
|
|
6441
|
+
locus,
|
|
6442
|
+
detail: `${describe(locus)} usage must be one of ${USAGE_CODES.join("/")}.`
|
|
6443
|
+
});
|
|
6444
|
+
}
|
|
6445
|
+
}
|
|
6446
|
+
function checkSeverity(sev, locus, out) {
|
|
6447
|
+
if (sev === void 0) return;
|
|
6448
|
+
if (typeof sev !== "string" || !SEVERITIES.includes(sev)) {
|
|
6449
|
+
out.push({
|
|
6450
|
+
locus,
|
|
6451
|
+
detail: `${describe(locus)} severity must be one of ${SEVERITIES.join("/")}.`
|
|
6452
|
+
});
|
|
6453
|
+
}
|
|
6454
|
+
}
|
|
6455
|
+
function checkFieldRule(rule, segment, index, out) {
|
|
6456
|
+
const locus = { segment };
|
|
6457
|
+
if (!isObject(rule)) {
|
|
6458
|
+
out.push({ locus, detail: `segment "${segment}" fields[${String(index)}] must be an object.` });
|
|
6459
|
+
return;
|
|
6460
|
+
}
|
|
6461
|
+
const field = rule["field"];
|
|
6462
|
+
if (typeof field !== "number" || !Number.isInteger(field) || field < 1) {
|
|
6463
|
+
out.push({
|
|
6464
|
+
locus,
|
|
6465
|
+
detail: `segment "${segment}" fields[${String(index)}].field must be a positive (1-indexed) integer.`
|
|
6466
|
+
});
|
|
6467
|
+
return;
|
|
6468
|
+
}
|
|
6469
|
+
const fieldLocus = { segment, field };
|
|
6470
|
+
checkUsage(rule["usage"], fieldLocus, out);
|
|
6471
|
+
checkSeverity(rule["severity"], fieldLocus, out);
|
|
6472
|
+
checkCardinality(rule["cardinality"], fieldLocus, out);
|
|
6473
|
+
const len = rule["length"];
|
|
6474
|
+
if (len !== void 0 && (typeof len !== "number" || !Number.isInteger(len) || len < 0)) {
|
|
6475
|
+
out.push({
|
|
6476
|
+
locus: fieldLocus,
|
|
6477
|
+
detail: `${describe(fieldLocus)} length must be a non-negative integer.`
|
|
6478
|
+
});
|
|
6479
|
+
}
|
|
6480
|
+
const comp = rule["component"];
|
|
6481
|
+
if (comp !== void 0 && (typeof comp !== "number" || !Number.isInteger(comp) || comp < 1)) {
|
|
6482
|
+
out.push({
|
|
6483
|
+
locus: fieldLocus,
|
|
6484
|
+
detail: `${describe(fieldLocus)} component must be a positive (1-indexed) integer.`
|
|
6485
|
+
});
|
|
6486
|
+
}
|
|
6487
|
+
const vs = rule["valueSet"];
|
|
6488
|
+
if (vs !== void 0) {
|
|
6489
|
+
if (!Array.isArray(vs)) {
|
|
6490
|
+
out.push({
|
|
6491
|
+
locus: fieldLocus,
|
|
6492
|
+
detail: `${describe(fieldLocus)} valueSet must be an array of strings.`
|
|
6493
|
+
});
|
|
6494
|
+
} else if (!vs.every((c) => typeof c === "string")) {
|
|
6495
|
+
out.push({
|
|
6496
|
+
locus: fieldLocus,
|
|
6497
|
+
detail: `${describe(fieldLocus)} valueSet entries must all be strings.`
|
|
6498
|
+
});
|
|
6499
|
+
}
|
|
6500
|
+
}
|
|
6501
|
+
}
|
|
6502
|
+
function defineConformanceProfile(profile) {
|
|
6503
|
+
const defects = collectProfileDefects(profile);
|
|
6504
|
+
if (defects.length > 0) {
|
|
6505
|
+
const name = isObject(profile) && typeof profile["name"] === "string" ? profile["name"] : void 0;
|
|
6506
|
+
throw new ProfileDefinitionError(
|
|
6507
|
+
`Conformance profile has ${String(defects.length)} defect(s): ` + defects.map((d) => d.detail).join("; "),
|
|
6508
|
+
name
|
|
6509
|
+
);
|
|
6510
|
+
}
|
|
6511
|
+
return profile;
|
|
6512
|
+
}
|
|
6513
|
+
|
|
6514
|
+
// src/conformance/validate-against-profile.ts
|
|
6515
|
+
function safeName(profile) {
|
|
6516
|
+
if (typeof profile === "object" && profile !== null && !Array.isArray(profile)) {
|
|
6517
|
+
const n = profile["name"];
|
|
6518
|
+
if (typeof n === "string" && n.trim().length > 0) return n;
|
|
6519
|
+
}
|
|
6520
|
+
return "(unnamed profile)";
|
|
6521
|
+
}
|
|
6522
|
+
function componentValue(rep, component) {
|
|
6523
|
+
return rep.components[component - 1]?.subcomponents[0] ?? "";
|
|
6524
|
+
}
|
|
6525
|
+
function fieldHasValue(field) {
|
|
6526
|
+
return field.repetitions.some(
|
|
6527
|
+
(rep) => rep.components.some((comp) => comp.subcomponents.some((sub) => sub !== ""))
|
|
6528
|
+
);
|
|
6529
|
+
}
|
|
6530
|
+
function presenceVerdict(usage, present) {
|
|
6531
|
+
if (usage === "R" && !present) return "required-absent";
|
|
6532
|
+
if (usage === "X" && present) return "not-permitted";
|
|
6533
|
+
return null;
|
|
6534
|
+
}
|
|
6535
|
+
function checkCardinality2(count, card, locus, unit, severity, out) {
|
|
6536
|
+
if (card === void 0) return;
|
|
6537
|
+
const { min, max } = card;
|
|
6538
|
+
if (typeof max === "number" && count > max) {
|
|
6539
|
+
out.push(cardinality(locus, count, card, unit, severity));
|
|
6540
|
+
return;
|
|
6541
|
+
}
|
|
6542
|
+
if (typeof min === "number" && count > 0 && count < min) {
|
|
6543
|
+
out.push(cardinality(locus, count, card, unit, severity));
|
|
6544
|
+
}
|
|
6545
|
+
}
|
|
6546
|
+
function checkFields(seg, occurrence, fields, out) {
|
|
6547
|
+
for (const rule of fields) {
|
|
6548
|
+
const severity = rule.severity ?? "error";
|
|
6549
|
+
const field = seg.field(rule.field);
|
|
6550
|
+
const present = fieldHasValue(field);
|
|
6551
|
+
const baseLocus = { segment: seg.type, field: rule.field, occurrence };
|
|
6552
|
+
const verdict = presenceVerdict(rule.usage, present);
|
|
6553
|
+
if (verdict === "required-absent") {
|
|
6554
|
+
out.push(requiredAbsent(baseLocus, severity));
|
|
6555
|
+
continue;
|
|
6556
|
+
}
|
|
6557
|
+
if (verdict === "not-permitted") {
|
|
6558
|
+
out.push(notPermitted(baseLocus, severity));
|
|
6559
|
+
continue;
|
|
6560
|
+
}
|
|
6561
|
+
if (!present) continue;
|
|
6562
|
+
const reps = field.repetitions;
|
|
6563
|
+
checkCardinality2(reps.length, rule.cardinality, baseLocus, "repetition", severity, out);
|
|
6564
|
+
if (rule.length === void 0 && rule.valueSet === void 0) continue;
|
|
6565
|
+
const component = rule.component ?? 1;
|
|
6566
|
+
for (let r = 0; r < reps.length; r++) {
|
|
6567
|
+
const rep = reps[r];
|
|
6568
|
+
if (rep === void 0) continue;
|
|
6569
|
+
const value = componentValue(rep, component);
|
|
6570
|
+
const locus = {
|
|
6571
|
+
segment: seg.type,
|
|
6572
|
+
field: rule.field,
|
|
6573
|
+
component,
|
|
6574
|
+
repetition: r,
|
|
6575
|
+
occurrence
|
|
6576
|
+
};
|
|
6577
|
+
if (rule.length !== void 0 && value.length > rule.length) {
|
|
6578
|
+
out.push(length(locus, value.length, rule.length, severity));
|
|
6579
|
+
}
|
|
6580
|
+
if (rule.valueSet !== void 0 && value !== "" && !rule.valueSet.includes(value)) {
|
|
6581
|
+
out.push(valueNotInSet(locus, rule.valueSet.length, severity));
|
|
6582
|
+
}
|
|
6583
|
+
}
|
|
6584
|
+
}
|
|
6585
|
+
}
|
|
6586
|
+
function checkSegment(message, rule, out) {
|
|
6587
|
+
const severity = rule.severity ?? "error";
|
|
6588
|
+
const occurrences = message.segments(rule.segment);
|
|
6589
|
+
const count = occurrences.length;
|
|
6590
|
+
const present = count > 0;
|
|
6591
|
+
const segLocus = { segment: rule.segment };
|
|
6592
|
+
const verdict = presenceVerdict(rule.usage, present);
|
|
6593
|
+
if (verdict === "required-absent") {
|
|
6594
|
+
out.push(requiredAbsent(segLocus, severity));
|
|
6595
|
+
return;
|
|
6596
|
+
}
|
|
6597
|
+
if (verdict === "not-permitted") {
|
|
6598
|
+
out.push(notPermitted(segLocus, severity));
|
|
6599
|
+
return;
|
|
6600
|
+
}
|
|
6601
|
+
checkCardinality2(count, rule.cardinality, segLocus, "occurrence", severity, out);
|
|
6602
|
+
if (!present || rule.fields === void 0) return;
|
|
6603
|
+
for (let occ = 0; occ < occurrences.length; occ++) {
|
|
6604
|
+
const seg = occurrences[occ];
|
|
6605
|
+
if (seg === void 0) continue;
|
|
6606
|
+
checkFields(seg, occ, rule.fields, out);
|
|
6607
|
+
}
|
|
6608
|
+
}
|
|
6609
|
+
function validateAgainstProfile(message, profile) {
|
|
6610
|
+
const defects = collectProfileDefects(profile);
|
|
6611
|
+
if (defects.length > 0) {
|
|
6612
|
+
const findings = defects.map((d) => malformed(d.locus, d.detail));
|
|
6613
|
+
return Object.freeze({ profileName: safeName(profile), findings: Object.freeze(findings) });
|
|
6614
|
+
}
|
|
6615
|
+
const out = [];
|
|
6616
|
+
for (const rule of profile.segments) {
|
|
6617
|
+
checkSegment(message, rule, out);
|
|
6618
|
+
}
|
|
6619
|
+
return Object.freeze({ profileName: profile.name, findings: Object.freeze(out) });
|
|
6620
|
+
}
|
|
6621
|
+
|
|
6622
|
+
// src/conformance/index.ts
|
|
6623
|
+
var conformance_exports = {};
|
|
6624
|
+
__export(conformance_exports, {
|
|
6625
|
+
FINDING_CODES: () => FINDING_CODES,
|
|
6626
|
+
USAGE_CODES: () => USAGE_CODES,
|
|
6627
|
+
collectProfileDefects: () => collectProfileDefects,
|
|
6628
|
+
defineConformanceProfile: () => defineConformanceProfile,
|
|
6629
|
+
validateAgainstProfile: () => validateAgainstProfile
|
|
6630
|
+
});
|
|
6631
|
+
function isEnvelopeName2(name) {
|
|
6632
|
+
return name === "FHS" || name === "BHS" || name === "BTS" || name === "FTS";
|
|
6633
|
+
}
|
|
6634
|
+
function decodeChunk(chunk) {
|
|
6635
|
+
if (typeof chunk === "string") return { text: chunk, wasBuffer: false };
|
|
6636
|
+
if (chunk instanceof Uint8Array) {
|
|
6637
|
+
return { text: Buffer.from(chunk).toString("latin1"), wasBuffer: true };
|
|
6638
|
+
}
|
|
6639
|
+
throw new TypeError(
|
|
6640
|
+
`parseStream: each chunk must be a string, Buffer, or Uint8Array; received ${chunk === null ? "null" : typeof chunk}.`
|
|
6641
|
+
);
|
|
6642
|
+
}
|
|
6643
|
+
async function* iterateChunks(source) {
|
|
6644
|
+
if (source === null || source === void 0) {
|
|
6645
|
+
throw new TypeError("parseStream: source must be an async-iterable or iterable of chunks.");
|
|
6646
|
+
}
|
|
6647
|
+
const asAsync = source[Symbol.asyncIterator];
|
|
6648
|
+
if (typeof asAsync === "function") {
|
|
6649
|
+
for await (const chunk of source) yield chunk;
|
|
6650
|
+
return;
|
|
6651
|
+
}
|
|
6652
|
+
const asSync = source[Symbol.iterator];
|
|
6653
|
+
if (typeof asSync === "function") {
|
|
6654
|
+
for (const chunk of source) yield chunk;
|
|
6655
|
+
return;
|
|
6656
|
+
}
|
|
6657
|
+
throw new TypeError(
|
|
6658
|
+
"parseStream: source must be an async-iterable or iterable of chunks (e.g. a Node Readable)."
|
|
6659
|
+
);
|
|
6660
|
+
}
|
|
6661
|
+
function nextSegment(buf, cursor, final) {
|
|
6662
|
+
if (cursor >= buf.length) return null;
|
|
6663
|
+
const r = buf.indexOf("\r", cursor);
|
|
6664
|
+
const n = buf.indexOf("\n", cursor);
|
|
6665
|
+
let idx;
|
|
6666
|
+
let isCr;
|
|
6667
|
+
if (r === -1 && n === -1) return null;
|
|
6668
|
+
else if (r === -1) {
|
|
6669
|
+
idx = n;
|
|
6670
|
+
isCr = false;
|
|
6671
|
+
} else if (n === -1) {
|
|
6672
|
+
idx = r;
|
|
6673
|
+
isCr = true;
|
|
6674
|
+
} else if (r < n) {
|
|
6675
|
+
idx = r;
|
|
6676
|
+
isCr = true;
|
|
6677
|
+
} else {
|
|
6678
|
+
idx = n;
|
|
6679
|
+
isCr = false;
|
|
6680
|
+
}
|
|
6681
|
+
if (isCr && idx === buf.length - 1 && !final) return null;
|
|
6682
|
+
let termLen = 1;
|
|
6683
|
+
if (isCr && idx + 1 < buf.length && buf.charCodeAt(idx + 1) === 10) termLen = 2;
|
|
6684
|
+
return { seg: buf.slice(cursor, idx), next: idx + termLen };
|
|
6685
|
+
}
|
|
6686
|
+
function parseStreamEntry(rawMessage, position, wasBuffer, optionsOrProfile, streamWarnings) {
|
|
6687
|
+
const input = wasBuffer ? Buffer.from(rawMessage, "latin1") : rawMessage;
|
|
6688
|
+
try {
|
|
6689
|
+
const message = optionsOrProfile === void 0 ? parseHL7(input) : parseHL7(input, optionsOrProfile);
|
|
6690
|
+
return Object.freeze({ ok: true, message, raw: rawMessage, position, streamWarnings });
|
|
6691
|
+
} catch (error) {
|
|
6692
|
+
if (error instanceof Hl7ParseError) {
|
|
6693
|
+
return Object.freeze({ ok: false, error, raw: rawMessage, position, streamWarnings });
|
|
6694
|
+
}
|
|
6695
|
+
throw error;
|
|
6696
|
+
}
|
|
6697
|
+
}
|
|
6698
|
+
async function* parseStream(source, optionsOrProfile) {
|
|
6699
|
+
if (typeof source === "string" || source instanceof Uint8Array) {
|
|
6700
|
+
throw new TypeError(
|
|
6701
|
+
"parseStream expects a stream of chunks (a Node Readable, an async-iterable, or an iterable of string/Buffer chunks), not a single string or Buffer. For one message use parseHL7; to stream a whole buffer, wrap it: parseStream([buffer])."
|
|
6702
|
+
);
|
|
6703
|
+
}
|
|
6704
|
+
let pending = "";
|
|
6705
|
+
let currentLines = [];
|
|
6706
|
+
let messageStartIndex = -1;
|
|
6707
|
+
let globalSegmentIndex = 0;
|
|
6708
|
+
let wasBuffer = false;
|
|
6709
|
+
let firstChunkSeen = false;
|
|
6710
|
+
let bomStripped = false;
|
|
6711
|
+
const flush = (finalUnterminated2) => {
|
|
6712
|
+
while (currentLines.length > 0 && currentLines[currentLines.length - 1] === "") {
|
|
6713
|
+
currentLines.pop();
|
|
6714
|
+
}
|
|
6715
|
+
if (currentLines.length === 0) {
|
|
6716
|
+
messageStartIndex = -1;
|
|
6717
|
+
return null;
|
|
6718
|
+
}
|
|
6719
|
+
const position = Object.freeze({ segmentIndex: messageStartIndex });
|
|
6720
|
+
const streamWarnings = finalUnterminated2 ? Object.freeze([unterminatedStreamMessage(position)]) : Object.freeze([]);
|
|
6721
|
+
const entry = parseStreamEntry(
|
|
6722
|
+
currentLines.join("\r"),
|
|
6723
|
+
position,
|
|
6724
|
+
wasBuffer,
|
|
6725
|
+
optionsOrProfile,
|
|
6726
|
+
streamWarnings
|
|
6727
|
+
);
|
|
6728
|
+
currentLines = [];
|
|
6729
|
+
messageStartIndex = -1;
|
|
6730
|
+
return entry;
|
|
6731
|
+
};
|
|
6732
|
+
const processSegment = (seg) => {
|
|
6733
|
+
const thisIndex = globalSegmentIndex;
|
|
6734
|
+
globalSegmentIndex += 1;
|
|
6735
|
+
const name = seg.slice(0, 3);
|
|
6736
|
+
if (isEnvelopeName2(name)) {
|
|
6737
|
+
return flush(false);
|
|
6738
|
+
}
|
|
6739
|
+
if (name === "MSH") {
|
|
6740
|
+
const flushed = flush(false);
|
|
6741
|
+
currentLines = [seg];
|
|
6742
|
+
messageStartIndex = thisIndex;
|
|
6743
|
+
return flushed;
|
|
6744
|
+
}
|
|
6745
|
+
if (currentLines.length === 0) {
|
|
6746
|
+
if (seg.trim() === "") return null;
|
|
6747
|
+
messageStartIndex = thisIndex;
|
|
6748
|
+
}
|
|
6749
|
+
currentLines.push(seg);
|
|
6750
|
+
return null;
|
|
6751
|
+
};
|
|
6752
|
+
const tryStripBom = (final) => {
|
|
6753
|
+
if (bomStripped || pending.length === 0) return;
|
|
6754
|
+
if (pending.charCodeAt(0) === 65279) {
|
|
6755
|
+
pending = pending.slice(1);
|
|
6756
|
+
bomStripped = true;
|
|
6757
|
+
} else if (pending.startsWith("\xEF\xBB\xBF")) {
|
|
6758
|
+
pending = pending.slice(3);
|
|
6759
|
+
bomStripped = true;
|
|
6760
|
+
} else if (final || !"\xEF\xBB\xBF".startsWith(pending)) {
|
|
6761
|
+
bomStripped = true;
|
|
6762
|
+
}
|
|
6763
|
+
};
|
|
6764
|
+
for await (const rawChunk of iterateChunks(source)) {
|
|
6765
|
+
const { text, wasBuffer: chunkWasBuffer } = decodeChunk(rawChunk);
|
|
6766
|
+
if (!firstChunkSeen) {
|
|
6767
|
+
wasBuffer = chunkWasBuffer;
|
|
6768
|
+
firstChunkSeen = true;
|
|
6769
|
+
}
|
|
6770
|
+
if (text.length === 0) continue;
|
|
6771
|
+
pending += text;
|
|
6772
|
+
tryStripBom(false);
|
|
6773
|
+
if (!bomStripped) continue;
|
|
6774
|
+
let cursor = 0;
|
|
6775
|
+
for (; ; ) {
|
|
6776
|
+
const res = nextSegment(pending, cursor, false);
|
|
6777
|
+
if (res === null) break;
|
|
6778
|
+
cursor = res.next;
|
|
6779
|
+
const entry = processSegment(res.seg);
|
|
6780
|
+
if (entry !== null) yield entry;
|
|
6781
|
+
}
|
|
6782
|
+
pending = pending.slice(cursor);
|
|
6783
|
+
}
|
|
6784
|
+
tryStripBom(true);
|
|
6785
|
+
{
|
|
6786
|
+
let cursor = 0;
|
|
6787
|
+
for (; ; ) {
|
|
6788
|
+
const res = nextSegment(pending, cursor, true);
|
|
6789
|
+
if (res === null) break;
|
|
6790
|
+
cursor = res.next;
|
|
6791
|
+
const entry = processSegment(res.seg);
|
|
6792
|
+
if (entry !== null) yield entry;
|
|
6793
|
+
}
|
|
6794
|
+
pending = pending.slice(cursor);
|
|
6795
|
+
}
|
|
6796
|
+
const tail = pending;
|
|
6797
|
+
pending = "";
|
|
6798
|
+
let finalUnterminated = false;
|
|
6799
|
+
if (tail.length > 0) {
|
|
6800
|
+
const flushed = processSegment(tail);
|
|
6801
|
+
if (flushed !== null) yield flushed;
|
|
6802
|
+
finalUnterminated = currentLines.length > 0 && tail.trim() !== "";
|
|
6803
|
+
}
|
|
6804
|
+
const finalEntry = flush(finalUnterminated);
|
|
6805
|
+
if (finalEntry !== null) yield finalEntry;
|
|
6806
|
+
}
|
|
6807
|
+
|
|
5442
6808
|
// src/index.ts
|
|
5443
|
-
var VERSION = "0.0.
|
|
6809
|
+
var VERSION = "0.0.3";
|
|
5444
6810
|
|
|
5445
|
-
export { ACK_CODES, ACK_CONDITIONS, BUILTIN_DATE_FALLBACKS, DEFAULT_ENCODING_CHARACTERS, ERR_CONDITION_CODES, ERR_CONDITION_CODE_SYSTEM, ERR_SEVERITIES, FATAL_CODES, Field, namespace_exports as HL7, Hl7Message, Hl7ParseError, KNOWN_CODING_SYSTEMS, KNOWN_SEGMENTS, MESSAGE_STRUCTURE_DEFINITIONS, ProfileDefinitionError, SUPPORTED_DATE_TOKENS, Segment, VERSION, WARNING_CODES, ackNoCorrelationId, alternateCodingSystemOf, analyzeMessageStructure, batchCountMismatch, batchMissingTrailer, buildAck, buildMessage, canonicalCharset, codingSystem, codingSystemOf, defineProfile, detectAckMode, downgradePositiveAck, dtmToDate, duplicateRequiredSegment, encodingMismatch, extraFields, fieldWhitespaceTrimmed, formatDtm, getDefaultProfile, interpretAck, isPositiveAck, mergeMissingPriorOrSurvivor, missingExpectedGroup, missingRequiredField, mllpFramingStripped, outOfOrderSegment, parseCe, parseCwe, parseCx, parseDtm, parseHL7, parseHd, parseNm, parsePath, parsePl, parseSn, parseTs, parseXad, parseXcn, parseXpn, parseXtn, pickMrn, profiles, reescape, resolveCharset, resolvePath, segmentCase, setDefaultProfile, splitBatch, timestampFallbackFormat, unescape, unknownCharset, unknownEscapeSequence, unknownSegment, unsupportedCharset, unterminatedEscapeSequence, versionMismatch };
|
|
6811
|
+
export { ACK_CODES, ACK_CONDITIONS, BUILTIN_DATE_FALLBACKS, DEFAULT_ENCODING_CHARACTERS, ERR_CONDITION_CODES, ERR_CONDITION_CODE_SYSTEM, ERR_SEVERITIES, FATAL_CODES, FINDING_CODES, Field, namespace_exports as HL7, Hl7Message, Hl7ParseError, KNOWN_CODING_SYSTEMS, KNOWN_SEGMENTS, MESSAGE_STRUCTURE_DEFINITIONS, ProfileDefinitionError, SUPPORTED_DATE_TOKENS, Segment, USAGE_CODES, VERSION, WARNING_CODES, ackNoCorrelationId, alternateCodingSystemOf, analyzeMessageStructure, batchCountMismatch, batchMissingTrailer, buildAck, buildAdt, buildMessage, buildOru, canonicalCharset, codingSystem, codingSystemOf, conformance_exports as conformance, decodeText, defineConformanceProfile, defineProfile, detectAckMode, downgradePositiveAck, dtmToDate, duplicateRequiredSegment, encodeCe, encodeComposite, encodeCompositeReps, encodeCwe, encodeCx, encodeHd, encodeNm, encodePl, encodeText, encodeTs, encodeXad, encodeXcn, encodeXpn, encodeXtn, encodingMismatch, extraFields, fieldWhitespaceTrimmed, formatDtm, getDefaultProfile, interpretAck, isPositiveAck, mergeMissingPriorOrSurvivor, missingExpectedGroup, missingRequiredField, mllpFramingStripped, outOfOrderSegment, parseCe, parseCwe, parseCx, parseDtm, parseHL7, parseHd, parseNm, parsePath, parsePl, parseSn, parseStream, parseTs, parseXad, parseXcn, parseXpn, parseXtn, pickMrn, profiles, reescape, renderText, resolveCharset, resolvePath, segmentCase, setDefaultProfile, splitBatch, text_exports as text, timestampFallbackFormat, unescape, unknownCharset, unknownEscapeSequence, unknownSegment, unsupportedCharset, unterminatedEscapeSequence, unterminatedStreamMessage, validateAgainstProfile, versionMismatch };
|
|
5446
6812
|
//# sourceMappingURL=index.mjs.map
|
|
5447
6813
|
//# sourceMappingURL=index.mjs.map
|