@cosyte/hl7 0.0.2 → 0.0.4
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 +287 -0
- package/README.md +14 -6
- package/dist/index.cjs +187 -122
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +314 -267
- package/dist/index.d.ts +314 -267
- package/dist/index.mjs +187 -122
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -38,7 +38,7 @@ var ProfileDefinitionError = class extends Error {
|
|
|
38
38
|
profileName;
|
|
39
39
|
/**
|
|
40
40
|
* Construct a new `ProfileDefinitionError`. `profileName` is optional so
|
|
41
|
-
*
|
|
41
|
+
* callers may omit it when the offending profile cannot be named
|
|
42
42
|
* (e.g. during initial validation before a name is parsed).
|
|
43
43
|
*
|
|
44
44
|
* @internal
|
|
@@ -255,7 +255,104 @@ var KNOWN_SEGMENTS = /* @__PURE__ */ new Set([
|
|
|
255
255
|
"CSS"
|
|
256
256
|
]);
|
|
257
257
|
|
|
258
|
+
// src/parser/charset.ts
|
|
259
|
+
function normalizeLabel(raw) {
|
|
260
|
+
return raw.trim().replace(/\s+/gu, " ").toUpperCase();
|
|
261
|
+
}
|
|
262
|
+
function decodeEntry(canonical, decoder) {
|
|
263
|
+
return { canonical, treatment: "decode", decoder };
|
|
264
|
+
}
|
|
265
|
+
function verbatimEntry(canonical) {
|
|
266
|
+
return { canonical, treatment: "verbatim", decoder: "" };
|
|
267
|
+
}
|
|
268
|
+
function buildTable() {
|
|
269
|
+
const table = /* @__PURE__ */ new Map();
|
|
270
|
+
const add = (aliases, entry) => {
|
|
271
|
+
for (const alias of aliases) table.set(normalizeLabel(alias), entry);
|
|
272
|
+
};
|
|
273
|
+
add(["ASCII", "US-ASCII", "ISO IR6"], decodeEntry("ASCII", "utf-8"));
|
|
274
|
+
add(["UTF-8", "UTF8", "UNICODE UTF-8", "UNICODE"], decodeEntry("UTF-8", "utf-8"));
|
|
275
|
+
add(["8859/1", "ISO-8859-1", "ISO 8859-1", "ISO8859-1"], decodeEntry("8859/1", "latin1"));
|
|
276
|
+
for (const n of [2, 3, 4, 5, 6, 7, 8, 10, 13, 14, 15, 16]) {
|
|
277
|
+
add(
|
|
278
|
+
[`8859/${n}`, `ISO-8859-${n}`, `ISO 8859-${n}`, `ISO8859-${n}`],
|
|
279
|
+
decodeEntry(`8859/${n}`, `iso-8859-${n}`)
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
add(["8859/9", "ISO-8859-9", "ISO 8859-9", "ISO8859-9"], verbatimEntry("8859/9"));
|
|
283
|
+
add(["8859/11", "ISO-8859-11", "ISO 8859-11", "ISO8859-11"], verbatimEntry("8859/11"));
|
|
284
|
+
add(["ISO IR14", "JIS X 0201"], verbatimEntry("ISO IR14"));
|
|
285
|
+
add(["ISO IR87", "JIS X 0208"], verbatimEntry("ISO IR87"));
|
|
286
|
+
add(["ISO IR159", "JIS X 0212"], verbatimEntry("ISO IR159"));
|
|
287
|
+
add(["GB 18030-2000", "GB18030", "GB 18030"], verbatimEntry("GB 18030-2000"));
|
|
288
|
+
add(["KS X 1001", "KSX1001", "KS C 5601"], verbatimEntry("KS X 1001"));
|
|
289
|
+
add(["CNS 11643-1992", "CNS 11643"], verbatimEntry("CNS 11643-1992"));
|
|
290
|
+
add(["BIG-5", "BIG5"], verbatimEntry("BIG-5"));
|
|
291
|
+
add(["UNICODE UTF-16", "UTF-16"], verbatimEntry("UNICODE UTF-16"));
|
|
292
|
+
add(["UNICODE UTF-32", "UTF-32"], verbatimEntry("UNICODE UTF-32"));
|
|
293
|
+
return table;
|
|
294
|
+
}
|
|
295
|
+
var CHARSET_TABLE = buildTable();
|
|
296
|
+
var DEFAULT_RESOLUTION = Object.freeze({
|
|
297
|
+
canonical: "ASCII",
|
|
298
|
+
treatment: "decode",
|
|
299
|
+
decoder: "utf-8",
|
|
300
|
+
recognized: true
|
|
301
|
+
});
|
|
302
|
+
function resolveCharset(raw) {
|
|
303
|
+
if (raw === void 0) return DEFAULT_RESOLUTION;
|
|
304
|
+
const key = normalizeLabel(raw);
|
|
305
|
+
if (key === "") return DEFAULT_RESOLUTION;
|
|
306
|
+
const entry = CHARSET_TABLE.get(key);
|
|
307
|
+
if (entry !== void 0) {
|
|
308
|
+
return {
|
|
309
|
+
canonical: entry.canonical,
|
|
310
|
+
treatment: entry.treatment,
|
|
311
|
+
decoder: entry.decoder,
|
|
312
|
+
recognized: true
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
return { canonical: key, treatment: "verbatim", decoder: "", recognized: false };
|
|
316
|
+
}
|
|
317
|
+
function canonicalCharset(raw) {
|
|
318
|
+
return resolveCharset(raw).canonical;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// src/parser/tokens.ts
|
|
322
|
+
var DERIVED_TOKEN_SHAPES = {
|
|
323
|
+
/**
|
|
324
|
+
* HL7 v2 Ch. 2 §2.5 segment identifier: three characters, the first
|
|
325
|
+
* alphabetic.
|
|
326
|
+
*
|
|
327
|
+
* Two deliberate tightenings, each measured rather than assumed. The first
|
|
328
|
+
* version allowed four characters as "vendor tolerance", which was invented
|
|
329
|
+
* rather than grounded: all 91 `KNOWN_SEGMENTS` are exactly three, and
|
|
330
|
+
* `defineProfile` independently validates custom Z-segments to
|
|
331
|
+
* `/^Z[A-Z0-9]{2}$/`, so nothing legitimate is longer. The second requires a
|
|
332
|
+
* leading letter, which every known segment and every legal Z-segment
|
|
333
|
+
* satisfies, and which excludes a **bare numeric** residue. That matters out
|
|
334
|
+
* of proportion to its size: a forged line reading `120` is a glucose, a
|
|
335
|
+
* blood pressure or a dose, which is the most clinical meaning three
|
|
336
|
+
* characters can carry.
|
|
337
|
+
*/
|
|
338
|
+
segmentId: /^[A-Za-z][A-Za-z0-9]{2}$/,
|
|
339
|
+
/** MSH-9 message type / trigger, e.g. `ADT^A01` or `A40`. */
|
|
340
|
+
messageType: /^[A-Za-z0-9]{1,8}(?:\^[A-Za-z0-9]{1,8}){0,2}$/,
|
|
341
|
+
/** MSH-12 version ID, e.g. `2.5` or `2.5.1`. */
|
|
342
|
+
version: /^[0-9]{1,2}(?:\.[0-9]{1,3}){0,3}$/
|
|
343
|
+
};
|
|
344
|
+
function safeDerivedToken(value, kind) {
|
|
345
|
+
return DERIVED_TOKEN_SHAPES[kind].test(value) ? value : WITHHELD;
|
|
346
|
+
}
|
|
347
|
+
var WITHHELD = "<withheld>";
|
|
348
|
+
function boundedIdentifier(value, kind) {
|
|
349
|
+
return value === "" ? "" : safeDerivedToken(value, kind);
|
|
350
|
+
}
|
|
351
|
+
|
|
258
352
|
// src/parser/warnings.ts
|
|
353
|
+
function safeCharsetLabel(value) {
|
|
354
|
+
return resolveCharset(value).recognized ? value : WITHHELD;
|
|
355
|
+
}
|
|
259
356
|
var WARNING_CODES = {
|
|
260
357
|
MLLP_FRAMING_STRIPPED: "MLLP_FRAMING_STRIPPED",
|
|
261
358
|
FIELD_WHITESPACE_TRIMMED: "FIELD_WHITESPACE_TRIMMED",
|
|
@@ -340,28 +437,28 @@ function timestampFallbackFormat(position, matchedFormat) {
|
|
|
340
437
|
function segmentCase(position, observed) {
|
|
341
438
|
return {
|
|
342
439
|
code: WARNING_CODES.SEGMENT_CASE,
|
|
343
|
-
message: `Segment identifier "${observed}" is not uppercase; normalized to "${observed.toUpperCase()}".`,
|
|
440
|
+
message: `Segment identifier "${safeDerivedToken(observed, "segmentId")}" is not uppercase; normalized to "${safeDerivedToken(observed.toUpperCase(), "segmentId")}".`,
|
|
344
441
|
position
|
|
345
442
|
};
|
|
346
443
|
}
|
|
347
444
|
function extraFields(position, segmentName2, extraCount) {
|
|
348
445
|
return {
|
|
349
446
|
code: WARNING_CODES.EXTRA_FIELDS,
|
|
350
|
-
message: `Segment "${segmentName2}" has ${String(extraCount)} more field(s) than the profile declares.`,
|
|
447
|
+
message: `Segment "${safeDerivedToken(segmentName2, "segmentId")}" has ${String(extraCount)} more field(s) than the profile declares.`,
|
|
351
448
|
position
|
|
352
449
|
};
|
|
353
450
|
}
|
|
354
451
|
function unknownSegment(position, segmentName2) {
|
|
355
452
|
return {
|
|
356
453
|
code: WARNING_CODES.UNKNOWN_SEGMENT,
|
|
357
|
-
message: `Unknown segment "${segmentName2}": not in HL7 spec and no profile claim.`,
|
|
454
|
+
message: `Unknown segment "${safeDerivedToken(segmentName2, "segmentId")}": not in HL7 spec and no profile claim.`,
|
|
358
455
|
position
|
|
359
456
|
};
|
|
360
457
|
}
|
|
361
458
|
function duplicateRequiredSegment(position, segmentName2) {
|
|
362
459
|
return {
|
|
363
460
|
code: WARNING_CODES.DUPLICATE_REQUIRED_SEGMENT,
|
|
364
|
-
message: `Required singleton segment "${segmentName2}" appears more than once.`,
|
|
461
|
+
message: `Required singleton segment "${safeDerivedToken(segmentName2, "segmentId")}" appears more than once.`,
|
|
365
462
|
position
|
|
366
463
|
};
|
|
367
464
|
}
|
|
@@ -375,42 +472,42 @@ function encodingMismatch(position, detail) {
|
|
|
375
472
|
function missingRequiredField(position, segmentName2, fieldIndex) {
|
|
376
473
|
return {
|
|
377
474
|
code: WARNING_CODES.MISSING_REQUIRED_FIELD,
|
|
378
|
-
message: `Required field ${segmentName2}-${String(fieldIndex)} is missing or empty.`,
|
|
475
|
+
message: `Required field ${safeDerivedToken(segmentName2, "segmentId")}-${String(fieldIndex)} is missing or empty.`,
|
|
379
476
|
position
|
|
380
477
|
};
|
|
381
478
|
}
|
|
382
479
|
function missingExpectedGroup(position, messageType, groupName, anchorSegments) {
|
|
383
480
|
return {
|
|
384
481
|
code: WARNING_CODES.MISSING_EXPECTED_GROUP,
|
|
385
|
-
message: `Message type "${messageType}" is missing its expected "${groupName}" segment group (no ${anchorSegments.join("/")}); message may be truncated or misrouted.`,
|
|
482
|
+
message: `Message type "${safeDerivedToken(messageType, "messageType")}" is missing its expected "${groupName}" segment group (no ${anchorSegments.join("/")}); message may be truncated or misrouted.`,
|
|
386
483
|
position
|
|
387
484
|
};
|
|
388
485
|
}
|
|
389
486
|
function outOfOrderSegment(position, segmentName2) {
|
|
390
487
|
return {
|
|
391
488
|
code: WARNING_CODES.OUT_OF_ORDER_SEGMENT,
|
|
392
|
-
message: `Segment "${segmentName2}" appears out of the order declared by the active profile.`,
|
|
489
|
+
message: `Segment "${safeDerivedToken(segmentName2, "segmentId")}" appears out of the order declared by the active profile.`,
|
|
393
490
|
position
|
|
394
491
|
};
|
|
395
492
|
}
|
|
396
493
|
function versionMismatch(position, declared, expected) {
|
|
397
494
|
return {
|
|
398
495
|
code: WARNING_CODES.VERSION_MISMATCH,
|
|
399
|
-
message: `HL7 version mismatch: message declares "${declared}", expected "${expected}".`,
|
|
496
|
+
message: `HL7 version mismatch: message declares "${safeDerivedToken(declared, "version")}", expected "${expected}".`,
|
|
400
497
|
position
|
|
401
498
|
};
|
|
402
499
|
}
|
|
403
500
|
function unknownCharset(position, requested) {
|
|
404
501
|
return {
|
|
405
502
|
code: WARNING_CODES.UNKNOWN_CHARSET,
|
|
406
|
-
message: `Unrecognized character set "${requested}"; not decoded, bytes read as latin1.`,
|
|
503
|
+
message: `Unrecognized character set "${safeCharsetLabel(requested)}"; not decoded, bytes read as latin1.`,
|
|
407
504
|
position
|
|
408
505
|
};
|
|
409
506
|
}
|
|
410
507
|
function unsupportedCharset(position, code) {
|
|
411
508
|
return {
|
|
412
509
|
code: WARNING_CODES.UNSUPPORTED_CHARSET,
|
|
413
|
-
message: `Character set "${code}" was not decoded; bytes read as latin1.`,
|
|
510
|
+
message: `Character set "${safeCharsetLabel(code)}" was not decoded; bytes read as latin1.`,
|
|
414
511
|
position
|
|
415
512
|
};
|
|
416
513
|
}
|
|
@@ -425,7 +522,7 @@ function mergeMissingPriorOrSurvivor(position, eventType, missing) {
|
|
|
425
522
|
const detail = missing === "prior" ? "no MRG segment carries a usable prior (non-surviving) identifier" : "no PID segment carries a usable surviving identifier";
|
|
426
523
|
return {
|
|
427
524
|
code: WARNING_CODES.MERGE_MISSING_PRIOR_OR_SURVIVOR,
|
|
428
|
-
message: `Identity event "${eventType}" is missing its ${missing} role: ${detail}. Surfacing what is present; the MRG->PID merge direction is not guessed.`,
|
|
525
|
+
message: `Identity event "${safeDerivedToken(eventType, "messageType")}" is missing its ${missing} role: ${detail}. Surfacing what is present; the MRG->PID merge direction is not guessed.`,
|
|
429
526
|
position
|
|
430
527
|
};
|
|
431
528
|
}
|
|
@@ -471,69 +568,6 @@ function emitIfFramed(result, emit, position) {
|
|
|
471
568
|
}
|
|
472
569
|
}
|
|
473
570
|
|
|
474
|
-
// src/parser/charset.ts
|
|
475
|
-
function normalizeLabel(raw) {
|
|
476
|
-
return raw.trim().replace(/\s+/gu, " ").toUpperCase();
|
|
477
|
-
}
|
|
478
|
-
function decodeEntry(canonical, decoder) {
|
|
479
|
-
return { canonical, treatment: "decode", decoder };
|
|
480
|
-
}
|
|
481
|
-
function verbatimEntry(canonical) {
|
|
482
|
-
return { canonical, treatment: "verbatim", decoder: "" };
|
|
483
|
-
}
|
|
484
|
-
function buildTable() {
|
|
485
|
-
const table = /* @__PURE__ */ new Map();
|
|
486
|
-
const add = (aliases, entry) => {
|
|
487
|
-
for (const alias of aliases) table.set(normalizeLabel(alias), entry);
|
|
488
|
-
};
|
|
489
|
-
add(["ASCII", "US-ASCII", "ISO IR6"], decodeEntry("ASCII", "utf-8"));
|
|
490
|
-
add(["UTF-8", "UTF8", "UNICODE UTF-8", "UNICODE"], decodeEntry("UTF-8", "utf-8"));
|
|
491
|
-
add(["8859/1", "ISO-8859-1", "ISO 8859-1", "ISO8859-1"], decodeEntry("8859/1", "latin1"));
|
|
492
|
-
for (const n of [2, 3, 4, 5, 6, 7, 8, 10, 13, 14, 15, 16]) {
|
|
493
|
-
add(
|
|
494
|
-
[`8859/${n}`, `ISO-8859-${n}`, `ISO 8859-${n}`, `ISO8859-${n}`],
|
|
495
|
-
decodeEntry(`8859/${n}`, `iso-8859-${n}`)
|
|
496
|
-
);
|
|
497
|
-
}
|
|
498
|
-
add(["8859/9", "ISO-8859-9", "ISO 8859-9", "ISO8859-9"], verbatimEntry("8859/9"));
|
|
499
|
-
add(["8859/11", "ISO-8859-11", "ISO 8859-11", "ISO8859-11"], verbatimEntry("8859/11"));
|
|
500
|
-
add(["ISO IR14", "JIS X 0201"], verbatimEntry("ISO IR14"));
|
|
501
|
-
add(["ISO IR87", "JIS X 0208"], verbatimEntry("ISO IR87"));
|
|
502
|
-
add(["ISO IR159", "JIS X 0212"], verbatimEntry("ISO IR159"));
|
|
503
|
-
add(["GB 18030-2000", "GB18030", "GB 18030"], verbatimEntry("GB 18030-2000"));
|
|
504
|
-
add(["KS X 1001", "KSX1001", "KS C 5601"], verbatimEntry("KS X 1001"));
|
|
505
|
-
add(["CNS 11643-1992", "CNS 11643"], verbatimEntry("CNS 11643-1992"));
|
|
506
|
-
add(["BIG-5", "BIG5"], verbatimEntry("BIG-5"));
|
|
507
|
-
add(["UNICODE UTF-16", "UTF-16"], verbatimEntry("UNICODE UTF-16"));
|
|
508
|
-
add(["UNICODE UTF-32", "UTF-32"], verbatimEntry("UNICODE UTF-32"));
|
|
509
|
-
return table;
|
|
510
|
-
}
|
|
511
|
-
var CHARSET_TABLE = buildTable();
|
|
512
|
-
var DEFAULT_RESOLUTION = Object.freeze({
|
|
513
|
-
canonical: "ASCII",
|
|
514
|
-
treatment: "decode",
|
|
515
|
-
decoder: "utf-8",
|
|
516
|
-
recognized: true
|
|
517
|
-
});
|
|
518
|
-
function resolveCharset(raw) {
|
|
519
|
-
if (raw === void 0) return DEFAULT_RESOLUTION;
|
|
520
|
-
const key = normalizeLabel(raw);
|
|
521
|
-
if (key === "") return DEFAULT_RESOLUTION;
|
|
522
|
-
const entry = CHARSET_TABLE.get(key);
|
|
523
|
-
if (entry !== void 0) {
|
|
524
|
-
return {
|
|
525
|
-
canonical: entry.canonical,
|
|
526
|
-
treatment: entry.treatment,
|
|
527
|
-
decoder: entry.decoder,
|
|
528
|
-
recognized: true
|
|
529
|
-
};
|
|
530
|
-
}
|
|
531
|
-
return { canonical: key, treatment: "verbatim", decoder: "", recognized: false };
|
|
532
|
-
}
|
|
533
|
-
function canonicalCharset(raw) {
|
|
534
|
-
return resolveCharset(raw).canonical;
|
|
535
|
-
}
|
|
536
|
-
|
|
537
571
|
// src/parser/normalize.ts
|
|
538
572
|
var CHARSET_POSITION = { segmentIndex: 0, fieldIndex: 18 };
|
|
539
573
|
function preserveVerbatim(input) {
|
|
@@ -928,8 +962,8 @@ function analyzeMessageStructure(messageCode, triggerEvent, presentSegmentNames)
|
|
|
928
962
|
if (def === void 0) {
|
|
929
963
|
return Object.freeze({
|
|
930
964
|
recognized: false,
|
|
931
|
-
messageCode,
|
|
932
|
-
triggerEvent,
|
|
965
|
+
messageCode: boundedIdentifier(messageCode, "segmentId"),
|
|
966
|
+
triggerEvent: boundedIdentifier(triggerEvent, "segmentId"),
|
|
933
967
|
expectedGroups: Object.freeze([]),
|
|
934
968
|
missingGroups: Object.freeze([])
|
|
935
969
|
});
|
|
@@ -1863,11 +1897,11 @@ var Field = class {
|
|
|
1863
1897
|
isNull;
|
|
1864
1898
|
/** Reference to the underlying `RawField.repetitions` (no defensive copy). */
|
|
1865
1899
|
repetitions;
|
|
1866
|
-
/** The 5 encoding characters for this message. Exposed for composite parsers
|
|
1900
|
+
/** The 5 encoding characters for this message. Exposed for composite parsers. @internal */
|
|
1867
1901
|
enc;
|
|
1868
1902
|
/** Position of this field in the parent message: used for position-aware error messages. @internal */
|
|
1869
1903
|
position;
|
|
1870
|
-
/** The full `RawField` this wrapper wraps. Exposed for composite parsers
|
|
1904
|
+
/** The full `RawField` this wrapper wraps. Exposed for composite parsers. @internal */
|
|
1871
1905
|
raw;
|
|
1872
1906
|
/**
|
|
1873
1907
|
* Construct a new `Field`. Called internally by `Segment.field(n)`; user
|
|
@@ -1884,7 +1918,7 @@ var Field = class {
|
|
|
1884
1918
|
/**
|
|
1885
1919
|
* First-repetition, first-component, first-subcomponent value as a decoded
|
|
1886
1920
|
* string: unescaped ONCE by the tokenizer on parse, returned verbatim here
|
|
1887
|
-
* (never re-unescaped
|
|
1921
|
+
* (never re-unescaped). Returns `""` when the field is
|
|
1888
1922
|
* empty or HL7 null. Equivalent to `msg.get('SEG.N')` for a top-level access.
|
|
1889
1923
|
*
|
|
1890
1924
|
* @example
|
|
@@ -1915,7 +1949,7 @@ var Field = class {
|
|
|
1915
1949
|
* vendor-quirk control id containing an unescaped delimiter (`ID^X`) must
|
|
1916
1950
|
* not be truncated to its first component.
|
|
1917
1951
|
*
|
|
1918
|
-
* **Byte-verbatim for parsed content
|
|
1952
|
+
* **Byte-verbatim for parsed content.** The parse pipeline stores
|
|
1919
1953
|
* *decoded* content, but also records the original wire bytes of any escape
|
|
1920
1954
|
* whose decode is not byte-faithful (`RawComponent.rawSubcomponents`), so
|
|
1921
1955
|
* re-serialization preserves the sender's exact escape bytes: hex escapes
|
|
@@ -2161,7 +2195,24 @@ var EMPTY_REP = Object.freeze({
|
|
|
2161
2195
|
|
|
2162
2196
|
// src/model/segment.ts
|
|
2163
2197
|
var Segment = class {
|
|
2164
|
-
/**
|
|
2198
|
+
/**
|
|
2199
|
+
* Segment identifier: three characters with a leading letter, e.g. `"PID"`,
|
|
2200
|
+
* `"OBX"`, `"ZPI"`.
|
|
2201
|
+
*
|
|
2202
|
+
* **Bounded, and it is `"<withheld>"` when the raw name is not that shape.**
|
|
2203
|
+
* A line with no field separator has its whole content read as a segment
|
|
2204
|
+
* name, so an unescaped line break inside a narrative field forges a
|
|
2205
|
+
* "segment" whose name is clinical text. This field presents itself as a
|
|
2206
|
+
* structural identifier and consumers interpolate it into labels, loci and
|
|
2207
|
+
* reports, so it never carries that text. `""` still means absent, which is
|
|
2208
|
+
* a different fact from withheld.
|
|
2209
|
+
*
|
|
2210
|
+
* Use {@link Segment.raw}`.name` when you need the verbatim text: it is the
|
|
2211
|
+
* unbounded value, and it is what serialization emits, so the byte-verbatim
|
|
2212
|
+
* round-trip is unaffected. One consequence worth knowing: a segment whose
|
|
2213
|
+
* raw name fails the shape (a 4-character vendor Z-segment, which HL7 v2
|
|
2214
|
+
* Ch. 2 §2.5 does not permit) is not matched by `msg.segments(name)`.
|
|
2215
|
+
*/
|
|
2165
2216
|
type;
|
|
2166
2217
|
/** Reference to the underlying `RawSegment.fields`: 1-indexed per HL7 convention. */
|
|
2167
2218
|
fields;
|
|
@@ -2169,7 +2220,7 @@ var Segment = class {
|
|
|
2169
2220
|
enc;
|
|
2170
2221
|
/** Absolute index of this segment in `Hl7Message.rawSegments[]`. Used for position tracking. @internal */
|
|
2171
2222
|
absoluteIndex;
|
|
2172
|
-
/** The full `RawSegment` this wrapper wraps. Exposed for mutation methods
|
|
2223
|
+
/** The full `RawSegment` this wrapper wraps. Exposed for mutation methods. @internal */
|
|
2173
2224
|
raw;
|
|
2174
2225
|
/**
|
|
2175
2226
|
* Lookup map from profile-declared field name → 1-indexed HL7 position.
|
|
@@ -2186,7 +2237,7 @@ var Segment = class {
|
|
|
2186
2237
|
* should obtain `Segment` instances via `msg.segments(type)` or
|
|
2187
2238
|
* `msg.allSegments()`.
|
|
2188
2239
|
*
|
|
2189
|
-
* The optional `customFields` parameter is the per-segment
|
|
2240
|
+
* The optional `customFields` parameter is the per-segment portion of the
|
|
2190
2241
|
* applied profile's merged `customSegments` map (PROF-07 / D-16). When
|
|
2191
2242
|
* supplied, `get(name)` resolves names against it; otherwise `get(name)`
|
|
2192
2243
|
* always returns `undefined`.
|
|
@@ -2194,7 +2245,7 @@ var Segment = class {
|
|
|
2194
2245
|
*/
|
|
2195
2246
|
constructor(raw, enc, absoluteIndex, customFields) {
|
|
2196
2247
|
this.raw = raw;
|
|
2197
|
-
this.type = raw.name;
|
|
2248
|
+
this.type = boundedIdentifier(raw.name, "segmentId");
|
|
2198
2249
|
this.fields = raw.fields;
|
|
2199
2250
|
this.enc = enc;
|
|
2200
2251
|
this.absoluteIndex = absoluteIndex;
|
|
@@ -3881,11 +3932,20 @@ var Hl7Message = class {
|
|
|
3881
3932
|
* Raw positional tree produced by the parser. 1-indexed per HL7 convention
|
|
3882
3933
|
* (`fields[0]` is the segment-name / MSH separator placeholder slot). Use
|
|
3883
3934
|
* `segments(type)` / `allSegments()` for typed wrapper access: this field
|
|
3884
|
-
* is exposed for advanced callers that need the raw tree directly
|
|
3885
|
-
* future serialization phase 5).
|
|
3935
|
+
* is exposed for advanced callers that need the raw tree directly.
|
|
3886
3936
|
*/
|
|
3887
3937
|
rawSegments;
|
|
3888
3938
|
encodingCharacters;
|
|
3939
|
+
/**
|
|
3940
|
+
* HL7 version the model asserts for this message, from MSH-12.1.1, e.g.
|
|
3941
|
+
* `"2.5"` or `"2.5.1"`.
|
|
3942
|
+
*
|
|
3943
|
+
* **Bounded, and it is `"<withheld>"` when MSH-12 does not hold a version.**
|
|
3944
|
+
* Same reasoning as {@link Segment.type}: it presents as an identifier and
|
|
3945
|
+
* consumers label with it. `meta.version` keeps MSH-12 exactly as it
|
|
3946
|
+
* arrived, and is what version-scoped field selection reads, so this bound
|
|
3947
|
+
* changes no parsing behaviour.
|
|
3948
|
+
*/
|
|
3889
3949
|
version;
|
|
3890
3950
|
warnings;
|
|
3891
3951
|
profile;
|
|
@@ -3898,7 +3958,7 @@ var Hl7Message = class {
|
|
|
3898
3958
|
dateFormats;
|
|
3899
3959
|
/**
|
|
3900
3960
|
* Merged `customSegments` map from the applied profile, stored so
|
|
3901
|
-
* `allSegments()` can hand per-segment
|
|
3961
|
+
* `allSegments()` can hand per-segment portions to `Segment` constructors
|
|
3902
3962
|
* (D-16). Undefined when no profile was applied.
|
|
3903
3963
|
* @internal
|
|
3904
3964
|
*/
|
|
@@ -3907,40 +3967,40 @@ var Hl7Message = class {
|
|
|
3907
3967
|
* Lazily built cache of Segment wrappers keyed by segment type. Built on
|
|
3908
3968
|
* first `segments(type)` call and filtered from `_allSegments` so
|
|
3909
3969
|
* individual Segment instances are identical across both caches (D-11).
|
|
3910
|
-
*
|
|
3970
|
+
* The mutation methods drop this cache wholesale.
|
|
3911
3971
|
* @internal
|
|
3912
3972
|
*/
|
|
3913
3973
|
_segmentsByType;
|
|
3914
3974
|
/**
|
|
3915
3975
|
* Lazily built cache of every Segment wrapper in document order. Built on
|
|
3916
|
-
* first `segments(type)` / `allSegments()` call.
|
|
3976
|
+
* first `segments(type)` / `allSegments()` call. The mutation methods
|
|
3917
3977
|
* drop this cache wholesale.
|
|
3918
3978
|
* @internal
|
|
3919
3979
|
*/
|
|
3920
3980
|
_allSegments;
|
|
3921
3981
|
/**
|
|
3922
|
-
* Lazily built `Meta` view (
|
|
3982
|
+
* Lazily built `Meta` view (memoized). Dropped wholesale
|
|
3923
3983
|
* by `invalidateCaches`. `Meta` is always defined (D-03: MSH absence
|
|
3924
3984
|
* throws `NO_MSH_SEGMENT` at parse time) so no null-sentinel is needed.
|
|
3925
3985
|
* @internal
|
|
3926
3986
|
*/
|
|
3927
3987
|
_meta;
|
|
3928
3988
|
/**
|
|
3929
|
-
* Lazily built `MessageStructure` view
|
|
3989
|
+
* Lazily built `MessageStructure` view. Dropped wholesale by
|
|
3930
3990
|
* `invalidateCaches`. Always defined: `analyzeMessageStructure` returns an
|
|
3931
3991
|
* `recognized: false` summary for unmodelled types rather than absence.
|
|
3932
3992
|
* @internal
|
|
3933
3993
|
*/
|
|
3934
3994
|
_structure;
|
|
3935
3995
|
/**
|
|
3936
|
-
* Lazily built `Patient | undefined` view (
|
|
3996
|
+
* Lazily built `Patient | undefined` view (memoized). Uses
|
|
3937
3997
|
* a null-sentinel cache because `undefined` means "not yet computed" while
|
|
3938
3998
|
* `null` means "computed, absent". D-04: no PID → public value `undefined`.
|
|
3939
3999
|
* @internal
|
|
3940
4000
|
*/
|
|
3941
4001
|
_patient;
|
|
3942
4002
|
/**
|
|
3943
|
-
* Lazily built `Visit | undefined` view (
|
|
4003
|
+
* Lazily built `Visit | undefined` view (memoized). Same
|
|
3944
4004
|
* null-sentinel convention as `_patient`. HELPERS-03: no PV1 → public
|
|
3945
4005
|
* value `undefined`.
|
|
3946
4006
|
* @internal
|
|
@@ -3956,7 +4016,7 @@ var Hl7Message = class {
|
|
|
3956
4016
|
constructor(init) {
|
|
3957
4017
|
this.rawSegments = init.segments;
|
|
3958
4018
|
this.encodingCharacters = init.encodingCharacters;
|
|
3959
|
-
this.version = init.version;
|
|
4019
|
+
this.version = boundedIdentifier(init.version, "version");
|
|
3960
4020
|
this.warnings = Object.freeze(init.warnings.slice());
|
|
3961
4021
|
this.profile = init.profile;
|
|
3962
4022
|
if (init.customSegments !== void 0) this._customSegments = init.customSegments;
|
|
@@ -3964,8 +4024,8 @@ var Hl7Message = class {
|
|
|
3964
4024
|
}
|
|
3965
4025
|
/**
|
|
3966
4026
|
* Resolve a dot-path (e.g. `PID.5.1`, `OBX[2].5`, `PID.3[0].1`) to its
|
|
3967
|
-
* decoded leaf string (unescaped once at parse: never re-unescaped on
|
|
3968
|
-
*
|
|
4027
|
+
* decoded leaf string (unescaped once at parse: never re-unescaped on
|
|
4028
|
+
* read). Returns `undefined` when the path doesn't
|
|
3969
4029
|
* resolve: never throws on missing path (MODEL-05). Throws `TypeError`
|
|
3970
4030
|
* on malformed path syntax (e.g. `"pid.5"`, empty string).
|
|
3971
4031
|
*
|
|
@@ -4000,7 +4060,7 @@ var Hl7Message = class {
|
|
|
4000
4060
|
* Return the cached array of `Segment` wrappers for `segmentType` in
|
|
4001
4061
|
* document order. The returned array identity and the individual Segment
|
|
4002
4062
|
* instances are both stable across calls (D-11). Invalidated wholesale
|
|
4003
|
-
* by
|
|
4063
|
+
* by the mutation methods.
|
|
4004
4064
|
*
|
|
4005
4065
|
* @example
|
|
4006
4066
|
* ```ts
|
|
@@ -4023,7 +4083,7 @@ var Hl7Message = class {
|
|
|
4023
4083
|
* Iterate every `Segment` in document order (MSH first, then every
|
|
4024
4084
|
* subsequent segment). Cached per-message; same array reference and same
|
|
4025
4085
|
* Segment instances on repeat calls (D-11). Invalidated wholesale by
|
|
4026
|
-
*
|
|
4086
|
+
* the mutation methods.
|
|
4027
4087
|
*
|
|
4028
4088
|
* @example
|
|
4029
4089
|
* ```ts
|
|
@@ -4057,7 +4117,7 @@ var Hl7Message = class {
|
|
|
4057
4117
|
* @example
|
|
4058
4118
|
* ```ts
|
|
4059
4119
|
* console.log(msg.meta.type); // "ADT^A01"
|
|
4060
|
-
* console.log(msg.meta.timestamp?.raw); // fidelity TS
|
|
4120
|
+
* console.log(msg.meta.timestamp?.raw); // fidelity TS
|
|
4061
4121
|
* console.log(msg.meta.controlId); // "MSG001"
|
|
4062
4122
|
* ```
|
|
4063
4123
|
*/
|
|
@@ -4065,8 +4125,8 @@ var Hl7Message = class {
|
|
|
4065
4125
|
return this._meta ??= buildMeta(this);
|
|
4066
4126
|
}
|
|
4067
4127
|
/**
|
|
4068
|
-
* Structural-conformance summary for the common message types
|
|
4069
|
-
*
|
|
4128
|
+
* Structural-conformance summary for the common message types: a
|
|
4129
|
+
* misroute/truncation safety net, NOT a conformance validator.
|
|
4070
4130
|
* Reports, per the message's recognized (MSH-9.1, MSH-9.2) type, which
|
|
4071
4131
|
* Required segment groups are present and which are entirely absent
|
|
4072
4132
|
* (`missingGroups`: the same set the parser flags as
|
|
@@ -4134,7 +4194,7 @@ var Hl7Message = class {
|
|
|
4134
4194
|
}
|
|
4135
4195
|
/**
|
|
4136
4196
|
* Every OBR as an Order with its OBX children grouped positionally (D-12) and
|
|
4137
|
-
* its TQ1 / legacy embedded-TQ (ORC-7) `timings` (
|
|
4197
|
+
* its TQ1 / legacy embedded-TQ (ORC-7) `timings` (the repeat pattern is
|
|
4138
4198
|
* surfaced verbatim, never resolved to a schedule). D-05: returns `[]` when no
|
|
4139
4199
|
* OBR present. D-06: not memoized.
|
|
4140
4200
|
*
|
|
@@ -4150,7 +4210,7 @@ var Hl7Message = class {
|
|
|
4150
4210
|
return orders(this);
|
|
4151
4211
|
}
|
|
4152
4212
|
/**
|
|
4153
|
-
* Message-level NTE notes
|
|
4213
|
+
* Message-level NTE notes: every NTE segment with no recognized
|
|
4154
4214
|
* preceding parent (not immediately following a `PID`, `ORC`, `OBR`, or
|
|
4155
4215
|
* `OBX`), surfaced verbatim in document order so nothing is dropped. Notes
|
|
4156
4216
|
* that DO attach to a specific patient / order / result are exposed on those
|
|
@@ -4167,7 +4227,7 @@ var Hl7Message = class {
|
|
|
4167
4227
|
}
|
|
4168
4228
|
/**
|
|
4169
4229
|
* Every recognized ADT patient-identity event (merge / move / link /
|
|
4170
|
-
* unlink / person add/update
|
|
4230
|
+
* unlink / person add/update), with the MRG-sourced
|
|
4171
4231
|
* `prior` and PID/PV1-sourced `surviving` parties labelled by role and the
|
|
4172
4232
|
* spec-constant `direction: "MRG_TO_PID"` on merge/move events. Returns
|
|
4173
4233
|
* `[]` when the trigger event is not in the identity family. D-06: not
|
|
@@ -4188,13 +4248,13 @@ var Hl7Message = class {
|
|
|
4188
4248
|
}
|
|
4189
4249
|
/**
|
|
4190
4250
|
* Every RXO/RXE/RXD/RXA as a typed `Medication`, with RXR (route) and RXC
|
|
4191
|
-
* (component) segments grouped positionally under their parent
|
|
4192
|
-
*
|
|
4193
|
-
*
|
|
4194
|
-
*
|
|
4251
|
+
* (component) segments grouped positionally under their parent. D-05:
|
|
4252
|
+
* returns `[]` when no RX* parent present. D-06: not memoized. The give
|
|
4253
|
+
* *amount* and give *strength* are surfaced separately and never
|
|
4254
|
+
* reconciled.
|
|
4195
4255
|
*
|
|
4196
4256
|
* Each medication also carries its TQ1 / legacy embedded-TQ (RXE-1) `timings`
|
|
4197
|
-
* (
|
|
4257
|
+
* (repeat pattern verbatim, never resolved to a schedule).
|
|
4198
4258
|
*
|
|
4199
4259
|
* @example
|
|
4200
4260
|
* ```ts
|
|
@@ -4211,7 +4271,7 @@ var Hl7Message = class {
|
|
|
4211
4271
|
/**
|
|
4212
4272
|
* Every RXA of a VXU^V04 as a typed `Immunization`, with RXR (route/site)
|
|
4213
4273
|
* and OBX children grouped positionally under the RXA and `orderControl`
|
|
4214
|
-
* from the preceding ORC of the VXU order group
|
|
4274
|
+
* from the preceding ORC of the VXU order group. D-05:
|
|
4215
4275
|
* returns `[]` when no RXA present. D-06: not memoized. The vaccine code
|
|
4216
4276
|
* carries its own provenance; the action code (RXA-21) is surfaced verbatim
|
|
4217
4277
|
* and `recordOrigin` (administered vs historical) is derived only from the
|
|
@@ -4279,7 +4339,7 @@ var Hl7Message = class {
|
|
|
4279
4339
|
return insurance(this);
|
|
4280
4340
|
}
|
|
4281
4341
|
/**
|
|
4282
|
-
* Every SCH of an SIU message as a typed `Appointment
|
|
4342
|
+
* Every SCH of an SIU message as a typed `Appointment`, with
|
|
4283
4343
|
* the AIS/AIG/AIL/AIP resource segments that follow it grouped positionally
|
|
4284
4344
|
* under that SCH. Surfaces the placer/filler appointment ids, SCH-25 filler
|
|
4285
4345
|
* status (Table 0278), SCH-11 start/end timing, and the resource groups
|
|
@@ -4299,7 +4359,7 @@ var Hl7Message = class {
|
|
|
4299
4359
|
return appointments(this);
|
|
4300
4360
|
}
|
|
4301
4361
|
/**
|
|
4302
|
-
* Every TXA of an MDM message as a typed `ClinicalDocument
|
|
4362
|
+
* Every TXA of an MDM message as a typed `ClinicalDocument`,
|
|
4303
4363
|
* with the OBX narrative body grouped positionally under that TXA. The
|
|
4304
4364
|
* completion status (TXA-17) and availability status (TXA-19) are surfaced as
|
|
4305
4365
|
* **distinct** fields and never conflated: a document can be available before
|
|
@@ -4319,7 +4379,7 @@ var Hl7Message = class {
|
|
|
4319
4379
|
return documents(this);
|
|
4320
4380
|
}
|
|
4321
4381
|
/**
|
|
4322
|
-
* Every FT1 of a DFT message as a typed `Charge
|
|
4382
|
+
* Every FT1 of a DFT message as a typed `Charge`, one per
|
|
4323
4383
|
* FT1 in document order. Surfaces billing-critical fields (FT1-6 transaction
|
|
4324
4384
|
* type, FT1-7 code, FT1-11/12 extended/unit amount, FT1-19 diagnosis linkage)
|
|
4325
4385
|
* with **no billing logic and no money-as-float**: amounts are the verbatim
|
|
@@ -4413,7 +4473,7 @@ var Hl7Message = class {
|
|
|
4413
4473
|
* `TypeError` with an actionable message otherwise).
|
|
4414
4474
|
*
|
|
4415
4475
|
* The value is accepted verbatim: unescaped delimiter characters are NOT
|
|
4416
|
-
* rejected on input (D-18). Re-escaping
|
|
4476
|
+
* rejected on input (D-18). Re-escaping is the serializer's concern.
|
|
4417
4477
|
*
|
|
4418
4478
|
* MSH-1 / MSH-2 follow the user-facing HL7 convention: `setField("MSH.3", ...)`
|
|
4419
4479
|
* targets MSH-3 (sending application), matching `msg.get("MSH.3")`.
|
|
@@ -4499,11 +4559,11 @@ var Hl7Message = class {
|
|
|
4499
4559
|
return this;
|
|
4500
4560
|
}
|
|
4501
4561
|
/**
|
|
4502
|
-
* Set a **typed composite** at a field (or field-repetition) dot-path
|
|
4503
|
-
*
|
|
4562
|
+
* Set a **typed composite** at a field (or field-repetition) dot-path:
|
|
4563
|
+
* the conservative-emit mirror of the typed read accessors
|
|
4504
4564
|
* (`asXpn`/`asCx`/…). The caller passes a structured value (an XPN name, a CX
|
|
4505
4565
|
* identifier, a TS timestamp, …) by its {@link CompositeKind}, and the setter
|
|
4506
|
-
* encodes it into a spec-clean field using the
|
|
4566
|
+
* encodes it into a spec-clean field using the encode-safe path: any
|
|
4507
4567
|
* delimiter embedded in a component value is **escaped, never injected**, so
|
|
4508
4568
|
* a `familyName` of `"Smith^Jr"` re-parses to exactly that string rather than
|
|
4509
4569
|
* forging a component boundary. No hand-assembly of `^`/`&`/`~`.
|
|
@@ -4694,8 +4754,8 @@ var Hl7Message = class {
|
|
|
4694
4754
|
return this;
|
|
4695
4755
|
}
|
|
4696
4756
|
/**
|
|
4697
|
-
* Drop every wrapper AND helper cache wholesale (
|
|
4698
|
-
*
|
|
4757
|
+
* Drop every wrapper AND helper cache wholesale (D-17 + D-02). Called by
|
|
4758
|
+
* every mutation method so subsequent `segments(type)` /
|
|
4699
4759
|
* `allSegments()` / `meta` / `patient` / `visit` reads rebuild from the
|
|
4700
4760
|
* mutated `rawSegments` tree.
|
|
4701
4761
|
* @internal
|
|
@@ -4794,7 +4854,12 @@ function resolveBufferCharset(raw, options, emit) {
|
|
|
4794
4854
|
emit(
|
|
4795
4855
|
encodingMismatch(
|
|
4796
4856
|
{ segmentIndex: 0 },
|
|
4797
|
-
`
|
|
4857
|
+
// `declared` is MSH-18 read off the wire. On a message with no
|
|
4858
|
+
// segment terminators it is not MSH-18 at all but the 18th
|
|
4859
|
+
// `|`-token of the flattened message, commonly a data field, so it
|
|
4860
|
+
// is shape-checked before it reaches a log surface. `override` is
|
|
4861
|
+
// the caller's own `options.charset`, not input, and is left alone.
|
|
4862
|
+
`options.charset="${override}" disagrees with MSH-18="${safeCharsetLabel(declared)}"`
|
|
4798
4863
|
)
|
|
4799
4864
|
);
|
|
4800
4865
|
}
|
|
@@ -6809,7 +6874,7 @@ async function* parseStream(source, optionsOrProfile) {
|
|
|
6809
6874
|
}
|
|
6810
6875
|
|
|
6811
6876
|
// src/index.ts
|
|
6812
|
-
var VERSION = "0.0.
|
|
6877
|
+
var VERSION = "0.0.4";
|
|
6813
6878
|
|
|
6814
6879
|
exports.ACK_CODES = ACK_CODES;
|
|
6815
6880
|
exports.ACK_CONDITIONS = ACK_CONDITIONS;
|