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