@cosyte/hl7 0.0.1 → 0.0.2

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.d.cts CHANGED
@@ -11,7 +11,7 @@ import { Buffer } from 'node:buffer';
11
11
  /**
12
12
  * Stable string codes for every Tier-2 warning the parser may emit. The
13
13
  * registry is frozen via `as const` so TypeScript infers the exact string
14
- * literal union for `WarningCode` — there is zero runtime cost and no
14
+ * literal union for `WarningCode`: there is zero runtime cost and no
15
15
  * magic-string comparisons for consumers.
16
16
  *
17
17
  * @example
@@ -43,6 +43,7 @@ declare const WARNING_CODES: {
43
43
  readonly MERGE_MISSING_PRIOR_OR_SURVIVOR: "MERGE_MISSING_PRIOR_OR_SURVIVOR";
44
44
  readonly BATCH_COUNT_MISMATCH: "BATCH_COUNT_MISMATCH";
45
45
  readonly BATCH_MISSING_TRAILER: "BATCH_MISSING_TRAILER";
46
+ readonly UNTERMINATED_STREAM_MESSAGE: "UNTERMINATED_STREAM_MESSAGE";
46
47
  };
47
48
  /**
48
49
  * Discriminant type for `Hl7ParseWarning.code`. Narrowing a warning by this
@@ -102,8 +103,8 @@ declare function mllpFramingStripped(position: Hl7Position): Hl7ParseWarning;
102
103
  * Build a `FIELD_WHITESPACE_TRIMMED` warning. Emitted when the parser trims
103
104
  * leading or trailing whitespace from a field value (the `trimFields`
104
105
  * option, on by default). The message carries only the leading/trailing
105
- * character **counts** — NEVER the field value itself (before or after
106
- * trimming) — so no PHI is exposed; the trimmed value is still preserved
106
+ * character **counts**: NEVER the field value itself (before or after
107
+ * trimming): so no PHI is exposed; the trimmed value is still preserved
107
108
  * verbatim in the parsed output.
108
109
  *
109
110
  * @example
@@ -116,12 +117,12 @@ declare function fieldWhitespaceTrimmed(position: Hl7Position, leadingCount: num
116
117
  /**
117
118
  * Build an `UNKNOWN_ESCAPE_SEQUENCE` warning for a **terminated** escape
118
119
  * sequence (`\..\`) whose body is not a recognized HL7 escape. The message
119
- * NEVER embeds the escape body — only its length and, when the body's first
120
+ * NEVER embeds the escape body: only its length and, when the body's first
120
121
  * character is a recognized HL7 escape-identifier letter (structural HL7
121
- * grammar, not PHI — e.g. `Z` for a vendor escape, `.` for a formatting
122
+ * grammar, not PHI: e.g. `Z` for a vendor escape, `.` for a formatting
122
123
  * escape), that single letter. A body that doesn't start with a known escape
123
124
  * letter is untrusted field text and names no character at all. The sequence
124
- * itself is still preserved verbatim in the parsed output — only the WARNING
125
+ * itself is still preserved verbatim in the parsed output: only the WARNING
125
126
  * message is PHI-safe.
126
127
  *
127
128
  * @example
@@ -137,7 +138,7 @@ declare function unknownEscapeSequence(position: Hl7Position, body: string): Hl7
137
138
  * (an escape character with no closing partner before end-of-input). The
138
139
  * "body" in this case is the entire remainder of the field, so the message
139
140
  * carries NEITHER the body NOR its length (the length of a truncated tail is
140
- * itself derivable field-shape information) — just the fact that an
141
+ * itself derivable field-shape information): just the fact that an
141
142
  * unterminated escape was found, and the position. The remainder is still
142
143
  * preserved verbatim in the parsed output.
143
144
  *
@@ -179,7 +180,7 @@ declare function timestampFallbackFormat(position: Hl7Position, matchedFormat: s
179
180
  declare function segmentCase(position: Hl7Position, observed: string): Hl7ParseWarning;
180
181
  /**
181
182
  * Build an `EXTRA_FIELDS` warning. Emitted when a segment contains more
182
- * fields than the profile definition (or HL7 spec) declares — the extras
183
+ * fields than the profile definition (or HL7 spec) declares: the extras
183
184
  * are preserved on `RawSegment.fields` but flagged for consumers.
184
185
  *
185
186
  * @example
@@ -243,10 +244,10 @@ declare function missingRequiredField(position: Hl7Position, segmentName: string
243
244
  * Build a `MISSING_EXPECTED_GROUP` warning (roadmap Phase G). Emitted once per
244
245
  * absent Required segment group when the message's (MSH-9.1, MSH-9.2) type is
245
246
  * one the structure safety net recognizes and an expected group is entirely
246
- * missing — e.g. an `ORU^R01` carrying no `OBR`/`OBX` result group, the
247
+ * missing: e.g. an `ORU^R01` carrying no `OBR`/`OBX` result group, the
247
248
  * signature of a truncated or misrouted feed. Tier-2 and additive: lenient
248
249
  * parse never throws on it, `strict` mode may promote it. The message carries
249
- * only the structural fact (message type, group name, anchor segment names) —
250
+ * only the structural fact (message type, group name, anchor segment names),
250
251
  * NEVER a field value, so no PHI is exposed. `position` references MSH-9.
251
252
  *
252
253
  * @example
@@ -291,7 +292,7 @@ declare function versionMismatch(position: Hl7Position, declared: string, expect
291
292
  * Table-0211 character set**. The parser never guesses an encoding: it reads the
292
293
  * raw bytes as `latin1` (a 1:1 byte mapping) so single-byte content stays
293
294
  * recoverable, rather than corrupting it with replacement characters. The
294
- * message carries the charset code only — never a decoded field value — so no
295
+ * message carries the charset code only, never a decoded field value, so no
295
296
  * PHI is exposed.
296
297
  *
297
298
  * @example
@@ -303,18 +304,18 @@ declare function versionMismatch(position: Hl7Position, declared: string, expect
303
304
  declare function unknownCharset(position: Hl7Position, requested: string): Hl7ParseWarning;
304
305
  /**
305
306
  * Build an `UNSUPPORTED_CHARSET` warning. Emitted when a **recognized**
306
- * Table-0211 character set is not decoded into text — either because this parser
307
- * does not decode it (the multibyte / ISO-2022-switched East-Asian sets — JIS,
308
- * GB 18030, KS X 1001, CNS 11643, BIG-5 — and the wide Unicode transforms
307
+ * Table-0211 character set is not decoded into text: either because this parser
308
+ * does not decode it (the multibyte / ISO-2022-switched East-Asian sets: JIS,
309
+ * GB 18030, KS X 1001, CNS 11643, BIG-5: and the wide Unicode transforms
309
310
  * UTF-16 / UTF-32), or because a strict decode of a decodable set **failed** (a
310
311
  * byte invalid / undefined for the declared set, or an ICU build lacking the
311
312
  * label). In every case the raw bytes are read as `latin1`, never guessed at, so
312
313
  * the parser does not emit replacement-char-corrupted text. Single-byte content
313
314
  * stays byte-recoverable; multibyte content is best-effort (a content byte can
314
- * coincide with a structural delimiter — see the parser's known-limitations).
315
+ * coincide with a structural delimiter: see the parser's known-limitations).
315
316
  * The switch escapes (`\Cxxyy\` / `\Mxxyyzz\`) are recognized and preserved by
316
317
  * the escape layer; full stateful decoding is a documented non-goal. The message
317
- * carries the charset code only — never a decoded field value — so no PHI is
318
+ * carries the charset code only, never a decoded field value, so no PHI is
318
319
  * exposed.
319
320
  *
320
321
  * @example
@@ -330,7 +331,7 @@ declare function unsupportedCharset(position: Hl7Position, code: string): Hl7Par
330
331
  * so the generated ACK leaves MSA-2 empty and, when a positive accept was
331
332
  * requested, downgrades it to an error code rather than fabricating an
332
333
  * unverifiable `AA`/`CA`. The `position` references the inbound MSH segment.
333
- * The message NEVER echoes a PHI value — only the structural fact.
334
+ * The message NEVER echoes a PHI value: only the structural fact.
334
335
  *
335
336
  * @example
336
337
  * ```ts
@@ -342,20 +343,20 @@ declare function unsupportedCharset(position: Hl7Position, code: string): Hl7Par
342
343
  declare function ackNoCorrelationId(position: Hl7Position): Hl7ParseWarning;
343
344
  /**
344
345
  * Build a `MERGE_MISSING_PRIOR_OR_SURVIVOR` warning (roadmap Phase K). Emitted
345
- * by `identityEvents()` (a read-side helper — it attaches to the returned
346
+ * by `identityEvents()` (a read-side helper: it attaches to the returned
346
347
  * `IdentityEvent.warnings`, never to `Hl7Message.warnings`) when a merge/move
347
348
  * trigger event (A18/A34/A35/A36/A39/A40/A41/A42/A43/A44) is missing one side
348
- * of the spec-mandated MRG (prior) → PID (surviving) pair — or when that side
349
+ * of the spec-mandated MRG (prior) → PID (surviving) pair: or when that side
349
350
  * carries no usable identity field: no MRG segment in the patient group, no
350
351
  * PID for an orphaned MRG, or a PID/MRG whose identifier, account, and visit
351
352
  * fields are all empty or version-gated (a v2.7+ MRG whose only content was
352
353
  * the withdrawn MRG-4 must not read as "nothing to retire"). The helper
353
354
  * surfaces whatever IS present and never
354
- * guesses the merge direction — this warning is the signal that the pair is
355
+ * guesses the merge direction: this warning is the signal that the pair is
355
356
  * incomplete.
356
357
  *
357
358
  * The message carries only the structural facts (trigger event code + which
358
- * role is missing) — NEVER an identifier, name, or any other field value, so
359
+ * role is missing): NEVER an identifier, name, or any other field value, so
359
360
  * no PHI is exposed (HL7 v2 Ch. 3: the PID carries surviving and the MRG
360
361
  * carries non-surviving identity information).
361
362
  *
@@ -368,18 +369,18 @@ declare function ackNoCorrelationId(position: Hl7Position): Hl7ParseWarning;
368
369
  declare function mergeMissingPriorOrSurvivor(position: Hl7Position, eventType: string, missing: "prior" | "survivor"): Hl7ParseWarning;
369
370
  /**
370
371
  * Build a `BATCH_COUNT_MISMATCH` warning (roadmap Phase L). Emitted by
371
- * `splitBatch()` — attached to the returned `BatchSplitResult.warnings`, never
372
- * to `Hl7Message.warnings` — when a declared envelope count does not equal the
372
+ * `splitBatch()`: attached to the returned `BatchSplitResult.warnings`, never
373
+ * to `Hl7Message.warnings`: when a declared envelope count does not equal the
373
374
  * count actually split out: a **BTS-1** batch message count that differs from
374
375
  * the messages found in that batch, or an **FTS-1** file batch count that
375
376
  * differs from the batches found in the file (HL7 v2 Ch. 2 §2.10.3; BTS-1 / FTS-1
376
377
  * per the BTS / FTS segment definitions in §2.15).
377
- * The splitter **never drops the tail** to make the numbers agree — the
378
+ * The splitter **never drops the tail** to make the numbers agree: the
378
379
  * mismatch is surfaced and every message is still returned; the caller decides
379
380
  * whether to reject.
380
381
  *
381
382
  * The message carries only the declared-vs-actual **integers** and the unit
382
- * (`message` for BTS-1, `batch` for FTS-1) — NEVER a field value, facility
383
+ * (`message` for BTS-1, `batch` for FTS-1): NEVER a field value, facility
383
384
  * identifier, or any other content, so no PHI is exposed. `position` references
384
385
  * the trailer segment (`BTS`/`FTS`) that declared the count.
385
386
  *
@@ -392,15 +393,15 @@ declare function mergeMissingPriorOrSurvivor(position: Hl7Position, eventType: s
392
393
  declare function batchCountMismatch(position: Hl7Position, unit: "message" | "batch", declared: number, actual: number): Hl7ParseWarning;
393
394
  /**
394
395
  * Build a `BATCH_MISSING_TRAILER` warning (roadmap Phase L). Emitted by
395
- * `splitBatch()` — attached to `BatchSplitResult.warnings` — when an envelope
396
+ * `splitBatch()` (attached to `BatchSplitResult.warnings`) when an envelope
396
397
  * header opens a scope that is never closed: a **BHS** batch header with no
397
398
  * matching **BTS** trailer, or an **FHS** file header with no matching **FTS**
398
- * trailer (HL7 v2 Ch. 2 §2.10.3 — each envelope segment is optional, but a
399
+ * trailer (HL7 v2 Ch. 2 §2.10.3: each envelope segment is optional, but a
399
400
  * profile such as an IIS file-submission spec may mandate the full frame).
400
- * `splitBatch` **does not enforce** such a rule — it splits, warns, and leaves
401
+ * `splitBatch` **does not enforce** such a rule: it splits, warns, and leaves
401
402
  * the accept/reject decision to the caller; the parse never throws for this.
402
403
  *
403
- * The message carries only the header/trailer segment names — NEVER a field
404
+ * The message carries only the header/trailer segment names: NEVER a field
404
405
  * value, so no PHI is exposed. `position` references the unmatched header
405
406
  * segment (`FHS`/`BHS`).
406
407
  *
@@ -411,13 +412,34 @@ declare function batchCountMismatch(position: Hl7Position, unit: "message" | "ba
411
412
  * ```
412
413
  */
413
414
  declare function batchMissingTrailer(position: Hl7Position, header: "FHS" | "BHS", expectedTrailer: "FTS" | "BTS"): Hl7ParseWarning;
415
+ /**
416
+ * Build an `UNTERMINATED_STREAM_MESSAGE` warning (roadmap Phase S). Emitted by
417
+ * `parseStream()`: attached to a {@link StreamMessageEntry}'s `streamWarnings`,
418
+ * NOT to `Hl7Message.warnings`: when the **final** message in a stream ends
419
+ * without a segment terminator (its last segment ran to end-of-stream with no
420
+ * trailing `\r`/`\r\n`/`\n`). The message is still parsed and yielded **in
421
+ * full**; this is the fail-safe signal that the tail may have been truncated
422
+ * mid-message (a cut-off feed), never a reason to drop it and never a throw.
423
+ * Only the last message can be unterminated: every earlier message is closed by
424
+ * the terminator that precedes the next `MSH`/envelope boundary.
425
+ *
426
+ * The message carries only the structural fact, NEVER a field value, so no PHI
427
+ * is exposed. `position` references the message's `MSH` segment index.
428
+ *
429
+ * @example
430
+ * ```ts
431
+ * import { unterminatedStreamMessage } from "@cosyte/hl7";
432
+ * const w = unterminatedStreamMessage({ segmentIndex: 6 });
433
+ * ```
434
+ */
435
+ declare function unterminatedStreamMessage(position: Hl7Position): Hl7ParseWarning;
414
436
 
415
437
  /**
416
438
  * Shared type definitions consumed across the `@cosyte/hl7` parser
417
439
  * pipeline. These types are contracts between parser stages (normalize,
418
440
  * mllp, segments, delimiters, tokenize) and the `Hl7Message` model shell.
419
441
  *
420
- * Every type here is deliberately readonly — the parser produces immutable
442
+ * Every type here is deliberately readonly: the parser produces immutable
421
443
  * data structures and consumers must not mutate them. Narrowing is done via
422
444
  * the `Hl7ParseWarning.code` and `Hl7ParseError.code` discriminants defined
423
445
  * in sibling files.
@@ -426,14 +448,14 @@ declare function batchMissingTrailer(position: Hl7Position, header: "FHS" | "BHS
426
448
  /**
427
449
  * Positional context attached to every warning and fatal error. Fields are
428
450
  * 1-indexed against the HL7 spec convention (see `RawSegment.fields` for the
429
- * index 0 slot convention). All fields past `segmentIndex` are optional —
451
+ * index 0 slot convention). All fields past `segmentIndex` are optional,
430
452
  * for a top-level fatal like `EMPTY_INPUT` only `segmentIndex: 0` is
431
453
  * populated; for a tokenizer warning deep inside a subcomponent all five
432
454
  * indices may be set.
433
455
  *
434
456
  * @remarks
435
457
  * With `exactOptionalPropertyTypes: true`, do not pass `fieldIndex: undefined`
436
- * explicitly — omit the key instead.
458
+ * explicitly: omit the key instead.
437
459
  *
438
460
  * @example
439
461
  * ```ts
@@ -470,7 +492,7 @@ type OnWarningCallback = (warning: Hl7ParseWarning) => void;
470
492
  *
471
493
  * @remarks
472
494
  * With `exactOptionalPropertyTypes: true`, callers cannot pass
473
- * `{ strict: undefined }` — either omit the key or pass a boolean. The
495
+ * `{ strict: undefined }`: either omit the key or pass a boolean. The
474
496
  * `profile: null` form is the explicit opt-out from the process-scoped
475
497
  * default profile (PROF-08 semantics); `profile` omitted means "use the
476
498
  * default if one is registered".
@@ -531,14 +553,14 @@ interface CustomSegmentDefinition {
531
553
  /**
532
554
  * Structural placeholder for HL7 profiles. A profile bundles vendor-specific
533
555
  * tolerances, date formats, custom segment definitions, and optional
534
- * callbacks. Phase 2 ships only the type — the `defineProfile()` builder
556
+ * callbacks. Phase 2 ships only the type: the `defineProfile()` builder
535
557
  * and runtime effects land in Phase 6.
536
558
  *
537
559
  * Phase 6 Plan 01 tightens `customSegments` to the locked
538
560
  * `CustomSegmentDefinition` shape and adds an optional `describe?` method
539
561
  * so `defineProfile()`-produced profiles can be introspected without
540
562
  * consumers needing to narrow away from the `Profile` type. The `describe`
541
- * method is only populated by `defineProfile()` — hand-authored `Profile`
563
+ * method is only populated by `defineProfile()`: hand-authored `Profile`
542
564
  * objects may omit it.
543
565
  *
544
566
  * @example
@@ -565,8 +587,8 @@ interface Profile {
565
587
  }
566
588
  /**
567
589
  * The HL7 delimiter characters discovered from MSH-1 (field separator) and
568
- * MSH-2 (encoding characters). The first four — component, repetition,
569
- * escape, subcomponent — are mandatory across all HL7 v2 versions. The fifth,
590
+ * MSH-2 (encoding characters). The first four: component, repetition,
591
+ * escape, subcomponent: are mandatory across all HL7 v2 versions. The fifth,
570
592
  * `truncation`, is the v2.7+ truncation character (default `#` per spec
571
593
  * §2.5.5.2): only present when MSH-2 actually carries 5 encoding characters,
572
594
  * so messages that pre-date v2.7 round-trip with a 4-char MSH-2 unchanged.
@@ -593,7 +615,7 @@ interface EncodingCharacters {
593
615
  readonly truncation?: string;
594
616
  }
595
617
  /**
596
- * A single component inside a repetition — the most deeply nested data
618
+ * A single component inside a repetition: the most deeply nested data
597
619
  * layer in the HL7 positional tree. A component is an ordered list of
598
620
  * subcomponent strings (subcomponent separator `&` by default).
599
621
  *
@@ -605,7 +627,7 @@ interface EncodingCharacters {
605
627
  */
606
628
  interface RawComponent {
607
629
  /**
608
- * The component's subcomponents, **HL7-decoded** — the tokenizer expands
630
+ * The component's subcomponents, **HL7-decoded**: the tokenizer expands
609
631
  * escape sequences on parse so consumers read literal values (`Smith|Jones`,
610
632
  * not `Smith\F\Jones`). This is the value surface every reader uses
611
633
  * (`Field.value`, the composite parsers, dot-path, `toJSON`).
@@ -616,7 +638,7 @@ interface RawComponent {
616
638
  * for each index, the subcomponent's **original wire bytes** to emit
617
639
  * verbatim instead of re-escaping the decoded form. An entry is present
618
640
  * (non-`undefined`) only when a subcomponent carried an escape whose decoded
619
- * form does not re-escape back to the exact wire bytes — i.e. a recognize-
641
+ * form does not re-escape back to the exact wire bytes: i.e. a recognize-
620
642
  * and-preserve escape (`\H\`, `\Z..\`, charset/formatting) or a hex escape
621
643
  * (`\X41\`, or non-canonical hex casing). Delimiter escapes (`\F\`→`|`) round-
622
644
  * trip through `reescape` unchanged and get no overlay. The whole field is
@@ -632,7 +654,7 @@ interface RawComponent {
632
654
  readonly rawSubcomponents?: readonly (string | undefined)[];
633
655
  }
634
656
  /**
635
- * A single repetition inside a field — HL7 fields may repeat using the
657
+ * A single repetition inside a field: HL7 fields may repeat using the
636
658
  * repetition separator (`~` by default). Each repetition is an ordered list
637
659
  * of components.
638
660
  *
@@ -663,7 +685,7 @@ interface RawField {
663
685
  readonly isNull: boolean;
664
686
  }
665
687
  /**
666
- * A parsed HL7 segment — the top level of the positional tree. The `name`
688
+ * A parsed HL7 segment: the top level of the positional tree. The `name`
667
689
  * is the three-character segment identifier (`MSH`, `PID`, `ZPI`, ...) and
668
690
  * `fields` is the 1-indexed positional field array (see the JSDoc on
669
691
  * `fields` for the index 0 slot convention).
@@ -708,7 +730,7 @@ interface RawSegment {
708
730
  * them, which keeps custom-delimiter behaviour (PARSE-02) consistent across
709
731
  * the pipeline.
710
732
  *
711
- * Only three of the four Tier-3 fatal codes originate here —
733
+ * Only three of the four Tier-3 fatal codes originate here,
712
734
  * `NO_MSH_SEGMENT`, `MSH_TOO_SHORT`, `INVALID_ENCODING_CHARACTERS`. The
713
735
  * fourth, `EMPTY_INPUT`, is owned by the `normalize.ts` preprocessing stage.
714
736
  */
@@ -727,23 +749,182 @@ interface RawSegment {
727
749
  declare const DEFAULT_ENCODING_CHARACTERS: EncodingCharacters;
728
750
 
729
751
  /**
730
- * CE — HL7 v2 Coded Element composite. 6-component coded-element shape
752
+ * Formatted-text rendering for `@cosyte/hl7`: turns HL7 v2 §2.7
753
+ * escape/formatting-bearing field content into a **normalized display model**
754
+ * a human (or a downstream display / FHIR `.text`) can read, instead of the
755
+ * raw `\H\`/`\.br\` sentinels the lenient parser preserves.
756
+ *
757
+ * This is the read-projection half of Phase R: `renderText` never mutates the
758
+ * raw field value (rendering is opt-in on top of the tolerant parse), and it
759
+ * **never fabricates**: an escape it cannot render is preserved as its literal
760
+ * characters AND flagged in {@link RenderedText.unrenderedSequences}, never
761
+ * dropped and never replaced with a guessed glyph.
762
+ *
763
+ * **Clinical-safety angle.** A lab/clinical narrative surfaced with raw
764
+ * `\.br\` / `\H\` sentinels is *misread* by a human; that is the harm this
765
+ * prevents. Formatting commands become real whitespace/line-breaks and
766
+ * highlight boundaries are dropped from the plain text (and exposed as
767
+ * `highlighted` runs for consumers that want emphasis), so what a reader sees
768
+ * is the intended text: never a sentinel and never an invented character.
769
+ *
770
+ * ## Spec traceability (HL7 v2 Chapter 2, §2.7: confirmed firsthand
771
+ * 2026-07-21 against the v2.5.1 and v2.8.2 chapter text; section numbers shift
772
+ * by version)
773
+ *
774
+ * - **§2.7.1 formatting codes**: the delimiter/escape substitutions
775
+ * `\F\ \S\ \T\ \R\ \E\` (→ the message's own field/component/subcomponent/
776
+ * repetition/escape characters), the highlight pair `\H\` (start) / `\N\`
777
+ * (normal, i.e. end), and (v2.7+) `\P\` (the truncation character).
778
+ * - **§2.7.2/2.7.3 charset switch**: `\Cxxyy\` (single-byte) / `\Mxxyyzz\`
779
+ * (multi-byte, `zz` optional): selects an alternate MSH-18 character set for
780
+ * the following run. Decoding requires stateful charset context this module
781
+ * does not have, so a switch is **preserved + flagged**, never guessed.
782
+ * - **§2.7.5/2.7.6 hex**: `\Xdddd…\`: consecutive **pairs** of hex digits,
783
+ * each pair one 8-bit byte.
784
+ * - **§2.7.6/2.7.7 formatting commands** (FT data type): `\.br\` `\.sp\`
785
+ * `\.in\` `\.ti\` `\.fi\` `\.nf\` `\.ce\` `\.sk\`; `.sp` takes an optional
786
+ * positive count, `.in`/`.ti` a signed indent, `.sk` a space count. Rendered
787
+ * to a conservative plain-text normalization (see the table below).
788
+ * - **§2.7.7/2.7.8 locally-defined**: `\Zdddd…\`: opaque, meaning is a
789
+ * sender/receiver agreement, so **preserved + flagged**, never interpreted.
790
+ *
791
+ * ## Normalization policy (conservative, documented: not a page-layout engine)
792
+ *
793
+ * | Escape | Rendered as |
794
+ * | --------------------------- | --------------------------------------------- |
795
+ * | `\F\ \S\ \T\ \R\ \E\ \P\` | the literal delimiter / escape / trunc char |
796
+ * | `\Xdddd…\` | the decoded byte(s) |
797
+ * | `\H\` / `\N\` | dropped from text; toggles a `highlighted` run |
798
+ * | `\.br\` | one line break |
799
+ * | `\.sp\` / `\.sp <n>\` | `n` line breaks (default 1, clamped to 100) |
800
+ * | `\.ce\` | one line break (centering dropped) |
801
+ * | `\.in <n>\` / `\.ti <n>\` | dropped (indentation: exact column math is a defer) |
802
+ * | `\.fi\` / `\.nf\` | dropped (word-wrap mode: no content) |
803
+ * | `\.sk <n>\` | `n` spaces (default 1, clamped to 100) |
804
+ * | `\Cxxyy\` `\Mxxyyzz\` `\Zdddd…\`, malformed / unterminated | literal chars, **preserved + flagged** |
805
+ *
806
+ * A raw CR / LF / CRLF already present in the input (e.g. a `\.br\` the parser
807
+ * already decoded to `\n`, or a hex-encoded `\X0D\`/`\X0A\`) is normalized to
808
+ * one line break too, so rendering a pre-decoded `Field.value` and rendering
809
+ * the wire text agree. A `\.sp <n>\`/`\.sk <n>\` count is clamped to a small
810
+ * maximum (a conservative renderer need not honor a pathological skip, and an
811
+ * unbounded count is a memory / `RangeError` foot-gun on a hostile feed).
812
+ *
813
+ * @packageDocumentation
814
+ */
815
+
816
+ /**
817
+ * One contiguous run of rendered display text, tagged with whether it fell
818
+ * inside a `\H\`…\`\N\` highlight span. Runs preserve emphasis boundaries that
819
+ * the flat {@link RenderedText.text} intentionally drops.
820
+ */
821
+ interface TextRun {
822
+ /**
823
+ * The literal display text of this run: escape sentinels already resolved
824
+ * (delimiter/hex decoded, formatting → whitespace/line breaks). Never
825
+ * contains a formatting sentinel; may contain the newline used for breaks.
826
+ */
827
+ readonly text: string;
828
+ /** `true` when this run is inside a `\H\`…`\N\` highlight span. */
829
+ readonly highlighted: boolean;
830
+ }
831
+ /**
832
+ * The normalized display model produced by {@link renderText}: a flat
833
+ * plain-text string plus the structured highlight-aware runs, plus an
834
+ * honesty list of the escape sequences that were preserved rather than
835
+ * rendered.
836
+ */
837
+ interface RenderedText {
838
+ /**
839
+ * The full plain-text normalization: formatting commands become
840
+ * whitespace / line breaks and highlight boundaries are dropped. This is
841
+ * the string to show a human or feed a downstream `.text`. Equal to the
842
+ * concatenation of every {@link runs} entry's `text`.
843
+ */
844
+ readonly text: string;
845
+ /**
846
+ * The structured, highlight-aware form: `{ text, highlighted }` runs in
847
+ * document order. Empty runs are elided. Use this to preserve emphasis
848
+ * (bold / reverse-video / etc.) that the flat {@link text} drops.
849
+ */
850
+ readonly runs: readonly TextRun[];
851
+ /**
852
+ * The escape sequences `renderText` **preserved verbatim instead of
853
+ * rendering**: vendor `\Zdddd…\`, charset switches `\Cxxyy\`/`\Mxxyyzz\`,
854
+ * and any malformed / unterminated sequence. Their literal characters ALSO
855
+ * appear in {@link text}/{@link runs} (never silently dropped); this list
856
+ * exists so a consumer can detect that a non-render decision was made and
857
+ * surface or route those sequences deliberately. Empty when everything
858
+ * rendered cleanly.
859
+ */
860
+ readonly unrenderedSequences: readonly string[];
861
+ }
862
+ /** Options for {@link renderText}. */
863
+ interface RenderTextOptions {
864
+ /**
865
+ * The string emitted for each line break (`\.br\`, `\.sp\`, `\.ce\`, and a
866
+ * raw CR/LF/CRLF in the input). Defaults to `"\n"`. Set `"\r\n"` for
867
+ * Windows-style display, or `" "` to flatten a note to a single line.
868
+ */
869
+ readonly newline?: string;
870
+ }
871
+ /**
872
+ * Render an HL7 v2 escape/formatting-bearing string into a normalized display
873
+ * model (plain text + highlight-aware runs). A **read projection**: it never
874
+ * mutates the underlying field, and it never fabricates: an escape it cannot
875
+ * render is preserved as literal characters and flagged in
876
+ * {@link RenderedText.unrenderedSequences}.
877
+ *
878
+ * `input` is the field's escape-bearing text. Pass the **wire form** (e.g.
879
+ * `Field.text`, byte-verbatim for parsed content) for the most faithful
880
+ * result: a wire `\E\H\E\` (an escaped literal backslash-H-backslash) then
881
+ * renders as the three literal characters `\H\`, never as a highlight. Passing
882
+ * an already-decoded `Field.value` also works: its `\.br\` is already a
883
+ * newline (rendered as one line break) and its `\H\`/formatting sentinels are
884
+ * still recognized.
885
+ *
886
+ * Never throws for any input.
887
+ *
888
+ * @param input - the escape-bearing field text to render.
889
+ * @param enc - the message's encoding characters (for `\F\`/`\S\`/… targets);
890
+ * defaults to the HL7 standard `|^~\&`.
891
+ * @param opts - see {@link RenderTextOptions}.
892
+ * @returns the normalized {@link RenderedText}.
893
+ *
894
+ * @example
895
+ * ```ts
896
+ * import { renderText } from "@cosyte/hl7";
897
+ *
898
+ * const r = renderText("Specimen received.\\.br\\Gross exam \\H\\normal\\N\\.");
899
+ * r.text;
900
+ * // "Specimen received.\nGross exam normal."
901
+ * r.runs;
902
+ * // [ { text: "Specimen received.\nGross exam ", highlighted: false },
903
+ * // { text: "normal", highlighted: true },
904
+ * // { text: ".", highlighted: false } ]
905
+ * r.unrenderedSequences; // []
906
+ * ```
907
+ */
908
+ declare function renderText(input: string, enc?: EncodingCharacters, opts?: RenderTextOptions): RenderedText;
909
+
910
+ /**
911
+ * CE: HL7 v2 Coded Element composite. 6-component coded-element shape
731
912
  * parsed from a `RawRepetition` on demand by `Field.asCe()` (wired in Plan
732
- * 04). Fields are OMITTED when absent (exactOptionalPropertyTypes) — NEVER
913
+ * 04). Fields are OMITTED when absent (exactOptionalPropertyTypes): NEVER
733
914
  * set to `undefined`.
734
915
  *
735
- * CE is the older, simpler sibling of CWE — 6 components, no version ids,
916
+ * CE is the older, simpler sibling of CWE: 6 components, no version ids,
736
917
  * no originalText. Still common in OBX.3 and similar observation-identifier
737
918
  * slots on older messages. CE was deprecated at HL7 v2.5 and withdrawn at
738
- * v2.6 in favor of CWE; the two are read uniformly here — reading a
919
+ * v2.6 in favor of CWE; the two are read uniformly here: reading a
739
920
  * CWE-shaped value through `asCe()` preserves components 7+ on
740
921
  * `extraComponents` rather than dropping them, so neither accessor is lossy.
741
922
  *
742
- * Zero runtime deps — pure function over the raw positional tree + `unescape`.
923
+ * Zero runtime deps: pure function over the raw positional tree + `unescape`.
743
924
  */
744
925
 
745
926
  /**
746
- * HL7 v2 Coded Element (CE) — coded element per HL7 Chapter 2. All 6
927
+ * HL7 v2 Coded Element (CE): coded element per HL7 Chapter 2. All 6
747
928
  * components are optional. Fields are OMITTED when the underlying component
748
929
  * is absent (exactOptionalPropertyTypes).
749
930
  *
@@ -756,7 +937,7 @@ declare const DEFAULT_ENCODING_CHARACTERS: EncodingCharacters;
756
937
  * 6. nameOfAlternateCodingSystem
757
938
  *
758
939
  * Components 7+ (present when a CWE-shaped value is read through the CE
759
- * accessor — e.g. version ids, originalText) are surfaced verbatim on
940
+ * accessor: e.g. version ids, originalText) are surfaced verbatim on
760
941
  * `extraComponents` rather than dropped.
761
942
  *
762
943
  * @example
@@ -783,7 +964,7 @@ interface CE {
783
964
  }
784
965
  /**
785
966
  * Parse an HL7 v2 CE repetition into a structured `CE` object. Components
786
- * are returned verbatim (already decoded once by the tokenizer — never re-unescaped,
967
+ * are returned verbatim (already decoded once by the tokenizer: never re-unescaped,
787
968
  * HL7-VALUE-REDECODE). Absent / empty components are OMITTED
788
969
  * from the result (exactOptionalPropertyTypes semantics).
789
970
  *
@@ -802,24 +983,24 @@ interface CE {
802
983
  declare function parseCe(rep: RawRepetition, enc: EncodingCharacters): CE;
803
984
 
804
985
  /**
805
- * CWE — HL7 v2 Coded with Exceptions composite. 9-component coded-element
986
+ * CWE: HL7 v2 Coded with Exceptions composite. 9-component coded-element
806
987
  * shape parsed from a `RawRepetition` on demand by `Field.asCwe()` (wired in
807
- * Plan 04). Fields are OMITTED when absent (exactOptionalPropertyTypes) —
988
+ * Plan 04). Fields are OMITTED when absent (exactOptionalPropertyTypes),
808
989
  * NEVER set to `undefined`.
809
990
  *
810
991
  * Note: full HL7 v2.6+ CWE has 22 components. v1 of this library ships the 9
811
- * core components — identifier, text, coding-system trio + version ids, and
812
- * originalText — which cover the common HL7 v2.5 use cases. v2 may restore
813
- * the full shape. Components 10+ that a newer (v2.7+) sender supplies — the
814
- * second-alternate triplet and the coding-system / value-set OIDs — are NOT
992
+ * core components: identifier, text, coding-system trio + version ids, and
993
+ * originalText: which cover the common HL7 v2.5 use cases. v2 may restore
994
+ * the full shape. Components 10+ that a newer (v2.7+) sender supplies: the
995
+ * second-alternate triplet and the coding-system / value-set OIDs: are NOT
815
996
  * dropped: they are preserved verbatim on `extraComponents` so the typed view
816
997
  * is lossless across versions.
817
998
  *
818
- * Zero runtime deps — pure function over the raw positional tree + `unescape`.
999
+ * Zero runtime deps: pure function over the raw positional tree + `unescape`.
819
1000
  */
820
1001
 
821
1002
  /**
822
- * HL7 v2 Coded with Exceptions (CWE) — coded element per HL7 Chapter 2. All
1003
+ * HL7 v2 Coded with Exceptions (CWE): coded element per HL7 Chapter 2. All
823
1004
  * 9 components are optional. Fields are OMITTED when the underlying
824
1005
  * component is absent (exactOptionalPropertyTypes).
825
1006
  *
@@ -835,7 +1016,7 @@ declare function parseCe(rep: RawRepetition, enc: EncodingCharacters): CE;
835
1016
  * 9. originalText
836
1017
  *
837
1018
  * Components 10+ (present only on v2.7+ senders) are surfaced verbatim, in
838
- * order, on `extraComponents` — never silently truncated.
1019
+ * order, on `extraComponents`: never silently truncated.
839
1020
  *
840
1021
  * @example
841
1022
  * ```ts
@@ -865,7 +1046,7 @@ interface CWE {
865
1046
  }
866
1047
  /**
867
1048
  * Parse an HL7 v2 CWE repetition into a structured `CWE` object. Components
868
- * are returned verbatim (already decoded once by the tokenizer — never re-unescaped,
1049
+ * are returned verbatim (already decoded once by the tokenizer: never re-unescaped,
869
1050
  * HL7-VALUE-REDECODE). Absent / empty components are OMITTED
870
1051
  * from the result (exactOptionalPropertyTypes semantics).
871
1052
  *
@@ -884,23 +1065,23 @@ interface CWE {
884
1065
  declare function parseCwe(rep: RawRepetition, enc: EncodingCharacters): CWE;
885
1066
 
886
1067
  /**
887
- * HD — HL7 v2 Hierarchic Designator composite. 3-component structured
1068
+ * HD: HL7 v2 Hierarchic Designator composite. 3-component structured
888
1069
  * identifier (namespace + universal id + universal id type) parsed from a
889
1070
  * `RawRepetition` on demand. Fields are OMITTED when absent
890
- * (exactOptionalPropertyTypes) — NEVER set to `undefined`.
1071
+ * (exactOptionalPropertyTypes): NEVER set to `undefined`.
891
1072
  *
892
- * Zero runtime deps — pure function over the raw positional tree + `unescape`.
1073
+ * Zero runtime deps: pure function over the raw positional tree + `unescape`.
893
1074
  */
894
1075
 
895
1076
  /**
896
- * HL7 v2 Hierarchic Designator (HD) — per HL7 Chapter 2 data type. All 3
1077
+ * HL7 v2 Hierarchic Designator (HD): per HL7 Chapter 2 data type. All 3
897
1078
  * components are optional. Fields are OMITTED when the underlying component
898
1079
  * is absent (exactOptionalPropertyTypes).
899
1080
  *
900
1081
  * Component positions (HL7 1-indexed; this interface is 0-indexed by key):
901
- * 1. namespaceId — application- or facility-scoped identifier (e.g. "EPIC").
902
- * 2. universalId — globally-unique id (e.g. an OID or UUID string).
903
- * 3. universalIdType — classifier for `universalId` (ISO, GUID, UUID, DNS,
1082
+ * 1. namespaceId: application- or facility-scoped identifier (e.g. "EPIC").
1083
+ * 2. universalId: globally-unique id (e.g. an OID or UUID string).
1084
+ * 3. universalIdType: classifier for `universalId` (ISO, GUID, UUID, DNS,
904
1085
  * URI, HL7, HCD, Random, etc.).
905
1086
  *
906
1087
  * @example
@@ -916,7 +1097,7 @@ interface HD {
916
1097
  }
917
1098
  /**
918
1099
  * Parse an HL7 v2 HD repetition into a structured `HD` object. Components
919
- * are returned verbatim (already decoded once by the tokenizer — never re-unescaped,
1100
+ * are returned verbatim (already decoded once by the tokenizer: never re-unescaped,
920
1101
  * HL7-VALUE-REDECODE). Absent / empty components are OMITTED
921
1102
  * from the result (exactOptionalPropertyTypes semantics).
922
1103
  *
@@ -936,10 +1117,10 @@ interface HD {
936
1117
  declare function parseHd(rep: RawRepetition, enc: EncodingCharacters): HD;
937
1118
 
938
1119
  /**
939
- * CX — HL7 v2 Extended Composite ID (with check digit) composite.
1120
+ * CX: HL7 v2 Extended Composite ID (with check digit) composite.
940
1121
  * 10-component structured-identifier shape parsed from a `RawRepetition` on
941
1122
  * demand by `Field.asCx()` (wired in Plan 04). Fields are OMITTED when
942
- * absent (exactOptionalPropertyTypes) — NEVER set to `undefined`.
1123
+ * absent (exactOptionalPropertyTypes): NEVER set to `undefined`.
943
1124
  *
944
1125
  * Component 4 (`assigningAuthority`) is the ONE nested-composite field in
945
1126
  * this plan: its subcomponents form a 3-field HD (namespaceId, universalId,
@@ -948,14 +1129,14 @@ declare function parseHd(rep: RawRepetition, enc: EncodingCharacters): HD;
948
1129
  * CX component 4.
949
1130
  *
950
1131
  * Component 6 (`assigningFacility`) is simplified to a flat `string` in v1
951
- * — the HL7 spec treats it as HD-shaped, but v1 favours simplicity. Callers
1132
+ *: the HL7 spec treats it as HD-shaped, but v1 favours simplicity. Callers
952
1133
  * who need the full HD can parse the raw string separately.
953
1134
  *
954
- * Zero runtime deps — pure function over the raw positional tree + `unescape`.
1135
+ * Zero runtime deps: pure function over the raw positional tree + `unescape`.
955
1136
  */
956
1137
 
957
1138
  /**
958
- * HL7 v2 Extended Composite ID (CX) — structured identifier per HL7 Chapter
1139
+ * HL7 v2 Extended Composite ID (CX): structured identifier per HL7 Chapter
959
1140
  * 2. All 10 components are optional. Fields are OMITTED when the underlying
960
1141
  * component is absent (exactOptionalPropertyTypes). `assigningAuthority`
961
1142
  * uses the nested `HD` shape; `assigningFacility` is flattened to a plain
@@ -965,7 +1146,7 @@ declare function parseHd(rep: RawRepetition, enc: EncodingCharacters): HD;
965
1146
  * 1. idNumber
966
1147
  * 2. checkDigit
967
1148
  * 3. checkDigitScheme (ISO 7064, M10, M11, NPI)
968
- * 4. assigningAuthority (nested HD — 3 subcomponents form a HD composite)
1149
+ * 4. assigningAuthority (nested HD: 3 subcomponents form a HD composite)
969
1150
  * 5. identifierTypeCode (MR, SSN, DL, MC, ...)
970
1151
  * 6. assigningFacility (v1: flattened to string; spec is HD-shaped)
971
1152
  * 7. effectiveDate (raw HL7 TS string)
@@ -997,7 +1178,7 @@ interface CX {
997
1178
  }
998
1179
  /**
999
1180
  * Parse an HL7 v2 CX repetition into a structured `CX` object. Components
1000
- * are returned verbatim (already decoded once by the tokenizer — never re-unescaped,
1181
+ * are returned verbatim (already decoded once by the tokenizer: never re-unescaped,
1001
1182
  * HL7-VALUE-REDECODE). Absent / empty components are OMITTED
1002
1183
  * from the result (exactOptionalPropertyTypes semantics). Component 4
1003
1184
  * (`assigningAuthority`) is parsed as a nested `HD`; see component table in
@@ -1021,7 +1202,7 @@ interface CX {
1021
1202
  declare function parseCx(rep: RawRepetition, enc: EncodingCharacters): CX;
1022
1203
 
1023
1204
  /**
1024
- * NM — HL7 v2 Numeric composite. Parses the raw HL7 numeric string into a
1205
+ * NM: HL7 v2 Numeric composite. Parses the raw HL7 numeric string into a
1025
1206
  * `number` via the stricter `Number(raw)` (not `parseFloat`, which tolerates
1026
1207
  * trailing garbage like "12abc" → 12). `NaN` is normalized to `undefined`
1027
1208
  * per the same no-throw discipline as TS/DTM (D-24 analogous).
@@ -1029,17 +1210,17 @@ declare function parseCx(rep: RawRepetition, enc: EncodingCharacters): CX;
1029
1210
  * The raw string is preserved verbatim on the composite so callers needing
1030
1211
  * to round-trip or render with the original precision/formatting can.
1031
1212
  *
1032
- * Zero runtime deps — pure function over the raw tree + `unescape` + stdlib
1213
+ * Zero runtime deps: pure function over the raw tree + `unescape` + stdlib
1033
1214
  * `Number`.
1034
1215
  */
1035
1216
 
1036
1217
  /**
1037
1218
  * HL7 v2 Numeric (NM) composite. Carries both the raw HL7 numeric string
1038
1219
  * and the parsed JS `number`. `.value` is `undefined` when the raw string
1039
- * is empty or not fully numeric — NEVER throws.
1220
+ * is empty or not fully numeric: NEVER throws.
1040
1221
  *
1041
1222
  * Unlike most composites in this phase, both `raw` and `value` are
1042
- * ALWAYS-PRESENT keys (not optional) — `value` is explicitly typed as
1223
+ * ALWAYS-PRESENT keys (not optional): `value` is explicitly typed as
1043
1224
  * `number | undefined` so callers can destructure uniformly.
1044
1225
  *
1045
1226
  * @example
@@ -1055,10 +1236,10 @@ interface NM {
1055
1236
  }
1056
1237
  /**
1057
1238
  * Parse an HL7 v2 NM repetition into `{ raw, value }`. Uses `Number(raw)`
1058
- * for strict numeric parsing — trailing non-numeric characters produce
1239
+ * for strict numeric parsing: trailing non-numeric characters produce
1059
1240
  * `NaN`, normalized to `undefined`. Empty raw also produces `undefined`.
1060
1241
  *
1061
- * `Number("")` is `0` in JS — which is the wrong answer for an empty HL7
1242
+ * `Number("")` is `0` in JS: which is the wrong answer for an empty HL7
1062
1243
  * numeric field. The explicit empty-string check below returns
1063
1244
  * `{ raw: "", value: undefined }` so empty inputs match missing inputs.
1064
1245
  *
@@ -1073,42 +1254,42 @@ interface NM {
1073
1254
  declare function parseNm(rep: RawRepetition, _enc: EncodingCharacters): NM;
1074
1255
 
1075
1256
  /**
1076
- * PL — HL7 v2 Person Location composite. 11-component structured-location
1077
- * shape (v1 trimmed from the HL7 v2.5 full 12-component PL — slot 12
1257
+ * PL: HL7 v2 Person Location composite. 11-component structured-location
1258
+ * shape (v1 trimmed from the HL7 v2.5 full 12-component PL: slot 12
1078
1259
  * `entityIdentifier` is rarely used; v2 may restore the full shape) parsed
1079
1260
  * from a `RawRepetition` on demand by `Field.asPl()` (wired in Plan 04).
1080
- * Fields are OMITTED when absent (exactOptionalPropertyTypes) — NEVER set
1261
+ * Fields are OMITTED when absent (exactOptionalPropertyTypes): NEVER set
1081
1262
  * to `undefined`.
1082
1263
  *
1083
1264
  * Component 4 (`facility`) is the ONE nested-composite field in this
1084
1265
  * parser: its subcomponents form a 3-field HD (namespaceId, universalId,
1085
- * universalIdType) — same synthesis pattern used in `parseCx` for
1266
+ * universalIdType): same synthesis pattern used in `parseCx` for
1086
1267
  * `assigningAuthority`. To reuse `parseHd` without duplicating logic, the
1087
1268
  * parser synthesises a `RawRepetition` whose components wrap the
1088
1269
  * subcomponents of PL component 4.
1089
1270
  *
1090
- * Zero runtime deps — pure function over the raw positional tree + `unescape`.
1271
+ * Zero runtime deps: pure function over the raw positional tree + `unescape`.
1091
1272
  */
1092
1273
 
1093
1274
  /**
1094
- * HL7 v2 Person Location (PL) — structured location per HL7 Chapter 2. All
1275
+ * HL7 v2 Person Location (PL): structured location per HL7 Chapter 2. All
1095
1276
  * 11 v1 components are optional. Fields are OMITTED when the underlying
1096
1277
  * component is absent (exactOptionalPropertyTypes). `facility` uses the
1097
1278
  * nested `HD` shape; `assigningAuthorityForLocation` is flattened to a
1098
1279
  * plain string in v1 (HL7 spec treats it as HD-shaped).
1099
1280
  *
1100
1281
  * Component positions (HL7 1-indexed; this interface is 0-indexed by key):
1101
- * 1. pointOfCare — e.g. "ICU", "ED"
1282
+ * 1. pointOfCare: e.g. "ICU", "ED"
1102
1283
  * 2. room
1103
1284
  * 3. bed
1104
- * 4. facility — nested HD (3 subcomponents form an HD composite)
1105
- * 5. locationStatus — O=Occupied, U=Unoccupied, K=Contaminated, C=Closed,
1285
+ * 4. facility: nested HD (3 subcomponents form an HD composite)
1286
+ * 5. locationStatus: O=Occupied, U=Unoccupied, K=Contaminated, C=Closed,
1106
1287
  * H=Housekeeping, I=Isolated
1107
- * 6. personLocationType — C=Clinic, D=Department, H=Home, N=Nursing Unit,
1288
+ * 6. personLocationType: C=Clinic, D=Department, H=Home, N=Nursing Unit,
1108
1289
  * O=Office, R=Revenue Location
1109
1290
  * 7. building
1110
1291
  * 8. floor
1111
- * 9. locationDescription — free-text
1292
+ * 9. locationDescription: free-text
1112
1293
  * 10. comprehensiveLocationId
1113
1294
  * 11. assigningAuthorityForLocation (v1: flattened to string)
1114
1295
  *
@@ -1138,7 +1319,7 @@ interface PL {
1138
1319
  }
1139
1320
  /**
1140
1321
  * Parse an HL7 v2 PL repetition into a structured `PL` object. Components
1141
- * are returned verbatim (already decoded once by the tokenizer — never re-unescaped,
1322
+ * are returned verbatim (already decoded once by the tokenizer: never re-unescaped,
1142
1323
  * HL7-VALUE-REDECODE). Absent / empty components are OMITTED
1143
1324
  * from the result (exactOptionalPropertyTypes semantics). Component 4
1144
1325
  * (`facility`) is parsed as a nested `HD`; see component table in the `PL`
@@ -1161,15 +1342,15 @@ interface PL {
1161
1342
  declare function parsePl(rep: RawRepetition, enc: EncodingCharacters): PL;
1162
1343
 
1163
1344
  /**
1164
- * SN — HL7 v2 Structured Numeric composite (HL7 Chapter 2A). Parses an OBX-5
1345
+ * SN: HL7 v2 Structured Numeric composite (HL7 Chapter 2A). Parses an OBX-5
1165
1346
  * value declared as `OBX-2 = SN` into its four positional components so a
1166
1347
  * comparator or a range/ratio is preserved as TYPED data instead of being
1167
1348
  * flattened to a string (where everything past the first component is lost).
1168
1349
  *
1169
1350
  * Component positions (HL7 1-indexed; this interface is 0-indexed by key):
1170
- * 1. comparator (ST) — `>` `<` `>=` `<=` `=` `<>`; absent ⇒ `=`
1351
+ * 1. comparator (ST): `>` `<` `>=` `<=` `=` `<>`; absent ⇒ `=`
1171
1352
  * 2. num1 (NM)
1172
- * 3. separatorOrSuffix (ST) — `-` (range), `:` / `/` (ratio), `+` (suffix), `.`
1353
+ * 3. separatorOrSuffix (ST): `-` (range), `:` / `/` (ratio), `+` (suffix), `.`
1173
1354
  * 4. num2 (NM)
1174
1355
  *
1175
1356
  * Usage examples (the literal OBX-5 string ⇒ what this parses):
@@ -1179,12 +1360,12 @@ declare function parsePl(rep: RawRepetition, enc: EncodingCharacters): PL;
1179
1360
  * `^1^:^128` ⇒ titer/ratio 1:128 → { num1: 1, separatorOrSuffix: ":", num2: 128 }
1180
1361
  *
1181
1362
  * Safety: `num1`/`num2` are parsed with the same strict `Number()` discipline
1182
- * as NM — non-numeric input becomes `undefined`, NEVER `NaN` and never a
1363
+ * as NM: non-numeric input becomes `undefined`, NEVER `NaN` and never a
1183
1364
  * silently wrong number. The comparator is surfaced ONLY when SN.1 is a
1184
1365
  * recognized operator, so a non-operator value in the comparator slot is never
1185
1366
  * passed off as a real relation.
1186
1367
  *
1187
- * Zero runtime deps — pure function over the raw positional tree + `unescape`.
1368
+ * Zero runtime deps: pure function over the raw positional tree + `unescape`.
1188
1369
  */
1189
1370
 
1190
1371
  /**
@@ -1194,7 +1375,7 @@ declare function parsePl(rep: RawRepetition, enc: EncodingCharacters): PL;
1194
1375
  * when absent (`exactOptionalPropertyTypes`).
1195
1376
  *
1196
1377
  * An absent `comparator` means the default `=` relation per HL7 Chapter 2A.
1197
- * This library surfaces the structure only — it does not evaluate the
1378
+ * This library surfaces the structure only: it does not evaluate the
1198
1379
  * inequality, validate the unit, or convert values.
1199
1380
  *
1200
1381
  * @example
@@ -1205,11 +1386,11 @@ declare function parsePl(rep: RawRepetition, enc: EncodingCharacters): PL;
1205
1386
  * ```
1206
1387
  */
1207
1388
  interface SN {
1208
- /** SN.1 comparator — one of `>` `<` `>=` `<=` `=` `<>`. Omitted ⇒ default `=`. */
1389
+ /** SN.1 comparator: one of `>` `<` `>=` `<=` `=` `<>`. Omitted ⇒ default `=`. */
1209
1390
  readonly comparator?: string;
1210
1391
  /** SN.2 first numeric value. `undefined` when absent or non-numeric (never `NaN`). */
1211
1392
  readonly num1: number | undefined;
1212
- /** SN.3 separator/suffix — `-` (range), `:`/`/` (ratio), `+` (suffix), `.`. Omitted when absent. */
1393
+ /** SN.3 separator/suffix: `-` (range), `:`/`/` (ratio), `+` (suffix), `.`. Omitted when absent. */
1213
1394
  readonly separatorOrSuffix?: string;
1214
1395
  /** SN.4 second numeric value. `undefined` when absent or non-numeric (never `NaN`). */
1215
1396
  readonly num2: number | undefined;
@@ -1222,7 +1403,7 @@ interface SN {
1222
1403
  *
1223
1404
  * Fail-safe: a non-operator value in the comparator slot (SN.1) is dropped
1224
1405
  * rather than surfaced as a relation, and a non-numeric SN.2/SN.4 becomes
1225
- * `undefined` — the parser never emits a confident wrong comparator or number.
1406
+ * `undefined`: the parser never emits a confident wrong comparator or number.
1226
1407
  *
1227
1408
  * @example
1228
1409
  * ```ts
@@ -1244,14 +1425,14 @@ declare function parseSn(rep: RawRepetition, enc: EncodingCharacters): SN | unde
1244
1425
  * `Date`-coercing helper into a **fidelity-first** parser. The HL7 v2 Ch. 2A
1245
1426
  * DTM datatype is `YYYY[MM[DD[HH[MM[SS[.S[S[S[S]]]]]]]]][+/-ZZZZ]`, where the
1246
1427
  * number of populated characters (excluding the offset) sets the precision and
1247
- * a missing offset "defaults to that of the local time zone of the sender" —
1428
+ * a missing offset "defaults to that of the local time zone of the sender",
1248
1429
  * NOT UTC and NOT the parser's zone. The old behavior (zero-fill truncations,
1249
1430
  * assume-UTC on a missing offset, eager `Date`) is an architectural defect
1250
1431
  * [S-DTM-IMPL]: it silently shifts a day-only birth date (`|19880705|`) by a
1251
1432
  * day in any negative-offset zone.
1252
1433
  *
1253
1434
  * This module therefore:
1254
- * - `parseDtm(raw)` decodes the DTM into typed **parts** (`DtmParts`) —
1435
+ * - `parseDtm(raw)` decodes the DTM into typed **parts** (`DtmParts`),
1255
1436
  * precision preserved, no zero-fill, no `Date`, no UTC assumption.
1256
1437
  * - `formatDtm(parts)` reconstructs the DTM string from parts (round-trip).
1257
1438
  * - `dtmToDate(parts, opts)` materializes an absolute `Date` **only on
@@ -1261,12 +1442,12 @@ declare function parseSn(rep: RawRepetition, enc: EncodingCharacters): SN | unde
1261
1442
  * formats → built-in fallbacks) used by non-composite callers such as
1262
1443
  * `msg.meta.timestamp`; it emits `TIMESTAMP_FALLBACK_FORMAT` on a fallback.
1263
1444
  *
1264
- * Zero runtime deps — only the JS stdlib `Date` / `Date.UTC` APIs and
1445
+ * Zero runtime deps: only the JS stdlib `Date` / `Date.UTC` APIs and
1265
1446
  * hand-rolled regex / token matchers. No date-fns, no luxon, no moment.
1266
1447
  */
1267
1448
 
1268
1449
  /**
1269
- * Stated precision of a parsed HL7 DTM value — the number of populated
1450
+ * Stated precision of a parsed HL7 DTM value: the number of populated
1270
1451
  * characters (excluding the timezone offset) determines which level applies.
1271
1452
  * A value's precision is preserved verbatim: `|1970|` is `"year"`, never
1272
1453
  * silently promoted to a full timestamp.
@@ -1280,7 +1461,7 @@ declare function parseSn(rep: RawRepetition, enc: EncodingCharacters): SN | unde
1280
1461
  */
1281
1462
  type DtmPrecision = "year" | "month" | "day" | "hour" | "minute" | "second" | "fraction";
1282
1463
  /**
1283
- * Parsed HL7 v2 TS/DTM value — the raw string plus its structural parts, with
1464
+ * Parsed HL7 v2 TS/DTM value: the raw string plus its structural parts, with
1284
1465
  * the stated **precision** and **timezone fidelity** preserved. This is the
1285
1466
  * shape of the `TS` composite (`field.asTs()`) and every helper datetime.
1286
1467
  *
@@ -1288,7 +1469,7 @@ type DtmPrecision = "year" | "month" | "day" | "hour" | "minute" | "second" | "f
1288
1469
  * **spec-native** (`month` is 1–12, NOT the JS `Date` 0–11). `offsetMinutes`
1289
1470
  * is present iff `hasTimezone` is `true` and is signed minutes east of UTC
1290
1471
  * (`+0500` → `300`, `-0430` → `-270`). A missing offset is **flagged**
1291
- * (`hasTimezone: false`), never resolved to UTC — the consumer decides how to
1472
+ * (`hasTimezone: false`), never resolved to UTC: the consumer decides how to
1292
1473
  * localize with {@link dtmToDate}.
1293
1474
  *
1294
1475
  * @example
@@ -1306,7 +1487,7 @@ interface DtmParts {
1306
1487
  /**
1307
1488
  * `true` when `raw` is a well-formed, in-range HL7 DTM (or a matched
1308
1489
  * fallback format). `false` for empty, malformed, or calendar-out-of-range
1309
- * input — in which case only `raw` and `hasTimezone: false` are meaningful.
1490
+ * input: in which case only `raw` and `hasTimezone: false` are meaningful.
1310
1491
  */
1311
1492
  readonly valid: boolean;
1312
1493
  /** Stated precision; absent when `valid` is `false`. */
@@ -1325,7 +1506,7 @@ interface DtmParts {
1325
1506
  readonly second?: number;
1326
1507
  /**
1327
1508
  * Fractional-second digits exactly as populated (no leading dot), e.g.
1328
- * `"5"` (0.5 s), `"0500"` (0.05 s). Preserved verbatim — never rounded.
1509
+ * `"5"` (0.5 s), `"0500"` (0.05 s). Preserved verbatim: never rounded.
1329
1510
  */
1330
1511
  readonly fractionalSeconds?: string;
1331
1512
  /** `true` iff an explicit `+/-ZZZZ` offset was present. */
@@ -1372,7 +1553,7 @@ declare const SUPPORTED_DATE_TOKENS: readonly string[];
1372
1553
  * never coerces to a `Date`, and never assumes UTC for a missing offset.
1373
1554
  *
1374
1555
  * Returns `{ raw, valid: false, hasTimezone: false }` (no parts) for empty,
1375
- * malformed, or calendar-out-of-range input — never throws. A fractional
1556
+ * malformed, or calendar-out-of-range input: never throws. A fractional
1376
1557
  * component is only accepted at full second precision.
1377
1558
  *
1378
1559
  * @example
@@ -1392,12 +1573,12 @@ declare const SUPPORTED_DATE_TOKENS: readonly string[];
1392
1573
  declare function parseDtm(raw: string): DtmParts;
1393
1574
  /**
1394
1575
  * Reconstruct the HL7 DTM string from {@link DtmParts}. The inverse of
1395
- * {@link parseDtm} for a strict HL7 parse — `formatDtm(parseDtm(s)) === s` for
1576
+ * {@link parseDtm} for a strict HL7 parse: `formatDtm(parseDtm(s)) === s` for
1396
1577
  * any well-formed `s`, including the byte-preserving `-0000` (which HL7, unlike
1397
1578
  * RFC 3339, treats as UTC but whose sign we retain for exact round-trip).
1398
1579
  * Returns the raw string unchanged when `parts.valid` is `false`.
1399
1580
  *
1400
- * Emits exactly the populated precision — no zero-fill — so a year-only value
1581
+ * Emits exactly the populated precision, no zero-fill, so a year-only value
1401
1582
  * re-serializes to four characters, never `YYYY0101`.
1402
1583
  *
1403
1584
  * @example
@@ -1423,14 +1604,14 @@ declare function formatDtm(parts: DtmParts): string;
1423
1604
  interface DtmToDateOptions {
1424
1605
  /**
1425
1606
  * Offset (signed minutes east of UTC) to assume when the value carries **no**
1426
- * timezone. Without it, an offset-less value resolves to `undefined` —
1607
+ * timezone. Without it, an offset-less value resolves to `undefined`,
1427
1608
  * {@link dtmToDate} never guesses a zone. Ignored when the value already has
1428
1609
  * an offset. Pass `0` to explicitly treat a naive value as UTC.
1429
1610
  */
1430
1611
  readonly assumeOffsetMinutes?: number;
1431
1612
  }
1432
1613
  /**
1433
- * Materialize an absolute-instant JS `Date` from {@link DtmParts} — **only on
1614
+ * Materialize an absolute-instant JS `Date` from {@link DtmParts}: **only on
1434
1615
  * explicit caller request**. Truncated fields fill to their lowest legal value
1435
1616
  * (month → January, day → 1, time → 0) *for instant construction only*; the
1436
1617
  * value's stated `precision` still tells the truth.
@@ -1448,35 +1629,35 @@ interface DtmToDateOptions {
1448
1629
  * import { parseDtm, dtmToDate } from "@cosyte/hl7";
1449
1630
  *
1450
1631
  * dtmToDate(parseDtm("20250102153045-0500"))?.toISOString();
1451
- * // "2025-01-02T20:30:45.000Z" — exact, offset-derived
1632
+ * // "2025-01-02T20:30:45.000Z": exact, offset-derived
1452
1633
  *
1453
- * dtmToDate(parseDtm("20250102")); // undefined — refuses to guess the zone
1634
+ * dtmToDate(parseDtm("20250102")); // undefined: refuses to guess the zone
1454
1635
  * dtmToDate(parseDtm("20250102"), { assumeOffsetMinutes: 0 })?.toISOString();
1455
- * // "2025-01-02T00:00:00.000Z" — caller explicitly assumed UTC
1636
+ * // "2025-01-02T00:00:00.000Z": caller explicitly assumed UTC
1456
1637
  * ```
1457
1638
  */
1458
1639
  declare function dtmToDate(parts: DtmParts, options?: DtmToDateOptions): Date | undefined;
1459
1640
 
1460
1641
  /**
1461
- * TS/DTM — HL7 v2 Time Stamp composite. Delegates parsing to the Phase 2
1642
+ * TS/DTM: HL7 v2 Time Stamp composite. Delegates parsing to the Phase 2
1462
1643
  * helper `src/parser/dates.ts::parseDtm` (D-10 "zero duplicate date logic").
1463
1644
  *
1464
1645
  * Phase N (datetime precision + timezone fidelity) reshaped this composite from
1465
1646
  * the old `{ raw, date }` (which zero-filled truncations and assumed UTC for a
1466
- * missing offset — an architectural defect) to the fidelity-preserving
1647
+ * missing offset: an architectural defect) to the fidelity-preserving
1467
1648
  * {@link DtmParts}: raw string + typed parts + stated precision + timezone
1468
1649
  * presence, with **no eager `Date`**. Callers that need an absolute instant
1469
- * opt in explicitly via `dtmToDate(ts, opts)` — which refuses to guess a zone
1650
+ * opt in explicitly via `dtmToDate(ts, opts)`: which refuses to guess a zone
1470
1651
  * for an offset-less value rather than silently defaulting to UTC.
1471
1652
  *
1472
- * Zero runtime deps — delegates to `parseDtm` + `unescape`.
1653
+ * Zero runtime deps: delegates to `parseDtm` + `unescape`.
1473
1654
  */
1474
1655
 
1475
1656
  /**
1476
- * HL7 v2 Time Stamp (TS) / Date Time (DTM) composite — the raw HL7 string plus
1657
+ * HL7 v2 Time Stamp (TS) / Date Time (DTM) composite: the raw HL7 string plus
1477
1658
  * its parsed parts, preserving the **stated precision** and **timezone
1478
1659
  * fidelity**. This is a {@link DtmParts}: `valid` is `false` (with no parts)
1479
- * for unparseable input — NEVER throws (TYPES-04 no-throw guarantee).
1660
+ * for unparseable input: NEVER throws (TYPES-04 no-throw guarantee).
1480
1661
  *
1481
1662
  * There is deliberately **no `date` field**: a day-only value coerced to a JS
1482
1663
  * `Date` at UTC midnight silently shifts the calendar day in negative-offset
@@ -1489,14 +1670,14 @@ declare function dtmToDate(parts: DtmParts, options?: DtmToDateOptions): Date |
1489
1670
  * import { dtmToDate } from "@cosyte/hl7";
1490
1671
  * const dob: TS = { raw: "19880705", valid: true, precision: "day",
1491
1672
  * year: 1988, month: 7, day: 5, hasTimezone: false };
1492
- * console.log(dob.precision); // "day" — not a full timestamp
1493
- * console.log(dtmToDate(dob)); // undefined — refuses to guess the zone
1673
+ * console.log(dob.precision); // "day": not a full timestamp
1674
+ * console.log(dtmToDate(dob)); // undefined: refuses to guess the zone
1494
1675
  * ```
1495
1676
  */
1496
1677
  type TS = DtmParts;
1497
1678
  /**
1498
1679
  * Parse an HL7 v2 TS/DTM repetition into fidelity {@link TS} parts. Delegates
1499
- * to `parseDtm` — the same structural parser that backs every timestamp in the
1680
+ * to `parseDtm`: the same structural parser that backs every timestamp in the
1500
1681
  * library. No user `dateFormats` at this layer; non-composite callers (e.g.
1501
1682
  * `msg.meta.timestamp`) that know `ParseOptions.dateFormats` use
1502
1683
  * `parseDtmCascade` directly.
@@ -1517,22 +1698,22 @@ type TS = DtmParts;
1517
1698
  declare function parseTs(rep: RawRepetition, _enc: EncodingCharacters): TS;
1518
1699
 
1519
1700
  /**
1520
- * XAD — HL7 v2 Extended Address composite. 12-component structured address
1701
+ * XAD: HL7 v2 Extended Address composite. 12-component structured address
1521
1702
  * shape parsed from a `RawRepetition` on demand by `Field.asXad()` (wired in
1522
- * Plan 04). Fields are OMITTED when absent (exactOptionalPropertyTypes) —
1703
+ * Plan 04). Fields are OMITTED when absent (exactOptionalPropertyTypes),
1523
1704
  * NEVER set to `undefined`.
1524
1705
  *
1525
- * Zero runtime deps — pure function over the raw positional tree + `unescape`.
1706
+ * Zero runtime deps: pure function over the raw positional tree + `unescape`.
1526
1707
  */
1527
1708
 
1528
1709
  /**
1529
- * HL7 v2 Extended Address (XAD) — structured postal address per HL7 Chapter
1710
+ * HL7 v2 Extended Address (XAD): structured postal address per HL7 Chapter
1530
1711
  * 2. All 12 components are optional. Fields are OMITTED when the underlying
1531
1712
  * component is absent (exactOptionalPropertyTypes).
1532
1713
  *
1533
1714
  * Component positions (HL7 1-indexed; this interface is 0-indexed by key):
1534
- * 1. street — street address (house number + street name).
1535
- * 2. otherDesignation — apartment number, suite, floor, etc.
1715
+ * 1. street: street address (house number + street name).
1716
+ * 2. otherDesignation: apartment number, suite, floor, etc.
1536
1717
  * 3. city
1537
1718
  * 4. stateOrProvince
1538
1719
  * 5. zipOrPostalCode
@@ -1566,7 +1747,7 @@ interface XAD {
1566
1747
  }
1567
1748
  /**
1568
1749
  * Parse an HL7 v2 XAD repetition into a structured `XAD` object. Components
1569
- * are returned verbatim (already decoded once by the tokenizer — never re-unescaped,
1750
+ * are returned verbatim (already decoded once by the tokenizer: never re-unescaped,
1570
1751
  * HL7-VALUE-REDECODE). Absent / empty components are OMITTED
1571
1752
  * from the result (exactOptionalPropertyTypes semantics).
1572
1753
  *
@@ -1587,7 +1768,7 @@ interface XAD {
1587
1768
  declare function parseXad(rep: RawRepetition, enc: EncodingCharacters): XAD;
1588
1769
 
1589
1770
  /**
1590
- * XCN — HL7 v2 Extended Composite ID Number and Name for Persons. Common in
1771
+ * XCN: HL7 v2 Extended Composite ID Number and Name for Persons. Common in
1591
1772
  * OBR-16 (ordering provider), PV1-7 (attending doctor), PV1-8 (referring
1592
1773
  * doctor), and other fields that identify a human clinician.
1593
1774
  *
@@ -1596,29 +1777,29 @@ declare function parseXad(rep: RawRepetition, enc: EncodingCharacters): XAD;
1596
1777
  * most-used components (HL7 v2.5 defines 23); additional components may be
1597
1778
  * restored in v2 if vendor-quirk fixtures require them.
1598
1779
  *
1599
- * Zero runtime deps — pure function over the raw positional tree + `unescape`.
1780
+ * Zero runtime deps: pure function over the raw positional tree + `unescape`.
1600
1781
  * Parser is silent (D-09 composite-parser silence).
1601
1782
  */
1602
1783
 
1603
1784
  /**
1604
- * HL7 v2 Extended Composite ID Number and Name for Persons (XCN) — per HL7
1785
+ * HL7 v2 Extended Composite ID Number and Name for Persons (XCN): per HL7
1605
1786
  * Chapter 2.A.88. All 13 v1 components are optional. Fields are OMITTED when
1606
1787
  * the underlying component is absent (exactOptionalPropertyTypes).
1607
1788
  *
1608
1789
  * Component positions (HL7 1-indexed; this interface is 0-indexed by key):
1609
- * 1. idNumber — e.g. employee ID, NPI digits, DEA number (CX-1 analogue)
1790
+ * 1. idNumber: e.g. employee ID, NPI digits, DEA number (CX-1 analogue)
1610
1791
  * 2. familyName (XPN-1)
1611
1792
  * 3. givenName (XPN-2)
1612
- * 4. secondName — second and further given names (XPN-3)
1613
- * 5. suffix — Jr., III, etc. (XPN-4)
1614
- * 6. prefix — Dr., Mrs., etc. (XPN-5)
1615
- * 7. degree — MD, PhD, etc. (XPN-6)
1793
+ * 4. secondName: second and further given names (XPN-3)
1794
+ * 5. suffix: Jr., III, etc. (XPN-4)
1795
+ * 6. prefix: Dr., Mrs., etc. (XPN-5)
1796
+ * 7. degree: MD, PhD, etc. (XPN-6)
1616
1797
  * 8. sourceTable
1617
- * 9. assigningAuthority — nested HD (CX-4 analogue)
1618
- * 10. nameTypeCode — L=Legal, M=Maiden, N=Nickname, ... (XPN-7)
1798
+ * 9. assigningAuthority: nested HD (CX-4 analogue)
1799
+ * 10. nameTypeCode: L=Legal, M=Maiden, N=Nickname, ... (XPN-7)
1619
1800
  * 11. identifierCheckDigit
1620
- * 12. checkDigitScheme — ISO 7064, M10, M11, NPI
1621
- * 13. identifierTypeCode — "NPI", "DN" (DEA number), ... (CX-5 analogue)
1801
+ * 12. checkDigitScheme: ISO 7064, M10, M11, NPI
1802
+ * 13. identifierTypeCode: "NPI", "DN" (DEA number), ... (CX-5 analogue)
1622
1803
  *
1623
1804
  * @example
1624
1805
  * ```ts
@@ -1648,7 +1829,7 @@ interface XCN {
1648
1829
  }
1649
1830
  /**
1650
1831
  * Parse an HL7 v2 XCN repetition into a structured `XCN` object. Components
1651
- * are returned verbatim (already decoded once by the tokenizer — never re-unescaped,
1832
+ * are returned verbatim (already decoded once by the tokenizer: never re-unescaped,
1652
1833
  * HL7-VALUE-REDECODE). Absent / empty components are OMITTED
1653
1834
  * from the result (exactOptionalPropertyTypes semantics). Component 9
1654
1835
  * (`assigningAuthority`) is parsed as a nested `HD`; see component table in
@@ -1682,16 +1863,16 @@ interface XCN {
1682
1863
  declare function parseXcn(rep: RawRepetition, enc: EncodingCharacters): XCN;
1683
1864
 
1684
1865
  /**
1685
- * XPN — HL7 v2 Extended Person Name composite. 14-component structured-name
1866
+ * XPN: HL7 v2 Extended Person Name composite. 14-component structured-name
1686
1867
  * shape parsed from a `RawRepetition` on demand by `Field.asXpn()` (wired in
1687
- * Plan 04). Fields are OMITTED when absent (exactOptionalPropertyTypes) —
1868
+ * Plan 04). Fields are OMITTED when absent (exactOptionalPropertyTypes),
1688
1869
  * NEVER set to `undefined`.
1689
1870
  *
1690
- * Zero runtime deps — pure function over the raw positional tree + `unescape`.
1871
+ * Zero runtime deps: pure function over the raw positional tree + `unescape`.
1691
1872
  */
1692
1873
 
1693
1874
  /**
1694
- * HL7 v2 Extended Person Name (XPN) — structured name per HL7 Chapter 2. All
1875
+ * HL7 v2 Extended Person Name (XPN): structured name per HL7 Chapter 2. All
1695
1876
  * 14 components are optional. Fields are OMITTED when the underlying
1696
1877
  * component is absent (exactOptionalPropertyTypes).
1697
1878
  *
@@ -1704,10 +1885,10 @@ declare function parseXcn(rep: RawRepetition, enc: EncodingCharacters): XCN;
1704
1885
  * 6. degree (e.g. MD, PhD)
1705
1886
  * 7. nameTypeCode (L=Legal, M=Maiden, N=Nickname, S=Coded Pseudo-Name, ...)
1706
1887
  * 8. nameRepresentationCode
1707
- * 9. nameContext (flattened to string in v1 — CWE nesting is out of scope)
1888
+ * 9. nameContext (flattened to string in v1: CWE nesting is out of scope)
1708
1889
  * 10. nameValidityRange
1709
1890
  * 11. nameAssemblyOrder (F=family first, G=given first)
1710
- * 12. effectiveDate (raw HL7 TS string — caller may parse via parseDtm)
1891
+ * 12. effectiveDate (raw HL7 TS string: caller may parse via parseDtm)
1711
1892
  * 13. expirationDate
1712
1893
  * 14. professionalSuffix
1713
1894
  *
@@ -1735,7 +1916,7 @@ interface XPN {
1735
1916
  }
1736
1917
  /**
1737
1918
  * Parse an HL7 v2 XPN repetition into a structured `XPN` object. Components
1738
- * are returned verbatim (already decoded once by the tokenizer — never re-unescaped,
1919
+ * are returned verbatim (already decoded once by the tokenizer: never re-unescaped,
1739
1920
  * HL7-VALUE-REDECODE). Absent / empty components are OMITTED
1740
1921
  * from the result (exactOptionalPropertyTypes semantics).
1741
1922
  *
@@ -1754,34 +1935,34 @@ interface XPN {
1754
1935
  declare function parseXpn(rep: RawRepetition, enc: EncodingCharacters): XPN;
1755
1936
 
1756
1937
  /**
1757
- * XTN — HL7 v2 Extended Telecommunication Number composite. 12-component
1938
+ * XTN: HL7 v2 Extended Telecommunication Number composite. 12-component
1758
1939
  * structured telecom shape (v1 trimmed from the HL7 v2.5 full 14-component
1759
- * XTN — slots 13/14 are rarely-used legacy fields; v2 may restore the full
1940
+ * XTN: slots 13/14 are rarely-used legacy fields; v2 may restore the full
1760
1941
  * shape) parsed from a `RawRepetition` on demand by `Field.asXtn()` (wired
1761
1942
  * in Plan 04). Fields are OMITTED when absent (exactOptionalPropertyTypes)
1762
- * — NEVER set to `undefined`.
1943
+ *: NEVER set to `undefined`.
1763
1944
  *
1764
- * Zero runtime deps — pure function over the raw positional tree + `unescape`.
1945
+ * Zero runtime deps: pure function over the raw positional tree + `unescape`.
1765
1946
  */
1766
1947
 
1767
1948
  /**
1768
- * HL7 v2 Extended Telecommunication Number (XTN) — structured telecom per
1949
+ * HL7 v2 Extended Telecommunication Number (XTN): structured telecom per
1769
1950
  * HL7 Chapter 2. All 12 v1 components are optional. Fields are OMITTED when
1770
1951
  * the underlying component is absent (exactOptionalPropertyTypes).
1771
1952
  *
1772
1953
  * Component positions (HL7 1-indexed; this interface is 0-indexed by key):
1773
- * 1. telephoneNumber — formatted or unformatted phone number
1774
- * 2. telecommunicationUseCode — PRN=Primary Residence, WPN=Work, NET=Internet,
1954
+ * 1. telephoneNumber: formatted or unformatted phone number
1955
+ * 2. telecommunicationUseCode: PRN=Primary Residence, WPN=Work, NET=Internet,
1775
1956
  * ORN=Other Residence, BPN=Beeper, VHN=Vacation Home, ASN=Answering
1776
1957
  * Service, EMR=Emergency, ...
1777
- * 3. telecommunicationEquipmentType — PH=Phone, FX=Fax, MD=Modem,
1958
+ * 3. telecommunicationEquipmentType: PH=Phone, FX=Fax, MD=Modem,
1778
1959
  * CP=Cellular Phone, BP=Beeper, Internet, X.400, TDD, TTY
1779
1960
  * 4. emailAddress
1780
1961
  * 5. countryCode (e.g. "+1")
1781
1962
  * 6. areaCityCode
1782
1963
  * 7. localNumber
1783
1964
  * 8. extension
1784
- * 9. anyText — free-text note
1965
+ * 9. anyText: free-text note
1785
1966
  * 10. extensionPrefix (e.g. "x")
1786
1967
  * 11. speedDialCode
1787
1968
  * 12. unformattedTelephoneNumber
@@ -1812,7 +1993,7 @@ interface XTN {
1812
1993
  }
1813
1994
  /**
1814
1995
  * Parse an HL7 v2 XTN repetition into a structured `XTN` object. Components
1815
- * are returned verbatim (already decoded once by the tokenizer — never re-unescaped,
1996
+ * are returned verbatim (already decoded once by the tokenizer: never re-unescaped,
1816
1997
  * HL7-VALUE-REDECODE). Absent / empty components are OMITTED
1817
1998
  * from the result (exactOptionalPropertyTypes semantics). Components past
1818
1999
  * position 12 are silently ignored in v1.
@@ -1832,7 +2013,7 @@ interface XTN {
1832
2013
  declare function parseXtn(rep: RawRepetition, enc: EncodingCharacters): XTN;
1833
2014
 
1834
2015
  /**
1835
- * `Field` — wrapper over a `RawField` exposing HL7 null/empty discrimination
2016
+ * `Field`: wrapper over a `RawField` exposing HL7 null/empty discrimination
1836
2017
  * (`isNull`), the raw repetitions tree, and a convenience `value` getter that
1837
2018
  * reads the first subcomponent of the first component of the first
1838
2019
  * repetition. Constructed internally by `Segment.field(n)`; user code never
@@ -1841,7 +2022,7 @@ declare function parseXtn(rep: RawRepetition, enc: EncodingCharacters): XTN;
1841
2022
  * Typed composite coercions (`asXpn`, `asXad`, `asCx`, `asCwe`, `asCe`,
1842
2023
  * `asXtn`, `asPl`, `asTs`, `asNm`, `asHd`) delegate to the corresponding
1843
2024
  * composite parsers from `./types/*`. Coercions are lazy and NOT memoized
1844
- * in v1 (D-09) — each call re-parses the first repetition. Empty fields
2025
+ * in v1 (D-09): each call re-parses the first repetition. Empty fields
1845
2026
  * return empty typed objects (`{}` for optional-field composites,
1846
2027
  * `{ raw: "", date: undefined }` / `{ raw: "", value: undefined }` for
1847
2028
  * the TS/NM scalar composites).
@@ -1850,7 +2031,7 @@ declare function parseXtn(rep: RawRepetition, enc: EncodingCharacters): XTN;
1850
2031
  /**
1851
2032
  * Wrapper over a `RawField` exposing HL7 null/empty discrimination
1852
2033
  * (`isNull`), the repetitions tree, and a decoded `value` getter.
1853
- * `seg.field(3) === seg.field(3)` — Field instances are referentially stable
2034
+ * `seg.field(3) === seg.field(3)`: Field instances are referentially stable
1854
2035
  * per segment position (D-12).
1855
2036
  *
1856
2037
  * @example
@@ -1858,19 +2039,19 @@ declare function parseXtn(rep: RawRepetition, enc: EncodingCharacters): XTN;
1858
2039
  * import { parseHL7 } from "@cosyte/hl7";
1859
2040
  * const msg = parseHL7(raw);
1860
2041
  * const pid5 = msg.segments("PID")[0]?.field(5);
1861
- * console.log(pid5?.value); // "Smith" — decoded at parse
1862
- * console.log(pid5?.isNull); // false — HL7 explicit null is "", absent is not
2042
+ * console.log(pid5?.value); // "Smith": decoded at parse
2043
+ * console.log(pid5?.isNull); // false: HL7 explicit null is "", absent is not
1863
2044
  * console.log(pid5?.repetitions.length); // 1
1864
2045
  * ```
1865
2046
  */
1866
2047
  declare class Field {
1867
- /** HL7 null indicator — `true` iff the underlying field was the two-char literal `""`. */
2048
+ /** HL7 null indicator: `true` iff the underlying field was the two-char literal `""`. */
1868
2049
  readonly isNull: boolean;
1869
2050
  /** Reference to the underlying `RawField.repetitions` (no defensive copy). */
1870
2051
  readonly repetitions: readonly RawRepetition[];
1871
2052
  /** The 5 encoding characters for this message. Exposed for composite parsers (Plan 04). @internal */
1872
2053
  readonly enc: EncodingCharacters;
1873
- /** Position of this field in the parent message — used for position-aware error messages. @internal */
2054
+ /** Position of this field in the parent message: used for position-aware error messages. @internal */
1874
2055
  readonly position: Hl7Position;
1875
2056
  /** The full `RawField` this wrapper wraps. Exposed for composite parsers (Plan 02/03/04). @internal */
1876
2057
  readonly raw: RawField;
@@ -1882,7 +2063,7 @@ declare class Field {
1882
2063
  constructor(raw: RawField, enc: EncodingCharacters, position: Hl7Position);
1883
2064
  /**
1884
2065
  * First-repetition, first-component, first-subcomponent value as a decoded
1885
- * string — unescaped ONCE by the tokenizer on parse, returned verbatim here
2066
+ * string: unescaped ONCE by the tokenizer on parse, returned verbatim here
1886
2067
  * (never re-unescaped, HL7-VALUE-REDECODE). Returns `""` when the field is
1887
2068
  * empty or HL7 null. Equivalent to `msg.get('SEG.N')` for a top-level access.
1888
2069
  *
@@ -1895,13 +2076,13 @@ declare class Field {
1895
2076
  */
1896
2077
  get value(): string;
1897
2078
  /**
1898
- * The field's **canonical wire text** — the full field re-serialized with
2079
+ * The field's **canonical wire text**: the full field re-serialized with
1899
2080
  * the active delimiters and re-escaped content (repetitions, components,
1900
2081
  * and subcomponents included). Contrast with {@link value}, which
1901
2082
  * returns only the first subcomponent of the first component of the first
1902
- * repetition (decoded once at parse — never re-unescaped).
2083
+ * repetition (decoded once at parse: never re-unescaped).
1903
2084
  *
1904
- * Use this when a field must be compared or echoed as a whole — e.g.
2085
+ * Use this when a field must be compared or echoed as a whole: e.g.
1905
2086
  * correlating an ACK's MSA-2 against the inbound MSH-10, where a
1906
2087
  * vendor-quirk control id containing an unescaped delimiter (`ID^X`) must
1907
2088
  * not be truncated to its first component.
@@ -1920,7 +2101,7 @@ declare class Field {
1920
2101
  *
1921
2102
  * **MSH-1/MSH-2 caveat.** Like {@link value}, calling this on MSH-1 or
1922
2103
  * MSH-2 (the delimiter-definition fields) re-escapes the encoding
1923
- * characters themselves and produces garbage — those two fields are only
2104
+ * characters themselves and produces garbage: those two fields are only
1924
2105
  * meaningful through `Hl7Message.encodingCharacters`.
1925
2106
  *
1926
2107
  * @example
@@ -1933,12 +2114,31 @@ declare class Field {
1933
2114
  */
1934
2115
  get text(): string;
1935
2116
  /**
1936
- * Return a synthetic empty `Field` sentinel — used by `Segment.field(n)` to
2117
+ * Render this field's formatted text (HL7 v2 §2.7 highlight + formatting
2118
+ * escapes) into a normalized {@link RenderedText} display model: plain text
2119
+ * plus highlight-aware runs. A **read projection** over the field's
2120
+ * byte-verbatim wire {@link text}: it never mutates the raw value, and it
2121
+ * never fabricates (an unrenderable escape is preserved + flagged). Use this
2122
+ * to surface a clinical narrative (an NTE / OBX-5 note) to a human without
2123
+ * the raw `\.br\` / `\H\` sentinels.
2124
+ *
2125
+ * @param opts - see {@link RenderTextOptions} (e.g. a custom line-break string).
2126
+ * @returns the normalized display model.
2127
+ *
2128
+ * @example
2129
+ * ```ts
2130
+ * const note = msg.segments("OBX")[0]?.field(5);
2131
+ * note?.render().text; // "Specimen received.\nGross exam normal."
2132
+ * ```
2133
+ */
2134
+ render(opts?: RenderTextOptions): RenderedText;
2135
+ /**
2136
+ * Return a synthetic empty `Field` sentinel: used by `Segment.field(n)` to
1937
2137
  * honor MODEL-05's "never throws on missing" contract. The returned Field
1938
2138
  * has `isNull === false`, `repetitions === []`, and `value === ""`.
1939
2139
  * Referentially stable across calls (same instance returned each time).
1940
2140
  *
1941
- * The `enc` argument is accepted for API symmetry but ignored — the
2141
+ * The `enc` argument is accepted for API symmetry but ignored: the
1942
2142
  * synthetic field carries no content, so unescape would be a no-op
1943
2143
  * regardless of the active encoding characters.
1944
2144
  *
@@ -1953,7 +2153,7 @@ declare class Field {
1953
2153
  /**
1954
2154
  * Coerce this field's first repetition to a typed `XPN` (Extended Person
1955
2155
  * Name). Absent components are OMITTED from the result
1956
- * (`exactOptionalPropertyTypes`). Not memoized in v1 — each call re-parses
2156
+ * (`exactOptionalPropertyTypes`). Not memoized in v1: each call re-parses
1957
2157
  * (D-09).
1958
2158
  *
1959
2159
  * @example
@@ -2029,7 +2229,7 @@ declare class Field {
2029
2229
  */
2030
2230
  asPl(): PL;
2031
2231
  /**
2032
- * Coerce this field's first repetition to a typed `TS` (Time Stamp) — the
2232
+ * Coerce this field's first repetition to a typed `TS` (Time Stamp): the
2033
2233
  * fidelity `DtmParts` (raw + parts + precision + timezone). `valid` is
2034
2234
  * `false` on unparseable input (no throw). Build an absolute instant only on
2035
2235
  * explicit request via `dtmToDate(ts)`.
@@ -2043,7 +2243,7 @@ declare class Field {
2043
2243
  asTs(): TS;
2044
2244
  /**
2045
2245
  * Coerce this field's first repetition to a typed `NM` (Numeric).
2046
- * `{ raw, value }` — `value` is `undefined` on non-numeric input.
2246
+ * `{ raw, value }`: `value` is `undefined` on non-numeric input.
2047
2247
  *
2048
2248
  * @example
2049
2249
  * ```ts
@@ -2094,18 +2294,18 @@ declare class Field {
2094
2294
  }
2095
2295
 
2096
2296
  /**
2097
- * `Segment` — wrapper class over a `RawSegment` that exposes `field(n)` with
2297
+ * `Segment`: wrapper class over a `RawSegment` that exposes `field(n)` with
2098
2298
  * referentially stable `Field` instances (D-12). Constructed internally by
2099
2299
  * `Hl7Message.segments(type)` / `Hl7Message.allSegments()`; user code never
2100
2300
  * calls `new Segment(...)` directly.
2101
2301
  *
2102
- * The wrapper does NOT copy `raw.fields` — it holds a reference so mutations
2302
+ * The wrapper does NOT copy `raw.fields`: it holds a reference so mutations
2103
2303
  * through Plan 04's `setField` / `addSegment` / `removeSegment` stay visible.
2104
2304
  */
2105
2305
 
2106
2306
  /**
2107
2307
  * Wrapper over a `RawSegment` exposing typed per-position `Field` instances.
2108
- * `seg.field(3) === seg.field(3)` — referential stability is guaranteed per
2308
+ * `seg.field(3) === seg.field(3)`: referential stability is guaranteed per
2109
2309
  * segment instance.
2110
2310
  *
2111
2311
  * @example
@@ -2119,7 +2319,7 @@ declare class Field {
2119
2319
  declare class Segment {
2120
2320
  /** Segment name (3 chars, e.g. `"PID"`, `"OBX"`, `"ZPI"`). */
2121
2321
  readonly type: string;
2122
- /** Reference to the underlying `RawSegment.fields` — 1-indexed per HL7 convention. */
2322
+ /** Reference to the underlying `RawSegment.fields`: 1-indexed per HL7 convention. */
2123
2323
  readonly fields: readonly RawField[];
2124
2324
  /** The 5 encoding characters for this message. Exposed for composite parsers. @internal */
2125
2325
  readonly enc: EncodingCharacters;
@@ -2135,7 +2335,7 @@ declare class Segment {
2135
2335
  * @internal
2136
2336
  */
2137
2337
  readonly customFields: Readonly<Record<string, number>> | undefined;
2138
- /** Lazy cache of Field wrappers — one per fields[] position. @internal */
2338
+ /** Lazy cache of Field wrappers: one per fields[] position. @internal */
2139
2339
  private _fieldWrappers;
2140
2340
  /**
2141
2341
  * Construct a new `Segment`. Called internally by `Hl7Message`; user code
@@ -2151,16 +2351,16 @@ declare class Segment {
2151
2351
  constructor(raw: RawSegment, enc: EncodingCharacters, absoluteIndex: number, customFields?: Readonly<Record<string, number>>);
2152
2352
  /**
2153
2353
  * Return the `Field` wrapper at HL7 position `n`. Indexing follows the HL7
2154
- * 1-indexed convention — `seg.field(5)` on a PID segment maps to PID-5.
2354
+ * 1-indexed convention: `seg.field(5)` on a PID segment maps to PID-5.
2155
2355
  * MSH segments use the same user-facing convention: `msh.field(1)` returns
2156
2356
  * the field-separator (MSH-1), `msh.field(2)` returns encoding chars
2157
- * (MSH-2), `msh.field(3)` returns MSH-3, and so on — the internal
2357
+ * (MSH-2), `msh.field(3)` returns MSH-3, and so on: the internal
2158
2358
  * `fields[N-1]` offset for MSH segments is applied here (mirrors the
2159
2359
  * dot-path resolver in `dot-path.ts`, keeping `msg.segments('MSH')[0].field(3)`
2160
2360
  * and `msg.get('MSH.3')` in agreement).
2161
2361
  *
2162
2362
  * Returns a synthetic empty `Field` (`.isNull === false`, `.value === ""`)
2163
- * when `n` is out of range — never throws (MODEL-05). Successive calls with
2363
+ * when `n` is out of range: never throws (MODEL-05). Successive calls with
2164
2364
  * the same `n` return the same `Field` instance (D-12).
2165
2365
  *
2166
2366
  * @example
@@ -2175,13 +2375,13 @@ declare class Segment {
2175
2375
  /**
2176
2376
  * Return the `Field` at the profile-declared position for `name`, or
2177
2377
  * `undefined` when no custom mapping exists (PROF-07). Unlike `field(n)`,
2178
- * missing names return `undefined` — NOT a synthetic empty Field — so
2378
+ * missing names return `undefined`, NOT a synthetic empty Field, so
2179
2379
  * typos surface instead of silently resolving to an empty string (D-14).
2180
2380
  *
2181
2381
  * For segments without a profile-declared customSegments slice (most
2182
2382
  * non-Z segments, and any Z-segment whose host message had no profile
2183
2383
  * applied), this method always returns `undefined` (D-15 defense-in-depth
2184
- * — D-05 already rejects standard-segment overlays at `defineProfile()`
2384
+ *: D-05 already rejects standard-segment overlays at `defineProfile()`
2185
2385
  * time).
2186
2386
  *
2187
2387
  * When the declared position is out of range for the underlying
@@ -2200,7 +2400,7 @@ declare class Segment {
2200
2400
  }
2201
2401
 
2202
2402
  /**
2203
- * `identityEvents` — roadmap Phase K read-side helper that recognizes the ADT
2403
+ * `identityEvents`: roadmap Phase K read-side helper that recognizes the ADT
2204
2404
  * patient-identity management trigger events and surfaces the MRG segment's
2205
2405
  * *prior* (non-surviving) identifiers alongside the PID/PV1 *surviving*
2206
2406
  * identifiers, each labelled by role.
@@ -2208,7 +2408,7 @@ declare class Segment {
2208
2408
  * Spec traceability (HL7 v2 Ch. 3, Patient Administration):
2209
2409
  * - A18 "The PID segment contains the surviving patient ID information. The
2210
2410
  * MRG segment contains the non-surviving information." The merge direction
2211
- * is spec-explicit and constant: **MRG (prior) → PID (surviving)** — this
2411
+ * is spec-explicit and constant: **MRG (prior) → PID (surviving)**: this
2212
2412
  * helper NEVER infers it from content and never reverses it.
2213
2413
  * - Merge family (§3.3.34–§3.3.42): A34/A35/A36 (v2.3-era merges), A39 merge
2214
2414
  * person, A40 merge patient identifier list, A41 merge account, A42 merge
@@ -2217,33 +2417,33 @@ declare class Segment {
2217
2417
  * A28 / A31 (PID only, no MRG).
2218
2418
  * - MRG field map is **version-scoped** (v2.5.1 §3.4.10): MRG-1 prior patient
2219
2419
  * identifier list (CX, repeating), MRG-3 prior patient account number (CX),
2220
- * MRG-4 prior patient ID (CX, backward-compat only — **withdrawn as of
2420
+ * MRG-4 prior patient ID (CX, backward-compat only: **withdrawn as of
2221
2421
  * v2.7** in favour of MRG-1), MRG-5 prior visit number (CX), MRG-7 prior
2222
2422
  * patient name (XPN). MRG-2 / MRG-6 (prior *alternate* patient/visit IDs,
2223
2423
  * also withdrawn v2.7) are deliberately not surfaced. On a v2.7+ message
2224
- * (MSH-12) the withdrawn MRG-4 — and the symmetric withdrawn PID-2 — are
2424
+ * (MSH-12) the withdrawn MRG-4 (and the symmetric withdrawn PID-2) are
2225
2425
  * NOT read as identity fields.
2226
2426
  *
2227
2427
  * Fail-safe: a merge/move event missing either side of the MRG→PID pair
2228
2428
  * surfaces what is present plus a `MERGE_MISSING_PRIOR_OR_SURVIVOR` warning on
2229
- * the event — the MRG is **never dropped** (an orphaned MRG yields its own
2429
+ * the event: the MRG is **never dropped** (an orphaned MRG yields its own
2230
2430
  * event) and the direction is **never guessed**. The helper never throws.
2231
2431
  *
2232
2432
  * PHI note: identifiers and names are the *payload* of the typed view (by
2233
- * design — the consumer needs them to apply the merge), but warning messages
2433
+ * design: the consumer needs them to apply the merge), but warning messages
2234
2434
  * carry only structural facts (event code + missing role), never a value.
2235
2435
  *
2236
2436
  * Applying the merge (re-pointing stored data to the survivor) is the
2237
- * consumer's / integration engine's job — this helper only surfaces it.
2437
+ * consumer's / integration engine's job: this helper only surfaces it.
2238
2438
  */
2239
2439
 
2240
2440
  /**
2241
2441
  * Classification of a recognized identity trigger event.
2242
2442
  *
2243
- * - `merge` — A18 / A34 / A35 / A36 / A39 / A40 / A41 / A42 (MRG expected)
2244
- * - `move` — A43 / A44 (MRG expected)
2245
- * - `link` / `unlink` — A24 / A37 (two PID groups, no MRG)
2246
- * - `add` / `update` — A28 / A31 (person add/update, no MRG)
2443
+ * - `merge`: A18 / A34 / A35 / A36 / A39 / A40 / A41 / A42 (MRG expected)
2444
+ * - `move`: A43 / A44 (MRG expected)
2445
+ * - `link` / `unlink`: A24 / A37 (two PID groups, no MRG)
2446
+ * - `add` / `update`: A28 / A31 (person add/update, no MRG)
2247
2447
  *
2248
2448
  * @example
2249
2449
  * ```ts
@@ -2255,7 +2455,7 @@ type IdentityEventKind = "merge" | "move" | "link" | "unlink" | "add" | "update"
2255
2455
  /**
2256
2456
  * Role of one party in an identity event. `surviving` / `subject` / `linked`
2257
2457
  * parties are ONLY ever sourced from PID (+ PV1); `prior` parties are ONLY
2258
- * ever sourced from MRG — the role-labelling invariant Phase K exists for.
2458
+ * ever sourced from MRG: the role-labelling invariant Phase K exists for.
2259
2459
  *
2260
2460
  * @example
2261
2461
  * ```ts
@@ -2289,15 +2489,15 @@ type IdentityRole = "surviving" | "prior" | "linked" | "subject";
2289
2489
  * ```
2290
2490
  */
2291
2491
  interface IdentityParty {
2292
- /** Role of this party in the event — the safety-critical label. */
2492
+ /** Role of this party in the event: the safety-critical label. */
2293
2493
  readonly role: IdentityRole;
2294
- /** Segment this party was sourced from — provenance for the role label. */
2494
+ /** Segment this party was sourced from: provenance for the role label. */
2295
2495
  readonly sourceSegment: "PID" | "MRG";
2296
2496
  /** Identifier list (PID-3 / MRG-1), every non-empty CX repetition. */
2297
2497
  readonly identifiers: readonly CX[];
2298
2498
  /**
2299
2499
  * Legacy single patient ID (PID-2 / MRG-4). Backward-compat only; withdrawn
2300
- * as of HL7 v2.7 — OMITTED (not read) when MSH-12 declares v2.7 or later.
2500
+ * as of HL7 v2.7: OMITTED (not read) when MSH-12 declares v2.7 or later.
2301
2501
  */
2302
2502
  readonly legacyPatientId?: CX;
2303
2503
  /** Patient account number (PID-18 / MRG-3). */
@@ -2310,11 +2510,11 @@ interface IdentityParty {
2310
2510
  /**
2311
2511
  * One recognized patient-identity event. For `merge` / `move` kinds the
2312
2512
  * `surviving` (PID/PV1-sourced) and `prior` (MRG-sourced) parties are also
2313
- * exposed directly, with the spec-constant `direction: "MRG_TO_PID"` — the
2513
+ * exposed directly, with the spec-constant `direction: "MRG_TO_PID"`: the
2314
2514
  * prior identifiers are the ones being retired in favour of the surviving
2315
2515
  * ones, never the reverse (HL7 v2 Ch. 3, A18/A39/A40).
2316
2516
  *
2317
- * `parties` is the complete role-labelled surface in document order — nothing
2517
+ * `parties` is the complete role-labelled surface in document order: nothing
2318
2518
  * present in the message is dropped, including a nonconforming MRG in a
2319
2519
  * link/add message (surfaced as a `prior`-role party).
2320
2520
  *
@@ -2330,7 +2530,7 @@ interface IdentityParty {
2330
2530
  * if (ev.kind === "merge" && ev.prior && ev.surviving) {
2331
2531
  * // retire ev.prior.identifiers in favour of ev.surviving.identifiers
2332
2532
  * } else if (ev.warnings.length > 0) {
2333
- * // incomplete pair — do NOT apply; route for review
2533
+ * // incomplete pair: do NOT apply; route for review
2334
2534
  * }
2335
2535
  * }
2336
2536
  * ```
@@ -2340,11 +2540,11 @@ interface IdentityEvent {
2340
2540
  readonly eventType: string;
2341
2541
  /** Classification of the trigger event. */
2342
2542
  readonly kind: IdentityEventKind;
2343
- /** Every party in document order, role-labelled — the complete surface. */
2543
+ /** Every party in document order, role-labelled: the complete surface. */
2344
2544
  readonly parties: readonly IdentityParty[];
2345
- /** The surviving party (merge/move) — ONLY ever sourced from PID/PV1. */
2545
+ /** The surviving party (merge/move): ONLY ever sourced from PID/PV1. */
2346
2546
  readonly surviving?: IdentityParty;
2347
- /** The prior (non-surviving) party (merge/move) — ONLY ever sourced from MRG. */
2547
+ /** The prior (non-surviving) party (merge/move): ONLY ever sourced from MRG. */
2348
2548
  readonly prior?: IdentityParty;
2349
2549
  /**
2350
2550
  * Spec-constant merge/move direction: the MRG (prior) identifiers merge
@@ -2357,14 +2557,14 @@ interface IdentityEvent {
2357
2557
  }
2358
2558
 
2359
2559
  /**
2360
- * Phase 4 helper type declarations — the 9 typed shapes returned by
2560
+ * Phase 4 helper type declarations: the 9 typed shapes returned by
2361
2561
  * `Hl7Message.meta`/`.patient`/`.visit` getters and the 6 collection methods
2362
2562
  * (`observations()`, `orders()`, `nextOfKin()`, `allergies()`, `diagnoses()`,
2363
2563
  * `insurance()`). Every field is `readonly`; every optional key is
2364
2564
  * `exactOptionalPropertyTypes`-safe (never `| undefined` on the declaration).
2365
2565
  *
2366
2566
  * Types compose on the 11 v1 composites from `src/model/types/*.ts` (XPN, XAD,
2367
- * CX, CWE, CE, XTN, PL, XCN) — helpers are pure views on top of Phase 3's
2567
+ * CX, CWE, CE, XTN, PL, XCN): helpers are pure views on top of Phase 3's
2368
2568
  * composite coercions, never re-parsing the raw tree.
2369
2569
  *
2370
2570
  * Field lists locked by Phase 4 CONTEXT.md decisions D-01..D-24. Nine interfaces:
@@ -2401,7 +2601,7 @@ interface Meta {
2401
2601
  readonly triggerEvent?: string;
2402
2602
  /** MSH-9.3 message structure (e.g. "ADT_A01"). */
2403
2603
  readonly messageStructure?: string;
2404
- /** MSH-10 message control ID — unique per message per sender. */
2604
+ /** MSH-10 message control ID: unique per message per sender. */
2405
2605
  readonly controlId?: string;
2406
2606
  /** MSH-7 message date/time as the fidelity `TS` (Phase N). */
2407
2607
  readonly timestamp?: TS;
@@ -2422,7 +2622,7 @@ interface Meta {
2422
2622
  * PID-derived patient view (HELPERS-02). `msg.patient` is `undefined` (D-04)
2423
2623
  * when no PID segment exists; this interface describes the shape when
2424
2624
  * present. `identifiers` and `phoneNumbers` are ALWAYS present as arrays
2425
- * (D-09 / D-20) — empty when the underlying field is absent. `name` is
2625
+ * (D-09 / D-20): empty when the underlying field is absent. `name` is
2426
2626
  * ALWAYS present (D-19) even if `{}` when PID-5 is empty.
2427
2627
  *
2428
2628
  * @example
@@ -2457,7 +2657,7 @@ interface Patient {
2457
2657
  readonly fullName?: string;
2458
2658
  /**
2459
2659
  * PID-7 date of birth as the fidelity `TS` (Phase N). A day-only DOB keeps
2460
- * `precision: "day"` — never coerced to a UTC-midnight instant that would
2660
+ * `precision: "day"`: never coerced to a UTC-midnight instant that would
2461
2661
  * read as the previous day in a negative-offset zone.
2462
2662
  */
2463
2663
  readonly dateOfBirth?: TS;
@@ -2474,7 +2674,7 @@ interface Patient {
2474
2674
  /** PID-15 primary language. */
2475
2675
  readonly language?: CE;
2476
2676
  /**
2477
- * NTE note lines positionally attached to the (first) PID (Phase P) — notes
2677
+ * NTE note lines positionally attached to the (first) PID (Phase P): notes
2478
2678
  * immediately following the patient's PID segment, HL7-unescaped, in
2479
2679
  * document order. OMITTED when the patient carries no notes. High-PHI-risk
2480
2680
  * clinical narrative.
@@ -2530,7 +2730,7 @@ interface Visit {
2530
2730
  * ```
2531
2731
  */
2532
2732
  interface ObservationBase {
2533
- /** OBX-1 set id (string — typically sequential "1", "2", ...). */
2733
+ /** OBX-1 set id (string: typically sequential "1", "2", ...). */
2534
2734
  readonly setId?: string;
2535
2735
  /** OBX-3 observation identifier. Always present (may be `{}` if OBX-3 absent). */
2536
2736
  readonly identifier: CWE;
@@ -2538,11 +2738,11 @@ interface ObservationBase {
2538
2738
  readonly units?: CWE;
2539
2739
  /**
2540
2740
  * `true` iff OBX-6's coding system (CWE.3, "name of coding system") is
2541
- * exactly `UCUM` (HL7 Table 0396) — i.e. the unit is declared UCUM and is
2741
+ * exactly `UCUM` (HL7 Table 0396): i.e. the unit is declared UCUM and is
2542
2742
  * safe to interpret as a computable unit. `false` means a unit IS present
2543
2743
  * but is NOT declared UCUM (e.g. a local code or free text) and is surfaced
2544
2744
  * as-is, never coerced. OMITTED when OBX-6 is absent. This is a *claim* check
2545
- * only — the library does not validate UCUM grammar or check the alternate
2745
+ * only: the library does not validate UCUM grammar or check the alternate
2546
2746
  * coding system (CWE.6).
2547
2747
  */
2548
2748
  readonly unitsAreUcum?: boolean;
@@ -2555,7 +2755,7 @@ interface ObservationBase {
2555
2755
  /** OBX-14 date/time of observation as the fidelity `TS` (Phase N). */
2556
2756
  readonly observedDateTime?: TS;
2557
2757
  /**
2558
- * NTE note lines positionally attached to this OBX (Phase P) — each
2758
+ * NTE note lines positionally attached to this OBX (Phase P): each
2559
2759
  * non-empty NTE-3 (Comment, FT) repetition of every NTE immediately
2560
2760
  * following this observation, HL7-unescaped, in document order. OMITTED when
2561
2761
  * the observation carries no notes. High-PHI-risk clinical narrative.
@@ -2608,30 +2808,30 @@ type Observation = ObservationBase & ({
2608
2808
  readonly value: string | undefined;
2609
2809
  });
2610
2810
  /**
2611
- * How an order/medication `RepeatPattern` code (HL7 Table 0335) is classified —
2811
+ * How an order/medication `RepeatPattern` code (HL7 Table 0335) is classified,
2612
2812
  * **provenance only, never used to resolve a schedule** (Phase M). The `code`
2613
2813
  * is always authoritative and surfaced verbatim; this flag only tells a
2614
2814
  * consumer *what kind* of pattern it is looking at so it can decide whether a
2615
2815
  * load-bearing integer is present.
2616
2816
  *
2617
- * - `"parametric"` — a `Q<integer><unit>` template (`Q6H`, `Q30M`, `Q2D`,
2817
+ * - `"parametric"`: a `Q<integer><unit>` template (`Q6H`, `Q30M`, `Q2D`,
2618
2818
  * `Q1W`, `Q3J5`) whose **integer is load-bearing**: `Q6H` (every 6 hours) is
2619
2819
  * a different dose count from `Q8H`. The parsed integer + unit ride on
2620
2820
  * {@link RepeatPattern.interval}.
2621
- * - `"named"` — a recognized fixed Table-0335 mnemonic scheduled at
2821
+ * - `"named"`: a recognized fixed Table-0335 mnemonic scheduled at
2622
2822
  * institution-specified times (`BID`, `TID`, `QID`, `QOD`, `QHS`, `QAM`,
2623
2823
  * `QPM`, `QSHIFT`, `PRN`, `AC`, `PC`, `HS`, `C`). No numeric interval.
2624
- * - `"unknown"` — anything else (a local code, free text, an unrecognized
2824
+ * - `"unknown"`: anything else (a local code, free text, an unrecognized
2625
2825
  * mnemonic). Surfaced **verbatim**, never mapped to a frequency.
2626
2826
  */
2627
2827
  type RepeatPatternKind = "parametric" | "named" | "unknown";
2628
2828
  /**
2629
- * An order/medication timing **repeat pattern** (HL7 Table 0335) — the
2829
+ * An order/medication timing **repeat pattern** (HL7 Table 0335): the
2630
2830
  * frequency/SIG field (TQ1-3, or the legacy embedded TQ interval RI.1), Phase M.
2631
2831
  *
2632
2832
  * **Safety contract.** `code` is the **decoded field value** (HL7 escapes are
2633
2833
  * unescaped as with every field read) and is **never resolved to clock times,
2634
- * normalized, or mapped to a different frequency** — reading `Q6H` as "daily"
2834
+ * normalized, or mapped to a different frequency**: reading `Q6H` as "daily"
2635
2835
  * or silently dropping a `BID` changes the administered dose count, a
2636
2836
  * transcription-class harm. `kind`/`interval` are convenience provenance ONLY;
2637
2837
  * `code` is the authoritative value.
@@ -2646,12 +2846,12 @@ type RepeatPatternKind = "parametric" | "named" | "unknown";
2646
2846
  interface RepeatPattern {
2647
2847
  /** The Table-0335 repeat-pattern code exactly as authored (e.g. `"Q6H"`, `"BID"`). Never normalized. */
2648
2848
  readonly code: string;
2649
- /** Provenance classification of `code` — never used to resolve a schedule. See {@link RepeatPatternKind}. */
2849
+ /** Provenance classification of `code`: never used to resolve a schedule. See {@link RepeatPatternKind}. */
2650
2850
  readonly kind: RepeatPatternKind;
2651
2851
  /**
2652
2852
  * For a `"parametric"` `Q<integer><unit>` template only: the load-bearing
2653
2853
  * integer and its unit letter (`S`/`M`/`H`/`D`/`W`/`L`, or `J` for
2654
- * day-of-week). OMITTED for `"named"`/`"unknown"` patterns. Informational —
2854
+ * day-of-week). OMITTED for `"named"`/`"unknown"` patterns. Informational,
2655
2855
  * `code` remains authoritative.
2656
2856
  */
2657
2857
  readonly interval?: {
@@ -2660,7 +2860,7 @@ interface RepeatPattern {
2660
2860
  };
2661
2861
  }
2662
2862
  /**
2663
- * A composite-quantity (CQ) value on an order/medication timing — the TQ1-2
2863
+ * A composite-quantity (CQ) value on an order/medication timing: the TQ1-2
2664
2864
  * service quantity, Phase M. `value` is strict-`Number()` parsed (`undefined`,
2665
2865
  * never `NaN`); `units` carries any CQ.2 units. Both keys OMITTED when absent.
2666
2866
  *
@@ -2677,7 +2877,7 @@ interface TimingQuantity {
2677
2877
  readonly units?: CWE;
2678
2878
  }
2679
2879
  /**
2680
- * The order/medication **timing** structure — one TQ1 segment (v2.5+) or the
2880
+ * The order/medication **timing** structure: one TQ1 segment (v2.5+) or the
2681
2881
  * legacy embedded TQ in ORC-7 / RXE-1 (pre-v2.5), Phase M. Attached to
2682
2882
  * {@link Order.timings} and {@link Medication.timings}.
2683
2883
  *
@@ -2686,7 +2886,7 @@ interface TimingQuantity {
2686
2886
  * clock times, or interpret sig. The load-bearing {@link repeatPattern} and
2687
2887
  * {@link totalOccurrences} are preserved verbatim (see {@link RepeatPattern});
2688
2888
  * `startDateTime`/`endDateTime` keep the Phase N `TS` precision + timezone
2689
- * fidelity. A malformed timing never throws — absent pieces are omitted keys.
2889
+ * fidelity. A malformed timing never throws: absent pieces are omitted keys.
2690
2890
  *
2691
2891
  * @example
2692
2892
  * ```ts
@@ -2704,18 +2904,18 @@ interface OrderTiming {
2704
2904
  * Which structure this timing was read from: the dedicated **TQ1** segment
2705
2905
  * (v2.5+) or the **legacy** embedded TQ data type in ORC-7 (orders) / RXE-1
2706
2906
  * (encoded medications, pre-v2.5). The library treats the presence of a TQ1
2707
- * segment as the v2.5+ signal — the legacy embedded TQ is surfaced only when
2907
+ * segment as the v2.5+ signal: the legacy embedded TQ is surfaced only when
2708
2908
  * no TQ1 accompanies the order, so the same timing is never double-counted
2709
2909
  * and a legacy-only timing is never dropped.
2710
2910
  */
2711
2911
  readonly source: "TQ1" | "legacy";
2712
2912
  /** TQ1-2 / legacy TQ.1 service quantity (CQ). */
2713
2913
  readonly quantity?: TimingQuantity;
2714
- /** TQ1-3 / legacy TQ.2 interval RI.1 repeat pattern (Table 0335) — verbatim. See {@link RepeatPattern}. */
2914
+ /** TQ1-3 / legacy TQ.2 interval RI.1 repeat pattern (Table 0335): verbatim. See {@link RepeatPattern}. */
2715
2915
  readonly repeatPattern?: RepeatPattern;
2716
- /** TQ1-4 / legacy TQ.2 interval RI.2 explicit time(s) — surfaced verbatim (first repetition/value). */
2916
+ /** TQ1-4 / legacy TQ.2 interval RI.2 explicit time(s): surfaced verbatim (first repetition/value). */
2717
2917
  readonly explicitTime?: string;
2718
- /** TQ1-6 / legacy TQ.3 service duration — surfaced verbatim. */
2918
+ /** TQ1-6 / legacy TQ.3 service duration: surfaced verbatim. */
2719
2919
  readonly serviceDuration?: string;
2720
2920
  /** TQ1-7 / legacy TQ.4 start date/time as the fidelity `TS` (Phase N). */
2721
2921
  readonly startDateTime?: TS;
@@ -2724,7 +2924,7 @@ interface OrderTiming {
2724
2924
  /** TQ1-9 priority (CWE) / legacy TQ.6 priority (surfaced as a CWE `{ identifier }`). */
2725
2925
  readonly priority?: CWE;
2726
2926
  /**
2727
- * TQ1-14 / legacy TQ.12 total occurrences (NM) — how many times the service
2927
+ * TQ1-14 / legacy TQ.12 total occurrences (NM): how many times the service
2728
2928
  * is to be performed (strict-parsed; never `NaN`). **TQ1-14, not TQ1-11**
2729
2929
  * (TQ1-11 is Text Instruction). Load-bearing: losing it drops the total
2730
2930
  * administered count.
@@ -2733,8 +2933,8 @@ interface OrderTiming {
2733
2933
  }
2734
2934
  /**
2735
2935
  * OBR-derived order (HELPERS-05, D-16) with positionally-grouped OBX children
2736
- * (D-12). `observations` is ALWAYS present — empty when no OBX follows this
2737
- * OBR before the next OBR or end-of-message. Phase M adds `timings` — ALWAYS
2936
+ * (D-12). `observations` is ALWAYS present: empty when no OBX follows this
2937
+ * OBR before the next OBR or end-of-message. Phase M adds `timings`: ALWAYS
2738
2938
  * present, empty when the order carries no TQ1 / legacy embedded TQ.
2739
2939
  *
2740
2940
  * @example
@@ -2757,7 +2957,7 @@ interface Order {
2757
2957
  readonly fillerOrderNumber?: string;
2758
2958
  /** OBR-4 universal service identifier (test code + description). */
2759
2959
  readonly universalServiceId?: CWE;
2760
- /** OBR-5 order status (v1 — Phase 7 may reconcile with OBR-25). */
2960
+ /** OBR-5 order status (v1: Phase 7 may reconcile with OBR-25). */
2761
2961
  readonly orderStatus?: string;
2762
2962
  /** ORC-1 order control when an ORC precedes this OBR. */
2763
2963
  readonly orderControl?: string;
@@ -2767,23 +2967,23 @@ interface Order {
2767
2967
  readonly observations: readonly Observation[];
2768
2968
  /**
2769
2969
  * TQ1 / legacy embedded-TQ timing(s) grouped under this order (Phase M).
2770
- * Always present — empty when the order carries no timing. See
2970
+ * Always present: empty when the order carries no timing. See
2771
2971
  * {@link OrderTiming}.
2772
2972
  */
2773
2973
  readonly timings: readonly OrderTiming[];
2774
2974
  /**
2775
- * NTE note lines positionally attached to this order (Phase P) — the
2975
+ * NTE note lines positionally attached to this order (Phase P): the
2776
2976
  * ORC-region notes (before the OBR) followed by the OBR-region notes, in
2777
2977
  * document order. Several ORCs before one OBR all contribute here; nothing is
2778
2978
  * dropped. OMITTED when the order carries no notes. A note on a trailing or
2779
2979
  * dangling ORC that never opens an order is surfaced at message level
2780
- * (`msg.notes()`), not here — still never dropped. High-PHI-risk clinical
2980
+ * (`msg.notes()`), not here: still never dropped. High-PHI-risk clinical
2781
2981
  * narrative.
2782
2982
  */
2783
2983
  readonly notes?: readonly string[];
2784
2984
  }
2785
2985
  /**
2786
- * NK1-derived next-of-kin entry (HELPERS-06). Lean subset — callers can
2986
+ * NK1-derived next-of-kin entry (HELPERS-06). Lean subset: callers can
2787
2987
  * reach for `msg.segments("NK1")` when they need the full NK1 surface.
2788
2988
  *
2789
2989
  * @example
@@ -2857,21 +3057,21 @@ interface Diagnosis {
2857
3057
  readonly type?: string;
2858
3058
  }
2859
3059
  /**
2860
- * Which pharmacy/treatment segment a `Medication` was extracted from — the
3060
+ * Which pharmacy/treatment segment a `Medication` was extracted from: the
2861
3061
  * clinical "phase" of the medication. Each value maps 1:1 to one RX* parent
2862
3062
  * segment (Phase D, Ch. 4A):
2863
- * - `"order"` — **RXO** (Pharmacy/Treatment Order): the originally *requested*
3063
+ * - `"order"`: **RXO** (Pharmacy/Treatment Order): the originally *requested*
2864
3064
  * give code/amount/dosage-form, before pharmacy encoding.
2865
- * - `"encoded"` — **RXE** (Encoded Order): the pharmacy-encoded give
2866
- * code/amount, plus the give *strength* (RXE-25/26) — the only context that
3065
+ * - `"encoded"`: **RXE** (Encoded Order): the pharmacy-encoded give
3066
+ * code/amount, plus the give *strength* (RXE-25/26): the only context that
2867
3067
  * carries a separate strength.
2868
- * - `"dispense"` — **RXD** (Dispense): what was actually dispensed.
2869
- * - `"administration"` — **RXA** (Administration): what was actually given to
3068
+ * - `"dispense"`: **RXD** (Dispense): what was actually dispensed.
3069
+ * - `"administration"`: **RXA** (Administration): what was actually given to
2870
3070
  * the patient.
2871
3071
  *
2872
3072
  * The context is preserved verbatim and never collapsed: an RDE order that
2873
3073
  * carries both an RXO request and an RXE encoded line surfaces as TWO
2874
- * `Medication` entries with distinct contexts — the helper never reconciles
3074
+ * `Medication` entries with distinct contexts: the helper never reconciles
2875
3075
  * one against the other.
2876
3076
  */
2877
3077
  type MedicationContext = "order" | "encoded" | "dispense" | "administration";
@@ -2880,10 +3080,10 @@ type MedicationContext = "order" | "encoded" | "dispense" | "administration";
2880
3080
  * Carries the HL7 min/max amount pair and its units.
2881
3081
  *
2882
3082
  * - For an **order** (RXO-2/3) or **encoded** order (RXE-3/4) the amount is a
2883
- * genuine min..max range — both keys may be present.
3083
+ * genuine min..max range: both keys may be present.
2884
3084
  * - For a **dispense** (RXD-4) or **administration** (RXA-6) there is a SINGLE
2885
3085
  * amount; it is surfaced as `minimum` with `maximum` OMITTED. This is a
2886
- * single value, not a range — do not read the absent `maximum` as "no upper
3086
+ * single value, not a range: do not read the absent `maximum` as "no upper
2887
3087
  * bound on a range".
2888
3088
  *
2889
3089
  * `minimum`/`maximum` are strict-`Number()` parsed (`undefined`, never `NaN`).
@@ -2906,7 +3106,7 @@ interface MedicationAmount {
2906
3106
  }
2907
3107
  /**
2908
3108
  * The give *strength* of an **encoded** `Medication` (RXE-25 value + RXE-26
2909
- * units) — Phase D. Strength is the concentration of active ingredient (e.g.
3109
+ * units): Phase D. Strength is the concentration of active ingredient (e.g.
2910
3110
  * "250 mg"), distinct from the give *amount* (how much is administered, e.g.
2911
3111
  * "2 tablets"). Only the `"encoded"` (RXE) context carries strength.
2912
3112
  *
@@ -2914,7 +3114,7 @@ interface MedicationAmount {
2914
3114
  * RXE-25/26 fields declare it, and is NEVER reconciled against any strength
2915
3115
  * *implied* by the give code (e.g. an NDC that encodes "250 mg"). A consumer
2916
3116
  * that sees both an explicit strength here and a coded drug in `giveCode` must
2917
- * treat a disagreement as a real signal — the library does not silently pick a
3117
+ * treat a disagreement as a real signal: the library does not silently pick a
2918
3118
  * winner. `value` is strict-`Number()` parsed (`undefined`, never `NaN`).
2919
3119
  *
2920
3120
  * @example
@@ -2932,7 +3132,7 @@ interface MedicationStrength {
2932
3132
  /**
2933
3133
  * One RXR (Pharmacy/Treatment Route) grouped under its parent RX* segment
2934
3134
  * (Phase D). `route` is HL7 Table 0162 (CWE); `site` is Table 0163 (CWE).
2935
- * Provenance travels on the CWE (`route.nameOfCodingSystem`) — a "PO" route is
3135
+ * Provenance travels on the CWE (`route.nameOfCodingSystem`): a "PO" route is
2936
3136
  * only safe to act on when you know the system it was coded against.
2937
3137
  *
2938
3138
  * @example
@@ -2949,7 +3149,7 @@ interface MedicationRoute {
2949
3149
  }
2950
3150
  /**
2951
3151
  * One RXC (Pharmacy/Treatment Component Order) grouped under its parent RX*
2952
- * segment (Phase D) — a component of a compound/IV. Surfaced STRUCTURALLY
3152
+ * segment (Phase D): a component of a compound/IV. Surfaced STRUCTURALLY
2953
3153
  * (the component list as authored), NOT pharmacologically resolved.
2954
3154
  *
2955
3155
  * @example
@@ -2959,7 +3159,7 @@ interface MedicationRoute {
2959
3159
  * ```
2960
3160
  */
2961
3161
  interface MedicationComponent {
2962
- /** RXC-1 component type (e.g. "B"=base, "A"=additive — HL7 Table 0166). */
3162
+ /** RXC-1 component type (e.g. "B"=base, "A"=additive: HL7 Table 0166). */
2963
3163
  readonly type?: string;
2964
3164
  /** RXC-2 component code. */
2965
3165
  readonly code?: CWE;
@@ -2977,15 +3177,15 @@ interface MedicationComponent {
2977
3177
  * **Safety contract.** A wrong drug, strength, or route can harm a real
2978
3178
  * patient, so this view is deliberately conservative:
2979
3179
  * - `giveCode` carries its own coding-system provenance via the CWE
2980
- * (`giveCode.nameOfCodingSystem` — e.g. `RXN` RxNorm, `NDC`). The helper
3180
+ * (`giveCode.nameOfCodingSystem`: e.g. `RXN` RxNorm, `NDC`). The helper
2981
3181
  * surfaces the *claim*; it never validates or looks the code up.
2982
3182
  * - `amount` (how much) and `strength` (concentration) are SEPARATE fields and
2983
- * are never reconciled — including against any strength a coded drug implies
3183
+ * are never reconciled: including against any strength a coded drug implies
2984
3184
  * (Phase D §4). A disagreement is preserved for the consumer to see.
2985
- * - Malformed RX* segments never throw — absent fields are omitted keys.
3185
+ * - Malformed RX* segments never throw: absent fields are omitted keys.
2986
3186
  *
2987
3187
  * `routes` and `components` are ALWAYS present (possibly empty). Phase M adds
2988
- * `timings` — ALWAYS present, empty when no TQ1 / legacy embedded TQ (RXE-1)
3188
+ * `timings`: ALWAYS present, empty when no TQ1 / legacy embedded TQ (RXE-1)
2989
3189
  * accompanies the medication; the repeat pattern is surfaced **verbatim, never
2990
3190
  * normalized to a schedule**. Deferred (not v1): sig/frequency *interpretation*,
2991
3191
  * dose-range or interaction checking, pharmacologic resolution of compounds.
@@ -3011,7 +3211,7 @@ interface Medication {
3011
3211
  readonly giveCode?: CWE;
3012
3212
  /** Give/dispense/administered amount (+ units). See {@link MedicationAmount}. */
3013
3213
  readonly amount?: MedicationAmount;
3014
- /** RXE-25/26 give strength — ENCODED context only; never reconciled with `giveCode`. */
3214
+ /** RXE-25/26 give strength: ENCODED context only; never reconciled with `giveCode`. */
3015
3215
  readonly strength?: MedicationStrength;
3016
3216
  /** RXO-5 requested dosage form (order context). */
3017
3217
  readonly dosageForm?: CWE;
@@ -3021,7 +3221,7 @@ interface Medication {
3021
3221
  readonly components: readonly MedicationComponent[];
3022
3222
  /**
3023
3223
  * TQ1 / legacy embedded-TQ (RXE-1) timing(s) grouped under this medication
3024
- * (Phase M). Always present — empty when the medication carries no timing.
3224
+ * (Phase M). Always present: empty when the medication carries no timing.
3025
3225
  * See {@link OrderTiming}.
3026
3226
  */
3027
3227
  readonly timings: readonly OrderTiming[];
@@ -3067,11 +3267,11 @@ interface Insurance {
3067
3267
  }
3068
3268
  /**
3069
3269
  * Whether an `Immunization` records a dose that was **administered** by the
3070
- * reporting system or is **historical** information sourced from elsewhere —
3270
+ * reporting system or is **historical** information sourced from elsewhere,
3071
3271
  * derived conservatively from RXA-9.1 against HL7 Table NIP001 (Immunization
3072
3272
  * Information Source, CDC v2.5.1 Immunization Messaging IG):
3073
- * - `"administered"` — RXA-9.1 is exactly `"00"` (New immunization record).
3074
- * - `"historical"` — RXA-9.1 is `"01".."08"` (any "Historical information …"
3273
+ * - `"administered"`: RXA-9.1 is exactly `"00"` (New immunization record).
3274
+ * - `"historical"`: RXA-9.1 is `"01".."08"` (any "Historical information …"
3075
3275
  * source).
3076
3276
  *
3077
3277
  * **Fail-safe:** this is OMITTED (never guessed) when RXA-9 is absent or carries
@@ -3079,7 +3279,7 @@ interface Insurance {
3079
3279
  * always preserved verbatim on `Immunization.informationSource`, so a consumer
3080
3280
  * can inspect the original code even when `recordOrigin` is undefined. The
3081
3281
  * distinction matters because an IIS de-duplicates a *historical* report
3082
- * differently from a dose it believes was *administered* — guessing corrupts
3282
+ * differently from a dose it believes was *administered*: guessing corrupts
3083
3283
  * the registry.
3084
3284
  */
3085
3285
  type ImmunizationRecordOrigin = "administered" | "historical";
@@ -3094,18 +3294,18 @@ type ImmunizationRecordOrigin = "administered" | "historical";
3094
3294
  * a patient or corrupt an IIS (Immunization Information System) registry, so
3095
3295
  * this view is deliberately conservative:
3096
3296
  * - `vaccineCode` carries its own coding-system provenance via the CWE
3097
- * (`vaccineCode.nameOfCodingSystem` — `CVX` HL7 Table 0292; live IIS feeds
3297
+ * (`vaccineCode.nameOfCodingSystem`: `CVX` HL7 Table 0292; live IIS feeds
3098
3298
  * frequently *dual-code* RXA-5 with an alternate CVX/NDC in CWE.4-6, surfaced
3099
3299
  * as `vaccineCode.alternateIdentifier`/`alternateText`/`nameOfAlternateCodingSystem`).
3100
3300
  * The helper reports the *claim*; it never validates or looks the code up.
3101
3301
  * - `actionCode` (RXA-21, `A`/`D`/`U`) is surfaced **verbatim** and never
3102
- * defaulted — mis-keying it corrupts a registry's add/delete/update dedup.
3302
+ * defaulted: mis-keying it corrupts a registry's add/delete/update dedup.
3103
3303
  * - `doseAmount` is strict-`Number()` parsed; the IIS "unknown dose" sentinel
3104
3304
  * `999` is surfaced **as the number `999`**, never specially coerced.
3105
3305
  * - `recordOrigin` (administered vs historical) is derived only from the
3106
- * well-known NIP001 RXA-9.1 codes and OMITTED otherwise — see
3306
+ * well-known NIP001 RXA-9.1 codes and OMITTED otherwise: see
3107
3307
  * {@link ImmunizationRecordOrigin}.
3108
- * - Malformed RXA segments never throw — absent fields are omitted keys.
3308
+ * - Malformed RXA segments never throw: absent fields are omitted keys.
3109
3309
  *
3110
3310
  * `routes` and `observations` are ALWAYS present (possibly empty). Deferred (not
3111
3311
  * v1): IIS-specific state profile constraints; CVX/MVX validity checks; the 2nd+
@@ -3140,9 +3340,9 @@ interface Immunization {
3140
3340
  readonly doseUnits?: CWE;
3141
3341
  /**
3142
3342
  * `true` iff RXA-7's coding system (CWE.3) is exactly `UCUM` (HL7 Table 0396)
3143
- * — i.e. the dose unit is declared UCUM and safe to interpret as computable.
3343
+ *: i.e. the dose unit is declared UCUM and safe to interpret as computable.
3144
3344
  * `false` means a unit IS present but is NOT declared UCUM (surfaced as-is,
3145
- * never coerced). OMITTED when RXA-7 is absent. A *claim* check only — UCUM
3345
+ * never coerced). OMITTED when RXA-7 is absent. A *claim* check only: UCUM
3146
3346
  * grammar is not validated here.
3147
3347
  */
3148
3348
  readonly doseUnitsAreUcum?: boolean;
@@ -3162,7 +3362,7 @@ interface Immunization {
3162
3362
  readonly refusalReason?: CWE;
3163
3363
  /** RXA-20 completion status (`CP`=complete, `RE`=refused, `NA`=not administered, `PA`=partially administered). */
3164
3364
  readonly completionStatus?: string;
3165
- /** RXA-21 action code (`A`=add, `D`=delete, `U`=update) — preserved verbatim, NEVER defaulted. */
3365
+ /** RXA-21 action code (`A`=add, `D`=delete, `U`=update): preserved verbatim, NEVER defaulted. */
3166
3366
  readonly actionCode?: string;
3167
3367
  /** RXR children grouped under this RXA (Table 0162 route / Table 0163 site). Always present (possibly empty). */
3168
3368
  readonly routes: readonly MedicationRoute[];
@@ -3170,7 +3370,7 @@ interface Immunization {
3170
3370
  readonly observations: readonly Observation[];
3171
3371
  }
3172
3372
  /**
3173
- * One appointment resource grouped under a `SCH` (Phase Q) — an AIS (service),
3373
+ * One appointment resource grouped under a `SCH` (Phase Q): an AIS (service),
3174
3374
  * AIG (general resource), AIL (location), or AIP (personnel / provider) segment.
3175
3375
  * The resource identifier lives at position 3 of every AI* segment; for the
3176
3376
  * personnel resource (AIP) it is additionally surfaced as a typed `person`
@@ -3186,7 +3386,7 @@ interface AppointmentResource {
3186
3386
  /** Which AI* segment sourced this resource: AIS→service, AIG→general, AIL→location, AIP→personnel. */
3187
3387
  readonly kind: "service" | "general" | "location" | "personnel";
3188
3388
  /**
3189
- * The AI*-3 resource identifier surfaced as a coded element — `code.identifier`
3389
+ * The AI*-3 resource identifier surfaced as a coded element: `code.identifier`
3190
3390
  * is the resource id (first component, verbatim). AIS-3 / AIG-3 are coded
3191
3391
  * elements, so `code.text` / `code.nameOfCodingSystem` are meaningful there;
3192
3392
  * AIL-3 is a **PL** (location) rather than a coded element, so only
@@ -3194,11 +3394,11 @@ interface AppointmentResource {
3194
3394
  * fields are positional provenance, not a coding system. Provenance-only.
3195
3395
  */
3196
3396
  readonly code?: CWE;
3197
- /** AIP-3 personnel resource as a typed `XCN` (personnel resources only) — the appointment provider. */
3397
+ /** AIP-3 personnel resource as a typed `XCN` (personnel resources only): the appointment provider. */
3198
3398
  readonly person?: XCN;
3199
3399
  }
3200
3400
  /**
3201
- * SCH-derived appointment entry (Phase Q — SIU scheduling breadth). Surfaces the
3401
+ * SCH-derived appointment entry (Phase Q: SIU scheduling breadth). Surfaces the
3202
3402
  * appointment identifiers, filler status (SCH-25, Table 0278), SCH-11 start/end
3203
3403
  * timing, and the AI* resource groups. NOT a scheduling-workflow state machine.
3204
3404
  *
@@ -3217,19 +3417,19 @@ interface Appointment {
3217
3417
  readonly placerAppointmentId?: string;
3218
3418
  /** SCH-2 filler appointment ID (EI first component, verbatim). */
3219
3419
  readonly fillerAppointmentId?: string;
3220
- /** SCH-25 filler status code (HL7 Table 0278) — the appointment status, verbatim/provenance-only. */
3420
+ /** SCH-25 filler status code (HL7 Table 0278): the appointment status, verbatim/provenance-only. */
3221
3421
  readonly fillerStatusCode?: CWE;
3222
- /** Appointment start date/time — SCH-11 TQ.4 (fidelity `TS`, Phase N). */
3422
+ /** Appointment start date/time: SCH-11 TQ.4 (fidelity `TS`, Phase N). */
3223
3423
  readonly startDateTime?: TS;
3224
- /** Appointment end date/time — SCH-11 TQ.5 (fidelity `TS`, Phase N). */
3424
+ /** Appointment end date/time: SCH-11 TQ.5 (fidelity `TS`, Phase N). */
3225
3425
  readonly endDateTime?: TS;
3226
3426
  /** AIS/AIG/AIL/AIP resources grouped under this SCH. Always present (possibly empty). */
3227
3427
  readonly resources: readonly AppointmentResource[];
3228
3428
  }
3229
3429
  /**
3230
- * TXA-derived clinical-document entry (Phase Q — MDM document breadth). The
3430
+ * TXA-derived clinical-document entry (Phase Q: MDM document breadth). The
3231
3431
  * load-bearing safety property: **completion status (TXA-17) and availability
3232
- * status (TXA-19) are DISTINCT fields and are never conflated** — a document can
3432
+ * status (TXA-19) are DISTINCT fields and are never conflated**: a document can
3233
3433
  * be *available* before it is *authenticated*, and reading a preliminary
3234
3434
  * document as final is the clinical harm. Both are verbatim / provenance-only.
3235
3435
  *
@@ -3238,8 +3438,8 @@ interface Appointment {
3238
3438
  * import type { ClinicalDocument } from "@cosyte/hl7";
3239
3439
  * const doc: ClinicalDocument = {
3240
3440
  * documentType: "DS",
3241
- * completionStatus: "IP", // in progress — NOT yet authenticated
3242
- * availabilityStatus: "AV", // available — a different axis
3441
+ * completionStatus: "IP", // in progress: NOT yet authenticated
3442
+ * availabilityStatus: "AV", // available: a different axis
3243
3443
  * observations: [],
3244
3444
  * };
3245
3445
  * ```
@@ -3248,14 +3448,14 @@ interface ClinicalDocument {
3248
3448
  /** TXA-2 document type (HL7 Table 0270), verbatim. */
3249
3449
  readonly documentType?: string;
3250
3450
  /**
3251
- * TXA-17 document **completion** status (HL7 Table 0271 — e.g. `DO` documented,
3451
+ * TXA-17 document **completion** status (HL7 Table 0271: e.g. `DO` documented,
3252
3452
  * `IP` in progress, `AU` authenticated, `LA` legally authenticated, `IN`
3253
3453
  * incomplete). Surfaced DISTINCT from {@link availabilityStatus}; verbatim,
3254
3454
  * never validated, never merged.
3255
3455
  */
3256
3456
  readonly completionStatus?: string;
3257
3457
  /**
3258
- * TXA-19 document **availability** status (HL7 Table 0273 — `AV` available,
3458
+ * TXA-19 document **availability** status (HL7 Table 0273: `AV` available,
3259
3459
  * `CA` cancelled, `OB` obsolete, `UN` unavailable). Surfaced DISTINCT from
3260
3460
  * {@link completionStatus}; verbatim, never validated, never merged.
3261
3461
  */
@@ -3264,14 +3464,14 @@ interface ClinicalDocument {
3264
3464
  readonly activityDateTime?: TS;
3265
3465
  /** TXA-12 unique document number (EI first component, verbatim). */
3266
3466
  readonly uniqueDocumentNumber?: string;
3267
- /** TXA-13 parent document number (EI first component) — addendum / replacement link. */
3467
+ /** TXA-13 parent document number (EI first component): addendum / replacement link. */
3268
3468
  readonly parentDocumentNumber?: string;
3269
3469
  /** OBX narrative body grouped under this TXA. Always present (possibly empty). */
3270
3470
  readonly observations: readonly Observation[];
3271
3471
  }
3272
3472
  /**
3273
- * FT1-derived charge entry (Phase Q — DFT financial breadth). Billing-critical
3274
- * fields surfaced with **no billing logic and no money-as-float** — the
3473
+ * FT1-derived charge entry (Phase Q: DFT financial breadth). Billing-critical
3474
+ * fields surfaced with **no billing logic and no money-as-float**: the
3275
3475
  * extended/unit amounts are the verbatim CP wire text, never parsed to a number.
3276
3476
  *
3277
3477
  * @example
@@ -3288,29 +3488,29 @@ interface ClinicalDocument {
3288
3488
  interface Charge {
3289
3489
  /** FT1-4 transaction date (fidelity `TS`, Phase N). */
3290
3490
  readonly transactionDate?: TS;
3291
- /** FT1-6 transaction type (HL7 Table 0017 — `CG` charge, `CD` credit, `PY` payment, `AJ` adjustment). Verbatim. */
3491
+ /** FT1-6 transaction type (HL7 Table 0017: `CG` charge, `CD` credit, `PY` payment, `AJ` adjustment). Verbatim. */
3292
3492
  readonly transactionType?: string;
3293
- /** FT1-7 transaction code — the institution charge/procedure code (CWE, provenance-only, never validated). */
3493
+ /** FT1-7 transaction code: the institution charge/procedure code (CWE, provenance-only, never validated). */
3294
3494
  readonly transactionCode?: CWE;
3295
3495
  /** FT1-10 transaction quantity (NM; strict-parsed, never `NaN`). */
3296
3496
  readonly quantity?: number;
3297
- /** FT1-11 transaction amount, extended (CP) — canonical wire text (e.g. `150.00^USD`, byte-exact for a plain amount); never parsed to a number. */
3497
+ /** FT1-11 transaction amount, extended (CP): canonical wire text (e.g. `150.00^USD`, byte-exact for a plain amount); never parsed to a number. */
3298
3498
  readonly amountExtended?: string;
3299
- /** FT1-12 transaction amount, unit (CP) — canonical wire text; never parsed to a number. */
3499
+ /** FT1-12 transaction amount, unit (CP): canonical wire text; never parsed to a number. */
3300
3500
  readonly amountUnit?: string;
3301
- /** FT1-19 diagnosis code(s) linked to this charge (CE, repeating) — billing diagnosis linkage. Always present (possibly empty). */
3501
+ /** FT1-19 diagnosis code(s) linked to this charge (CE, repeating): billing diagnosis linkage. Always present (possibly empty). */
3302
3502
  readonly diagnoses: readonly CWE[];
3303
3503
  }
3304
3504
 
3305
3505
  /**
3306
- * Message-type & structure awareness (roadmap Phase G) — a conservative
3506
+ * Message-type & structure awareness (roadmap Phase G): a conservative
3307
3507
  * **misroute / truncation safety net**, NOT an abstract-message-syntax
3308
3508
  * validator.
3309
3509
  *
3310
3510
  * It answers one question per message: **"for this trigger event, are the
3311
3511
  * core segment groups the spec marks Required actually present?"** When an
3312
3512
  * expected group is entirely absent (e.g. an `ORU^R01` carrying no `OBR`/`OBX`
3313
- * result group — the classic signature of a truncated or misrouted feed), the
3513
+ * result group: the classic signature of a truncated or misrouted feed), the
3314
3514
  * parser emits a single additive Tier-2 `MISSING_EXPECTED_GROUP` warning. It
3315
3515
  * never throws, never refuses, never rewrites the message.
3316
3516
  *
@@ -3318,24 +3518,24 @@ interface Charge {
3318
3518
  * false-positives):
3319
3519
  *
3320
3520
  * - **Per trigger event, never per family.** The claim that an ADT family
3321
- * shares one shape is false — events diverge by version and trigger. Every
3521
+ * shares one shape is false: events diverge by version and trigger. Every
3322
3522
  * definition keys on the (messageCode, triggerEvent) pair.
3323
3523
  * - **Required (R) anchors only.** A group is modelled only when its anchor
3324
3524
  * segment is genuinely Required by the v2.5.1 abstract syntax for that
3325
3525
  * event. Optional groups (e.g. PID in ORU, RXA in VXU, OBR in OML) are
3326
3526
  * deliberately excluded so a conformant-but-sparse message never warns.
3327
3527
  * - **Presence is liberal.** A group counts as present if ANY of its anchor
3328
- * segments appears — the conservative direction (it suppresses a warning
3528
+ * segments appears: the conservative direction (it suppresses a warning
3329
3529
  * rather than inventing one).
3330
3530
  * - **Unrecognized = silent.** A message whose type has no definition here
3331
3531
  * produces an unrecognized structure summary and zero structural warnings.
3332
3532
  *
3333
- * Spec traceability: HL7 v2.5.1 — Ch. 3 (ADT), Ch. 4 (orders), Ch. 6
3334
- * (financial — DFT), Ch. 7 (observation — ORU), Ch. 9 (MDM), Ch. 10
3335
- * (scheduling — SIU), Ch. 2 (ACK), CDC IG (VXU). Per-entry sourcing lives in
3533
+ * Spec traceability: HL7 v2.5.1: Ch. 3 (ADT), Ch. 4 (orders), Ch. 6
3534
+ * (financial: DFT), Ch. 7 (observation: ORU), Ch. 9 (MDM), Ch. 10
3535
+ * (scheduling: SIU), Ch. 2 (ACK), CDC IG (VXU). Per-entry sourcing lives in
3336
3536
  * `docs-content/spec-notes-structure.md`.
3337
3537
  *
3338
- * Zero runtime deps — pure data + pure functions.
3538
+ * Zero runtime deps: pure data + pure functions.
3339
3539
  */
3340
3540
  /**
3341
3541
  * One expected segment group for a recognized trigger event. The group is
@@ -3397,7 +3597,7 @@ interface StructureGroup {
3397
3597
  readonly present: boolean;
3398
3598
  }
3399
3599
  /**
3400
- * The structure summary for a parsed message — the data behind
3600
+ * The structure summary for a parsed message: the data behind
3401
3601
  * `Hl7Message.structure`. For an unrecognized type, `recognized` is `false`,
3402
3602
  * `expectedGroups` is empty, and `missingGroups` is empty (the safety net is
3403
3603
  * deliberately silent on types it does not model).
@@ -3418,7 +3618,7 @@ interface MessageStructure {
3418
3618
  * Analyze a parsed message's structure against the conservative expected-group
3419
3619
  * registry. Pure: it takes the message code, trigger event, and the set of
3420
3620
  * segment names actually present, and returns a `MessageStructure` summary. It
3421
- * decides nothing about whether to warn — the caller (parser) emits one
3621
+ * decides nothing about whether to warn: the caller (parser) emits one
3422
3622
  * `MISSING_EXPECTED_GROUP` warning per name in `missingGroups`.
3423
3623
  *
3424
3624
  * @param messageCode - MSH-9.1 (e.g. `"ORU"`); empty string if absent.
@@ -3436,7 +3636,7 @@ interface MessageStructure {
3436
3636
  declare function analyzeMessageStructure(messageCode: string, triggerEvent: string, presentSegmentNames: ReadonlySet<string>): MessageStructure;
3437
3637
 
3438
3638
  /**
3439
- * `emitJson` + `SerializedMessage` — snapshot-stable JSON projection of an
3639
+ * `emitJson` + `SerializedMessage`: snapshot-stable JSON projection of an
3440
3640
  * `Hl7Message`. Mirrors `rawSegments` one-for-one; preserves `isNull`;
3441
3641
  * always includes `warnings: []`; omits `profile` when absent.
3442
3642
  *
@@ -3449,15 +3649,15 @@ declare function analyzeMessageStructure(messageCode: string, triggerEvent: stri
3449
3649
  * warnings + optional profile).
3450
3650
  * - D-18: `Hl7Message.toJSON` delegates here so `JSON.stringify(msg)` Just Works.
3451
3651
  * - D-19: warnings array is ALWAYS present (`warnings: []` when empty).
3452
- * - D-20: `profile` field appears only when `msg.profile` is truthy — then
3652
+ * - D-20: `profile` field appears only when `msg.profile` is truthy: then
3453
3653
  * contains only `name` + `lineage`.
3454
3654
  * - D-21: `SerializedMessage` is exported from `src/index.ts` (not nested
3455
3655
  * under HL7 namespace).
3456
3656
  *
3457
3657
  * Note on runtime freeze scope: `emitJson` returns an object that is
3458
- * boundary-frozen (top level only — `Object.isFrozen(msg.toJSON()) === true`).
3658
+ * boundary-frozen (top level only: `Object.isFrozen(msg.toJSON()) === true`).
3459
3659
  * Inner arrays are readonly at the TypeScript type level but MUTABLE at
3460
- * runtime — consumers should treat the returned structure as immutable
3660
+ * runtime: consumers should treat the returned structure as immutable
3461
3661
  * and not mutate nested arrays. Deep-freeze is explicitly rejected per
3462
3662
  * D-30 (emit is hot-path; runtime deep-freeze would add cost with no
3463
3663
  * observable benefit given the type-level readonly contract).
@@ -3469,7 +3669,7 @@ declare function analyzeMessageStructure(messageCode: string, triggerEvent: stri
3469
3669
  *
3470
3670
  * Runtime immutability: the top-level object is `Object.freeze`d
3471
3671
  * (boundary-frozen). Inner arrays are readonly at the TypeScript type
3472
- * level but mutable at runtime — treat as immutable, do not mutate.
3672
+ * level but mutable at runtime: treat as immutable, do not mutate.
3473
3673
  *
3474
3674
  * @example
3475
3675
  * ```ts
@@ -3503,11 +3703,214 @@ interface SerializedMessage {
3503
3703
  }
3504
3704
 
3505
3705
  /**
3506
- * `Hl7Message` — the immutable parsed-message model produced by `parseHL7`.
3706
+ * Typed-composite **encoders** for the `@cosyte/hl7` emit path (roadmap Phase
3707
+ * T): the conservative-emit mirror of the `src/model/types/*` read parsers.
3708
+ *
3709
+ * Each encoder takes one typed composite (an {@link XPN} name, a {@link CX}
3710
+ * identifier, a {@link TS} timestamp, …) and produces a `RawField` whose
3711
+ * positional structure matches exactly what the corresponding `parseXxx`
3712
+ * reads back. The load-bearing guarantees:
3713
+ *
3714
+ * - **No delimiter injection.** Component values are stored **decoded** (the
3715
+ * same surface `parseXxx` returns), and the serializer (`emit-field.ts`)
3716
+ * runs every subcomponent through `reescape` (the HL7-R encode-safe codec)
3717
+ * on the way out. A `familyName` of `"Smith^Jr"` is therefore emitted as
3718
+ * `Smith\S\Jr` (one component) and re-parses to the exact string `"Smith^Jr"`,
3719
+ * never forging a component boundary. The caller never hand-assembles
3720
+ * `^`/`&`/`~`.
3721
+ * - **`emit ∘ parse` identity on the modelled fields.** Interior empty
3722
+ * components are preserved (so component positions stay aligned) and only
3723
+ * trailing empties are trimmed (matching the serializer's D-02 strip and the
3724
+ * parser's omit-on-absent), so `parseXxx(encodeXxx(v)) ` reproduces `v` on
3725
+ * every modelled field.
3726
+ * - **Never fabricate.** An omitted optional field encodes to an empty /
3727
+ * absent component: never a defaulted value. An all-empty composite encodes
3728
+ * to an absent field (`repetitions: []`).
3729
+ *
3730
+ * Zero runtime deps: pure functions over the raw positional tree.
3731
+ */
3732
+
3733
+ /**
3734
+ * The 11 typed composite kinds this module can encode. Mirrors the read-side
3735
+ * composite set (`XPN`, `XAD`, `CX`, `CWE`, `CE`, `XTN`, `PL`, `TS`, `NM`,
3736
+ * `HD`, `XCN`).
3737
+ */
3738
+ type CompositeKind = "XPN" | "XAD" | "CX" | "CWE" | "CE" | "XTN" | "PL" | "TS" | "NM" | "HD" | "XCN";
3739
+ /**
3740
+ * Maps each {@link CompositeKind} to the typed value {@link encodeComposite}
3741
+ * (and `setComposite`) accept for it. `TS` also accepts a pre-formatted HL7
3742
+ * timestamp string; `NM` also accepts a `number` or a raw numeric string,
3743
+ * both are emitted verbatim (the serializer never re-formats a claimed value).
3744
+ */
3745
+ interface CompositeValueByKind {
3746
+ readonly XPN: XPN;
3747
+ readonly XAD: XAD;
3748
+ readonly CX: CX;
3749
+ readonly CWE: CWE;
3750
+ readonly CE: CE;
3751
+ readonly XTN: XTN;
3752
+ readonly PL: PL;
3753
+ readonly TS: TS | string;
3754
+ readonly NM: NM | number | string;
3755
+ readonly HD: HD;
3756
+ readonly XCN: XCN;
3757
+ }
3758
+ /**
3759
+ * Encode an XPN (14 components) to a spec-clean field.
3760
+ *
3761
+ * @example
3762
+ * ```ts
3763
+ * import { encodeXpn } from "@cosyte/hl7";
3764
+ * encodeXpn({ familyName: "Doe", givenName: "Jane", prefix: "Dr" });
3765
+ * ```
3766
+ */
3767
+ declare function encodeXpn(v: XPN): RawField;
3768
+ /**
3769
+ * Encode an XAD (12 components) to a spec-clean field.
3770
+ *
3771
+ * @example
3772
+ * ```ts
3773
+ * import { encodeXad } from "@cosyte/hl7";
3774
+ * encodeXad({ street: "123 Main St", city: "Boston", stateOrProvince: "MA" });
3775
+ * ```
3776
+ */
3777
+ declare function encodeXad(v: XAD): RawField;
3778
+ /**
3779
+ * Encode a CX (identifier): component 4 is a nested HD (assigningAuthority).
3780
+ *
3781
+ * @example
3782
+ * ```ts
3783
+ * import { encodeCx } from "@cosyte/hl7";
3784
+ * encodeCx({ idNumber: "MRN001", assigningAuthority: { namespaceId: "HOSP" }, identifierTypeCode: "MR" });
3785
+ * ```
3786
+ */
3787
+ declare function encodeCx(v: CX): RawField;
3788
+ /**
3789
+ * Encode a CWE (coded element, 9 modelled + preserved `extraComponents`).
3790
+ *
3791
+ * @example
3792
+ * ```ts
3793
+ * import { encodeCwe } from "@cosyte/hl7";
3794
+ * encodeCwe({ identifier: "GLU", text: "Glucose", nameOfCodingSystem: "LN" });
3795
+ * ```
3796
+ */
3797
+ declare function encodeCwe(v: CWE): RawField;
3798
+ /**
3799
+ * Encode a CE (coded element, 6 modelled + preserved `extraComponents`).
3800
+ *
3801
+ * @example
3802
+ * ```ts
3803
+ * import { encodeCe } from "@cosyte/hl7";
3804
+ * encodeCe({ identifier: "GLU", text: "Glucose", nameOfCodingSystem: "L" });
3805
+ * ```
3806
+ */
3807
+ declare function encodeCe(v: CE): RawField;
3808
+ /**
3809
+ * Encode an XTN (telecom, 12 components) to a spec-clean field.
3810
+ *
3811
+ * @example
3812
+ * ```ts
3813
+ * import { encodeXtn } from "@cosyte/hl7";
3814
+ * encodeXtn({ telephoneNumber: "555-1234", telecommunicationUseCode: "PRN" });
3815
+ * ```
3816
+ */
3817
+ declare function encodeXtn(v: XTN): RawField;
3818
+ /**
3819
+ * Encode a PL (person location): component 4 is a nested HD (facility).
3820
+ *
3821
+ * @example
3822
+ * ```ts
3823
+ * import { encodePl } from "@cosyte/hl7";
3824
+ * encodePl({ pointOfCare: "ICU", room: "101", bed: "A" });
3825
+ * ```
3826
+ */
3827
+ declare function encodePl(v: PL): RawField;
3828
+ /**
3829
+ * Encode an HD (hierarchic designator, 3 components) to a spec-clean field.
3830
+ *
3831
+ * @example
3832
+ * ```ts
3833
+ * import { encodeHd } from "@cosyte/hl7";
3834
+ * encodeHd({ namespaceId: "EPIC", universalId: "1.2.840", universalIdType: "ISO" });
3835
+ * ```
3836
+ */
3837
+ declare function encodeHd(v: HD): RawField;
3838
+ /**
3839
+ * Encode a TS/DTM timestamp. Accepts either the typed {@link TS} (its `raw`
3840
+ * string is emitted verbatim: the serializer never re-derives a timestamp
3841
+ * from parts) or a pre-formatted HL7 timestamp string.
3842
+ *
3843
+ * @example
3844
+ * ```ts
3845
+ * import { encodeTs } from "@cosyte/hl7";
3846
+ * encodeTs("20260721101500");
3847
+ * ```
3848
+ */
3849
+ declare function encodeTs(v: TS | string): RawField;
3850
+ /**
3851
+ * Encode an NM numeric. Accepts the typed {@link NM} (its `raw` string emitted
3852
+ * verbatim, preserving the sender's precision/formatting), a `number`, or a raw
3853
+ * string. A `number` is stringified with `String(n)`; the value is never
3854
+ * reconciled or rounded.
3855
+ *
3856
+ * @example
3857
+ * ```ts
3858
+ * import { encodeNm } from "@cosyte/hl7";
3859
+ * encodeNm("120.50"); // precision preserved verbatim
3860
+ * ```
3861
+ */
3862
+ declare function encodeNm(v: NM | number | string): RawField;
3863
+ /**
3864
+ * Encode an XCN: component 9 is a nested HD (assigningAuthority).
3865
+ *
3866
+ * @example
3867
+ * ```ts
3868
+ * import { encodeXcn } from "@cosyte/hl7";
3869
+ * encodeXcn({ idNumber: "1234567890", familyName: "Welby", identifierTypeCode: "NPI" });
3870
+ * ```
3871
+ */
3872
+ declare function encodeXcn(v: XCN): RawField;
3873
+ /**
3874
+ * Encode any typed composite into a spec-clean `RawField` by its
3875
+ * {@link CompositeKind}. The single dispatcher `setComposite` and the typed
3876
+ * builders (`buildAdt`/`buildOru`) route through.
3877
+ *
3878
+ * Encoding takes **no** encoding-characters argument on purpose: the field it
3879
+ * produces carries the **decoded** component values, and the actual
3880
+ * delimiter-escaping happens later in the serializer against the message's own
3881
+ * encoding characters: so a composite is delimiter-independent to encode.
3882
+ *
3883
+ * @example
3884
+ * ```ts
3885
+ * import { encodeComposite } from "@cosyte/hl7";
3886
+ * // A hostile family name cannot break framing on emit:
3887
+ * const f = encodeComposite("XPN", { familyName: "Smith^Jr", givenName: "Ann" });
3888
+ * ```
3889
+ */
3890
+ declare function encodeComposite<K extends CompositeKind>(kind: K, value: CompositeValueByKind[K]): RawField;
3891
+ /**
3892
+ * Encode an array of typed composites into a single repeating `RawField`: one
3893
+ * HL7 repetition (`~`-joined on emit) per array element. Used for repeating
3894
+ * fields such as PID-3 (patient identifier list) and PID-11 (addresses). An
3895
+ * empty array yields an absent field.
3896
+ *
3897
+ * @example
3898
+ * ```ts
3899
+ * import { encodeCompositeReps } from "@cosyte/hl7";
3900
+ * const ids = encodeCompositeReps("CX", [
3901
+ * { idNumber: "MRN001", identifierTypeCode: "MR" },
3902
+ * { idNumber: "9990", identifierTypeCode: "SS" },
3903
+ * ]);
3904
+ * ```
3905
+ */
3906
+ declare function encodeCompositeReps<K extends CompositeKind>(kind: K, values: readonly CompositeValueByKind[K][]): RawField;
3907
+
3908
+ /**
3909
+ * `Hl7Message`: the immutable parsed-message model produced by `parseHL7`.
3507
3910
  * Phase 2 shipped the read-only shell; Phase 3 extends the same class with
3508
3911
  * the read-path traversal methods (`get`, `getAll`, `segments`,
3509
3912
  * `allSegments`) on top of lazy, referentially stable Segment/Field caches
3510
- * (D-11/D-12). The constructor surface is unchanged (Phase 2 D-05 lock) —
3913
+ * (D-11/D-12). The constructor surface is unchanged (Phase 2 D-05 lock),
3511
3914
  * `init.segments` is still the parser-side key, but the public raw-tree
3512
3915
  * field is now exposed as `rawSegments` to free up the name `segments` for
3513
3916
  * the typed `segments(type)` method.
@@ -3521,7 +3924,7 @@ interface SerializedMessage {
3521
3924
  *
3522
3925
  * @remarks
3523
3926
  * With `exactOptionalPropertyTypes: true`, callers cannot pass
3524
- * `{ profile: undefined }` — either omit the key or pass a real profile
3927
+ * `{ profile: undefined }`: either omit the key or pass a real profile
3525
3928
  * descriptor. This matches the `Hl7Message.profile` public field shape
3526
3929
  * (`... | undefined`).
3527
3930
  *
@@ -3547,7 +3950,7 @@ interface Hl7MessageInit {
3547
3950
  */
3548
3951
  readonly customSegments?: Readonly<Record<string, CustomSegmentDefinition>>;
3549
3952
  /**
3550
- * Merged `dateFormats` list — `options.dateFormats ++ profile.dateFormats`
3953
+ * Merged `dateFormats` list: `options.dateFormats ++ profile.dateFormats`
3551
3954
  * deduped first-occurrence per D-21. Consumed by `msg.meta.timestamp` and
3552
3955
  * any future helper that calls `parseDtmCascade` directly. Absent when
3553
3956
  * neither `options.dateFormats` nor `profile.dateFormats` was supplied.
@@ -3557,7 +3960,7 @@ interface Hl7MessageInit {
3557
3960
  /**
3558
3961
  * Parsed HL7 v2 message. Produced by `parseHL7`. Exposes the raw positional
3559
3962
  * tree (`rawSegments`), delimiter metadata, warnings, and a typed traversal
3560
- * surface — `get(path)` for dot-paths, `getAll(type)` / `segments(type)` /
3963
+ * surface: `get(path)` for dot-paths, `getAll(type)` / `segments(type)` /
3561
3964
  * `allSegments()` for wrapper-level iteration.
3562
3965
  *
3563
3966
  * @remarks
@@ -3582,7 +3985,7 @@ declare class Hl7Message {
3582
3985
  /**
3583
3986
  * Raw positional tree produced by the parser. 1-indexed per HL7 convention
3584
3987
  * (`fields[0]` is the segment-name / MSH separator placeholder slot). Use
3585
- * `segments(type)` / `allSegments()` for typed wrapper access — this field
3988
+ * `segments(type)` / `allSegments()` for typed wrapper access: this field
3586
3989
  * is exposed for advanced callers that need the raw tree directly (e.g.
3587
3990
  * future serialization phase 5).
3588
3991
  */
@@ -3595,7 +3998,7 @@ declare class Hl7Message {
3595
3998
  readonly lineage: readonly string[];
3596
3999
  } | undefined;
3597
4000
  /**
3598
- * Merged `dateFormats` list — `options.dateFormats ++ profile.dateFormats`
4001
+ * Merged `dateFormats` list: `options.dateFormats ++ profile.dateFormats`
3599
4002
  * deduped first-occurrence per D-21. Empty array when neither source
3600
4003
  * supplied any formats. Exposed publicly so helpers (`msg.meta.timestamp`)
3601
4004
  * and advanced callers can introspect the active cascade.
@@ -3625,14 +4028,14 @@ declare class Hl7Message {
3625
4028
  private _allSegments;
3626
4029
  /**
3627
4030
  * Lazily built `Meta` view (Phase 4 D-02 memoization). Dropped wholesale
3628
- * by `invalidateCaches`. `Meta` is always defined (D-03 — MSH absence
4031
+ * by `invalidateCaches`. `Meta` is always defined (D-03: MSH absence
3629
4032
  * throws `NO_MSH_SEGMENT` at parse time) so no null-sentinel is needed.
3630
4033
  * @internal
3631
4034
  */
3632
4035
  private _meta;
3633
4036
  /**
3634
4037
  * Lazily built `MessageStructure` view (Phase G). Dropped wholesale by
3635
- * `invalidateCaches`. Always defined — `analyzeMessageStructure` returns an
4038
+ * `invalidateCaches`. Always defined: `analyzeMessageStructure` returns an
3636
4039
  * `recognized: false` summary for unmodelled types rather than absence.
3637
4040
  * @internal
3638
4041
  */
@@ -3661,9 +4064,9 @@ declare class Hl7Message {
3661
4064
  constructor(init: Hl7MessageInit);
3662
4065
  /**
3663
4066
  * Resolve a dot-path (e.g. `PID.5.1`, `OBX[2].5`, `PID.3[0].1`) to its
3664
- * decoded leaf string (unescaped once at parse — never re-unescaped on read,
4067
+ * decoded leaf string (unescaped once at parse: never re-unescaped on read,
3665
4068
  * HL7-VALUE-REDECODE). Returns `undefined` when the path doesn't
3666
- * resolve — never throws on missing path (MODEL-05). Throws `TypeError`
4069
+ * resolve: never throws on missing path (MODEL-05). Throws `TypeError`
3667
4070
  * on malformed path syntax (e.g. `"pid.5"`, empty string).
3668
4071
  *
3669
4072
  * @example
@@ -3672,14 +4075,14 @@ declare class Hl7Message {
3672
4075
  * msg.get("PID.5.1"); // "Smith"
3673
4076
  * msg.get("OBX[2].5"); // third OBX's 5th field
3674
4077
  * msg.get("NOT.9.9"); // undefined
3675
- * msg.get("MSH.12"); // "2.5" — HL7 version string
4078
+ * msg.get("MSH.12"); // "2.5": HL7 version string
3676
4079
  * ```
3677
4080
  */
3678
4081
  get(path: string): string | undefined;
3679
4082
  /**
3680
4083
  * Return every `Segment` of `segmentType` in document order. Returns `[]`
3681
4084
  * (empty array, NEVER `undefined`) when no segment of that type exists
3682
- * (MODEL-02). Alias for `segments(segmentType)` — shares the same cache.
4085
+ * (MODEL-02). Alias for `segments(segmentType)`: shares the same cache.
3683
4086
  *
3684
4087
  * @example
3685
4088
  * ```ts
@@ -3718,7 +4121,7 @@ declare class Hl7Message {
3718
4121
  allSegments(): readonly Segment[];
3719
4122
  /**
3720
4123
  * MSH-derived message metadata (type, controlId, timestamp, version, etc.).
3721
- * D-01: plain object. D-02: memoized — `msg.meta === msg.meta` across
4124
+ * D-01: plain object. D-02: memoized: `msg.meta === msg.meta` across
3722
4125
  * reads until mutation invalidates. D-03: always defined (MSH absence
3723
4126
  * throws `NO_MSH_SEGMENT` at parse time).
3724
4127
  *
@@ -3732,10 +4135,10 @@ declare class Hl7Message {
3732
4135
  get meta(): Meta;
3733
4136
  /**
3734
4137
  * Structural-conformance summary for the common message types (roadmap
3735
- * Phase G) — a misroute/truncation safety net, NOT a conformance validator.
4138
+ * Phase G): a misroute/truncation safety net, NOT a conformance validator.
3736
4139
  * Reports, per the message's recognized (MSH-9.1, MSH-9.2) type, which
3737
4140
  * Required segment groups are present and which are entirely absent
3738
- * (`missingGroups` — the same set the parser flags as
4141
+ * (`missingGroups`: the same set the parser flags as
3739
4142
  * `MISSING_EXPECTED_GROUP` warnings). For an unmodelled type, `recognized`
3740
4143
  * is `false` and `missingGroups` is empty. D-02: memoized.
3741
4144
  *
@@ -3748,14 +4151,14 @@ declare class Hl7Message {
3748
4151
  get structure(): MessageStructure;
3749
4152
  /**
3750
4153
  * PID-derived patient view, or `undefined` when no PID segment exists
3751
- * (D-04). D-02: memoized. HELPERS-07: never throws — absent fields
4154
+ * (D-04). D-02: memoized. HELPERS-07: never throws: absent fields
3752
4155
  * surface as `undefined` on the returned `Patient` object.
3753
4156
  *
3754
4157
  * @example
3755
4158
  * ```ts
3756
4159
  * console.log(msg.patient?.mrn);
3757
4160
  * console.log(msg.patient?.fullName);
3758
- * console.log(msg.patient?.dateOfBirth?.raw); // fidelity TS — e.g. "19800115"
4161
+ * console.log(msg.patient?.dateOfBirth?.raw); // fidelity TS: e.g. "19800115"
3759
4162
  * ```
3760
4163
  */
3761
4164
  get patient(): Patient | undefined;
@@ -3773,7 +4176,7 @@ declare class Hl7Message {
3773
4176
  get visit(): Visit | undefined;
3774
4177
  /**
3775
4178
  * Every OBX segment as a typed Observation in document order. D-05:
3776
- * returns `[]` when no OBX present. D-06: NOT memoized — each call
4179
+ * returns `[]` when no OBX present. D-06: NOT memoized: each call
3777
4180
  * re-walks `rawSegments`. Value type is discriminated per D-13.
3778
4181
  *
3779
4182
  * @example
@@ -3786,7 +4189,7 @@ declare class Hl7Message {
3786
4189
  observations(): readonly Observation[];
3787
4190
  /**
3788
4191
  * Every OBR as an Order with its OBX children grouped positionally (D-12) and
3789
- * its TQ1 / legacy embedded-TQ (ORC-7) `timings` (Phase M — the repeat pattern
4192
+ * its TQ1 / legacy embedded-TQ (ORC-7) `timings` (Phase M: the repeat pattern
3790
4193
  * surfaced verbatim, never resolved to a schedule). D-05: returns `[]` when no
3791
4194
  * OBR present. D-06: not memoized.
3792
4195
  *
@@ -3794,17 +4197,17 @@ declare class Hl7Message {
3794
4197
  * ```ts
3795
4198
  * for (const order of msg.orders()) {
3796
4199
  * console.log(order.placerOrderNumber, order.observations.length);
3797
- * for (const t of order.timings) console.log(t.repeatPattern?.code); // e.g. "Q6H" — verbatim
4200
+ * for (const t of order.timings) console.log(t.repeatPattern?.code); // e.g. "Q6H": verbatim
3798
4201
  * }
3799
4202
  * ```
3800
4203
  */
3801
4204
  orders(): readonly Order[];
3802
4205
  /**
3803
- * Message-level NTE notes (Phase P) — every NTE segment with no recognized
4206
+ * Message-level NTE notes (Phase P): every NTE segment with no recognized
3804
4207
  * preceding parent (not immediately following a `PID`, `ORC`, `OBR`, or
3805
4208
  * `OBX`), surfaced verbatim in document order so nothing is dropped. Notes
3806
4209
  * that DO attach to a specific patient / order / result are exposed on those
3807
- * helper outputs (`msg.patient?.notes`, `order.notes`, `observation.notes`) —
4210
+ * helper outputs (`msg.patient?.notes`, `order.notes`, `observation.notes`),
3808
4211
  * not here. D-05: returns `[]` when there are none. D-06: NOT memoized.
3809
4212
  *
3810
4213
  * @example
@@ -3815,7 +4218,7 @@ declare class Hl7Message {
3815
4218
  notes(): readonly string[];
3816
4219
  /**
3817
4220
  * Every recognized ADT patient-identity event (merge / move / link /
3818
- * unlink / person add/update — roadmap Phase K), with the MRG-sourced
4221
+ * unlink / person add/update: roadmap Phase K), with the MRG-sourced
3819
4222
  * `prior` and PID/PV1-sourced `surviving` parties labelled by role and the
3820
4223
  * spec-constant `direction: "MRG_TO_PID"` on merge/move events. Returns
3821
4224
  * `[]` when the trigger event is not in the identity family. D-06: not
@@ -3840,7 +4243,7 @@ declare class Hl7Message {
3840
4243
  * and never reconciled (Phase D §4).
3841
4244
  *
3842
4245
  * Each medication also carries its TQ1 / legacy embedded-TQ (RXE-1) `timings`
3843
- * (Phase M — repeat pattern verbatim, never resolved to a schedule).
4246
+ * (Phase M: repeat pattern verbatim, never resolved to a schedule).
3844
4247
  *
3845
4248
  * @example
3846
4249
  * ```ts
@@ -3859,7 +4262,7 @@ declare class Hl7Message {
3859
4262
  * returns `[]` when no RXA present. D-06: not memoized. The vaccine code
3860
4263
  * carries its own provenance; the action code (RXA-21) is surfaced verbatim
3861
4264
  * and `recordOrigin` (administered vs historical) is derived only from the
3862
- * well-known NIP001 RXA-9.1 codes — never guessed.
4265
+ * well-known NIP001 RXA-9.1 codes: never guessed.
3863
4266
  *
3864
4267
  * @example
3865
4268
  * ```ts
@@ -3919,7 +4322,7 @@ declare class Hl7Message {
3919
4322
  * status (Table 0278), SCH-11 start/end timing, and the resource groups
3920
4323
  * (service / general / location / personnel). D-05: returns `[]` when no SCH
3921
4324
  * is present. D-06: not memoized. Never throws (HELPERS-07). Not a
3922
- * scheduling-workflow state machine — see the package known-limitations.
4325
+ * scheduling-workflow state machine: see the package known-limitations.
3923
4326
  *
3924
4327
  * @example
3925
4328
  * ```ts
@@ -3934,7 +4337,7 @@ declare class Hl7Message {
3934
4337
  * Every TXA of an MDM message as a typed `ClinicalDocument` (roadmap Phase Q),
3935
4338
  * with the OBX narrative body grouped positionally under that TXA. The
3936
4339
  * completion status (TXA-17) and availability status (TXA-19) are surfaced as
3937
- * **distinct** fields and never conflated — a document can be available before
4340
+ * **distinct** fields and never conflated: a document can be available before
3938
4341
  * it is authenticated, and reading a preliminary document as final is the
3939
4342
  * harm. D-05: returns `[]` when no TXA is present. D-06: not memoized. Never
3940
4343
  * throws (HELPERS-07).
@@ -3952,7 +4355,7 @@ declare class Hl7Message {
3952
4355
  * Every FT1 of a DFT message as a typed `Charge` (roadmap Phase Q), one per
3953
4356
  * FT1 in document order. Surfaces billing-critical fields (FT1-6 transaction
3954
4357
  * type, FT1-7 code, FT1-11/12 extended/unit amount, FT1-19 diagnosis linkage)
3955
- * with **no billing logic and no money-as-float** — amounts are the verbatim
4358
+ * with **no billing logic and no money-as-float**: amounts are the verbatim
3956
4359
  * CP wire text. D-05: returns `[]` when no FT1 is present. D-06: not memoized.
3957
4360
  * Never throws (HELPERS-07).
3958
4361
  *
@@ -3971,7 +4374,7 @@ declare class Hl7Message {
3971
4374
  * D-05; MSH-1 and MSH-2 are inlined verbatim from
3972
4375
  * `this.encodingCharacters` per D-06; every field string passes through
3973
4376
  * `reescape` per D-04. `RawField.isNull === true` is preserved as the
3974
- * HL7 literal `""` (D-02). Pure — never warns, never throws (D-07).
4377
+ * HL7 literal `""` (D-02). Pure: never warns, never throws (D-07).
3975
4378
  *
3976
4379
  * @example
3977
4380
  * ```ts
@@ -3987,7 +4390,7 @@ declare class Hl7Message {
3987
4390
  * Re-walks `rawSegments` on every call (D-30 no caching). Mirrors the
3988
4391
  * raw tree one-for-one, preserves `isNull`, always includes
3989
4392
  * `warnings: []`, and includes `profile: { name, lineage }` only when
3990
- * `this.profile` is truthy (D-19/D-20). Pure — never warns, never throws.
4393
+ * `this.profile` is truthy (D-19/D-20). Pure: never warns, never throws.
3991
4394
  *
3992
4395
  * @example
3993
4396
  * ```ts
@@ -4004,16 +4407,16 @@ declare class Hl7Message {
4004
4407
  * debugging (SER-04). Single opinionated format (D-22 no options):
4005
4408
  * header line with type / controlId / timestamp / segment count, then
4006
4409
  * one line per segment with labeled `[N]=value` fields (D-23). Composite
4007
- * values render as their raw HL7 string — depth stops at field level
4008
- * (D-24). Pure — never warns, never throws (D-26).
4410
+ * values render as their raw HL7 string: depth stops at field level
4411
+ * (D-24). Pure: never warns, never throws (D-26).
4009
4412
  *
4010
4413
  * **Field values render as their raw HL7 string representation.**
4011
- * Embedded delimiters in user data appear as escape sequences — e.g.
4414
+ * Embedded delimiters in user data appear as escape sequences: e.g.
4012
4415
  * a patient family name containing `|` renders as `Smith\F\Jones`
4013
4416
  * (NOT `Smith|Jones`). This preserves round-trip fidelity: copy-pasting
4014
4417
  * prettyPrint output into `parseHL7` yields a structurally equivalent
4015
4418
  * message. For un-escaped human display, parse the composite first via
4016
- * typed accessors (e.g. `msg.patient?.familyName`) — those return
4419
+ * typed accessors (e.g. `msg.patient?.familyName`): those return
4017
4420
  * already-decoded strings.
4018
4421
  *
4019
4422
  * @example
@@ -4031,13 +4434,13 @@ declare class Hl7Message {
4031
4434
  * Set the string value at a dot-path. Mutates the underlying tree and
4032
4435
  * returns `this` for chaining (D-15). Auto-creates missing repetitions,
4033
4436
  * components, and subcomponents WITHIN an existing field, but does NOT
4034
- * auto-create segments — callers must `addSegment` first (throws
4437
+ * auto-create segments: callers must `addSegment` first (throws
4035
4438
  * `TypeError` with an actionable message otherwise).
4036
4439
  *
4037
4440
  * The value is accepted verbatim: unescaped delimiter characters are NOT
4038
4441
  * rejected on input (D-18). Re-escaping on serialize is Phase 5's concern.
4039
4442
  *
4040
- * MSH-1 / MSH-2 follow the user-facing HL7 convention — `setField("MSH.3", ...)`
4443
+ * MSH-1 / MSH-2 follow the user-facing HL7 convention: `setField("MSH.3", ...)`
4041
4444
  * targets MSH-3 (sending application), matching `msg.get("MSH.3")`.
4042
4445
  *
4043
4446
  * Segment/Field wrapper caches are invalidated wholesale on success (D-17).
@@ -4051,9 +4454,41 @@ declare class Hl7Message {
4051
4454
  * ```
4052
4455
  */
4053
4456
  setField(path: string, value: string): this;
4457
+ /**
4458
+ * Set a **typed composite** at a field (or field-repetition) dot-path,
4459
+ * roadmap Phase T, the conservative-emit mirror of the typed read accessors
4460
+ * (`asXpn`/`asCx`/…). The caller passes a structured value (an XPN name, a CX
4461
+ * identifier, a TS timestamp, …) by its {@link CompositeKind}, and the setter
4462
+ * encodes it into a spec-clean field using the HL7-R encode-safe path: any
4463
+ * delimiter embedded in a component value is **escaped, never injected**, so
4464
+ * a `familyName` of `"Smith^Jr"` re-parses to exactly that string rather than
4465
+ * forging a component boundary. No hand-assembly of `^`/`&`/`~`.
4466
+ *
4467
+ * The path must resolve to a **field** (`"PID.5"`) or a specific
4468
+ * **repetition** of a field (`"PID.11[1]"`). A component/subcomponent-level
4469
+ * path (`"PID.5.1"`) is rejected with `TypeError`: a composite occupies a
4470
+ * whole field, not a single component. Like {@link setField}, the target
4471
+ * segment must already exist (`addSegment` first); the repetition defaults to
4472
+ * index 0 and other repetitions of the field are preserved.
4473
+ *
4474
+ * Never fabricates: an omitted optional composite field encodes to an
4475
+ * empty/absent component, never a defaulted value; an all-empty composite
4476
+ * clears the field. Segment/helper caches are invalidated on success; the
4477
+ * frozen `warnings` array is untouched.
4478
+ *
4479
+ * @example
4480
+ * ```ts
4481
+ * const msg = buildMessage({ type: "ADT^A01" }).addSegment("PID", [""]);
4482
+ * msg.setComposite("PID.5", "XPN", { familyName: "Smith", givenName: "Ann" });
4483
+ * msg.setComposite("PID.3", "CX", { idNumber: "MRN001", identifierTypeCode: "MR" });
4484
+ * msg.setComposite("PID.7", "TS", "19880705");
4485
+ * msg.get("PID.5.1"); // "Smith"
4486
+ * ```
4487
+ */
4488
+ setComposite<K extends CompositeKind>(path: string, kind: K, value: CompositeValueByKind[K]): this;
4054
4489
  /**
4055
4490
  * Append a new segment to the end of the message. `name` must match
4056
- * `/^(?:[A-Z]{3}|Z[A-Z0-9]{2})$/u` — throws `TypeError` otherwise (D-19).
4491
+ * `/^(?:[A-Z]{3}|Z[A-Z0-9]{2})$/u`: throws `TypeError` otherwise (D-19).
4057
4492
  *
4058
4493
  * `fields` is interpreted in HL7 1-indexed terms: `addSegment("NTE", [a, b, c])`
4059
4494
  * produces a segment whose `NTE-1 = a`, `NTE-2 = b`, `NTE-3 = c`. The
@@ -4076,14 +4511,14 @@ declare class Hl7Message {
4076
4511
  /**
4077
4512
  * Remove segments by type + occurrence or by type + all. Call shapes:
4078
4513
  *
4079
- * - `removeSegment("NTE")` — remove the FIRST NTE (occurrence 0).
4080
- * - `removeSegment("OBX", 1)` — remove the SECOND OBX (0-indexed per D-01).
4081
- * - `removeSegment("OBX", { all: true })` — remove ALL OBX segments.
4514
+ * - `removeSegment("NTE")`: remove the FIRST NTE (occurrence 0).
4515
+ * - `removeSegment("OBX", 1)`: remove the SECOND OBX (0-indexed per D-01).
4516
+ * - `removeSegment("OBX", { all: true })`: remove ALL OBX segments.
4082
4517
  *
4083
- * `MSH` is protected — `removeSegment("MSH")` throws `TypeError` (every
4518
+ * `MSH` is protected: `removeSegment("MSH")` throws `TypeError` (every
4084
4519
  * HL7 message must retain its MSH segment). Unknown segment types are a
4085
4520
  * no-op (idempotent; no throw). Segment name must match the D-19 shape
4086
- * regex — invalid shapes throw `TypeError` for symmetry with `addSegment`.
4521
+ * regex: invalid shapes throw `TypeError` for symmetry with `addSegment`.
4087
4522
  *
4088
4523
  * Invalidates caches on return; warnings untouched (D-16).
4089
4524
  *
@@ -4108,7 +4543,7 @@ declare class Hl7Message {
4108
4543
  }
4109
4544
 
4110
4545
  /**
4111
- * Public entry point for the `@cosyte/hl7` parser — composes every
4546
+ * Public entry point for the `@cosyte/hl7` parser: composes every
4112
4547
  * parser stage built across Plans 01–05 (normalize, strip MLLP, split
4113
4548
  * segments, read delimiters, tokenize) and routes every Tier-2 warning
4114
4549
  * through a single `emitWarning` chokepoint. The four Tier-3 fatal codes
@@ -4160,7 +4595,7 @@ declare function parseHL7(raw: string | Buffer, options: ParseOptions): Hl7Messa
4160
4595
  * thrown directly; consumers narrow via the `code` discriminant.
4161
4596
  *
4162
4597
  * `ProfileDefinitionError` is declared here so the error taxonomy is locked
4163
- * before Phase 6 wires profile validation — keeping file ownership clean
4598
+ * before Phase 6 wires profile validation: keeping file ownership clean
4164
4599
  * across phases.
4165
4600
  */
4166
4601
 
@@ -4218,7 +4653,7 @@ type FatalCode = (typeof FATAL_CODES)[keyof typeof FATAL_CODES];
4218
4653
  * snippet of the offending input so consumers can log actionable errors.
4219
4654
  *
4220
4655
  * @remarks
4221
- * Snippets may contain PHI when parsing real clinical messages — redact at
4656
+ * Snippets may contain PHI when parsing real clinical messages: redact at
4222
4657
  * the call site if required by your compliance posture. The library does
4223
4658
  * not redact snippets itself.
4224
4659
  *
@@ -4229,7 +4664,7 @@ type FatalCode = (typeof FATAL_CODES)[keyof typeof FATAL_CODES];
4229
4664
  * parseHL7("");
4230
4665
  * } catch (err) {
4231
4666
  * if (err instanceof Hl7ParseError && err.code === "EMPTY_INPUT") {
4232
- * // handle empty input — err.position, err.snippet available
4667
+ * // handle empty input: err.position, err.snippet available
4233
4668
  * }
4234
4669
  * }
4235
4670
  * ```
@@ -4248,7 +4683,7 @@ declare class Hl7ParseError extends Error {
4248
4683
  }
4249
4684
  /**
4250
4685
  * Thrown by `defineProfile()` and profile-validation code (Phase 6) when a
4251
- * profile definition is structurally invalid — e.g. references an undefined
4686
+ * profile definition is structurally invalid: e.g. references an undefined
4252
4687
  * parent, declares a malformed custom segment, or includes an unsupported
4253
4688
  * date format. Declared in Phase 2 so the error taxonomy is locked before
4254
4689
  * Phase 6 lands; callers may optionally supply the offending profile name
@@ -4279,13 +4714,13 @@ declare class ProfileDefinitionError extends Error {
4279
4714
  * HL7 v2 **Table 0211 (Alternate Character Sets)** resolution for the parser's
4280
4715
  * `Buffer`-decode stage (Phase O). Mirrors the frozen read-only registries
4281
4716
  * `KNOWN_SEGMENTS` / `KNOWN_CODING_SYSTEMS`: a single source of truth mapping an
4282
- * MSH-18 character-set code to how the parser treats it — **decode** (single-byte
4717
+ * MSH-18 character-set code to how the parser treats it: **decode** (single-byte
4283
4718
  * ISO-8859 family + Unicode UTF-8) or **preserve-verbatim** (the multibyte /
4284
4719
  * ISO-2022-switched East-Asian sets and UTF-16/32, which HL7 renders through
4285
4720
  * stateful `\Mxxyyzz\` escapes this phase deliberately does not fully decode).
4286
4721
  *
4287
4722
  * Spec traceability: HL7 v2 Chapter 2, **MSH-18** (item 00692) + **Table 0211**
4288
- * (OID 2.16.840.1.113883.18.116). MSH-18 is **repeating** — the first occurrence
4723
+ * (OID 2.16.840.1.113883.18.116). MSH-18 is **repeating**: the first occurrence
4289
4724
  * is the message's default encoding, later occurrences are alternates activated
4290
4725
  * mid-message by the §2.7.4 charset-switch escapes (`\Cxxyy\` single-byte,
4291
4726
  * `\Mxxyyzz\` multi-byte). A **blank** MSH-18 means 7-bit ASCII (the default).
@@ -4299,18 +4734,18 @@ declare class ProfileDefinitionError extends Error {
4299
4734
  * be re-decoded downstream via `Buffer.from(value, "latin1")`. For a **multibyte**
4300
4735
  * set (UTF-16/32, the East-Asian DBCS/ISO-2022 sets) a content byte can coincide
4301
4736
  * with a structural byte, so tokenization runs on raw bytes and framing is
4302
- * best-effort, not byte-recoverable — which is exactly why decoding those sets is
4737
+ * best-effort, not byte-recoverable: which is exactly why decoding those sets is
4303
4738
  * deferred (see the parser's known-limitations). Because a recognized-but-undecoded
4304
4739
  * set and an unrecognized label both preserve bytes, the exact Table-0211 spelling
4305
- * of the multibyte codes is not load-bearing for safety — only for which warning
4740
+ * of the multibyte codes is not load-bearing for safety: only for which warning
4306
4741
  * (`UNSUPPORTED_CHARSET` vs `UNKNOWN_CHARSET`) fires.
4307
4742
  */
4308
4743
  /**
4309
4744
  * How the parser treats a resolved MSH-18 character set.
4310
4745
  *
4311
- * - `decode` — decode the byte stream to text with {@link CharsetResolution.decoder}.
4312
- * - `verbatim` — read the raw bytes as a 1:1 `latin1` mapping; do not decode
4313
- * (byte-recoverable for single-byte content — see the module header).
4746
+ * - `decode`: decode the byte stream to text with {@link CharsetResolution.decoder}.
4747
+ * - `verbatim`: read the raw bytes as a 1:1 `latin1` mapping; do not decode
4748
+ * (byte-recoverable for single-byte content: see the module header).
4314
4749
  */
4315
4750
  type CharsetTreatment = "decode" | "verbatim";
4316
4751
  /**
@@ -4372,7 +4807,7 @@ declare function canonicalCharset(raw: string): string;
4372
4807
 
4373
4808
  /**
4374
4809
  * HL7 escape-sequence handling for the `@cosyte/hl7` parser pipeline
4375
- * — expands reserved-delimiter escapes on parse (`unescape`) and re-escapes
4810
+ *: expands reserved-delimiter escapes on parse (`unescape`) and re-escapes
4376
4811
  * them back when emitting spec-clean HL7 on serialize (`reescape`).
4377
4812
  *
4378
4813
  * The HL7 v2 spec reserves the delimiter characters (field, component,
@@ -4385,7 +4820,7 @@ declare function canonicalCharset(raw: string): string;
4385
4820
  * sequences. We **decode** sequences whose meaning is byte-exact (delimiter
4386
4821
  * back-substitution, hex, newline, truncation char). We **recognize and
4387
4822
  * preserve verbatim** sequences whose intent is presentational or sender-
4388
- * specific — decoding them would either lose information (formatting/charset)
4823
+ * specific: decoding them would either lose information (formatting/charset)
4389
4824
  * or invent a rendering policy the spec leaves to the consumer. Either way,
4390
4825
  * a recognized standard sequence never emits `UNKNOWN_ESCAPE_SEQUENCE`;
4391
4826
  * that warning is reserved for genuinely-unknown bodies (`\Z..\`, garbage).
@@ -4405,7 +4840,7 @@ declare function canonicalCharset(raw: string): string;
4405
4840
  * \.sp\, \.in\, \.ti\, \.fi\, formatting commands (§2.7.6, kept as
4406
4841
  * \.nf\, \.ce\ semantic sentinels for a renderer)
4407
4842
  * \Cxxyy\, \Mxxyyzz\ single- / multi-byte charset switch
4408
- * (§2.7.4 — sender-local byte sequences;
4843
+ * (§2.7.4: sender-local byte sequences;
4409
4844
  * decoding requires charset context
4410
4845
  * this module does not have)
4411
4846
  *
@@ -4424,7 +4859,7 @@ declare function canonicalCharset(raw: string): string;
4424
4859
  * Unknown or malformed sequences are preserved VERBATIM in the output and
4425
4860
  * emit an `UNKNOWN_ESCAPE_SEQUENCE` warning via `emit`. Unterminated escapes
4426
4861
  * (an escape character with no closing partner before end-of-input) are also
4427
- * preserved in full and warn once — the scan is strictly O(n) and cannot
4862
+ * preserved in full and warn once: the scan is strictly O(n) and cannot
4428
4863
  * infinite-loop on malformed input.
4429
4864
  *
4430
4865
  * @example
@@ -4458,10 +4893,10 @@ declare function unescape(input: string, enc: EncodingCharacters, emit: (w: Hl7P
4458
4893
  * "\n" (LF) → \.br\
4459
4894
  * "\r" (CR) → \X0D\ (a decoded CR is the HL7 segment separator;
4460
4895
  * emitting it raw would corrupt wire framing, so
4461
- * it re-encodes to its hex escape — see below)
4896
+ * it re-encodes to its hex escape: see below)
4462
4897
  *
4463
4898
  * **Lossy by construction for the non-delimiter escape families.** `reescape`
4464
- * only knows about the reserved characters above — it cannot reconstruct a
4899
+ * only knows about the reserved characters above: it cannot reconstruct a
4465
4900
  * recognize-and-preserve escape (`\H\`, formatting, charset, `\Z..\`) or the
4466
4901
  * original bytes of a hex escape (`\X41\` decoded to `A`; casing of `\X0d\`),
4467
4902
  * because those decode to ordinary characters that carry no "I was an escape"
@@ -4483,17 +4918,120 @@ declare function unescape(input: string, enc: EncodingCharacters, emit: (w: Hl7P
4483
4918
  */
4484
4919
  declare function reescape(input: string, enc: EncodingCharacters): string;
4485
4920
 
4921
+ /**
4922
+ * First-class HL7 v2 text codec for `@cosyte/hl7`: the ergonomic
4923
+ * decode / encode pair that sits on top of the parser-internal
4924
+ * `unescape` / `reescape` primitives.
4925
+ *
4926
+ * - {@link decodeText} turns a field's escape-bearing wire text into its
4927
+ * decoded value (delimiter + hex + `\.br\` escapes resolved; presentational
4928
+ * escapes preserved verbatim), with no warning plumbing to wire up.
4929
+ * - {@link encodeText} is the **encode-safe** direction: an arbitrary string in,
4930
+ * a spec-clean field body out that can **never inject a delimiter or forge a
4931
+ * component boundary**. This is the primitive Phase T (typed emit) builds on.
4932
+ *
4933
+ * For a human-readable rendering (formatting commands → whitespace, highlight
4934
+ * dropped), use {@link renderText} instead of {@link decodeText}.
4935
+ */
4936
+
4937
+ /**
4938
+ * Decode a field's escape-bearing HL7 text to its human value: the five
4939
+ * delimiter escapes (`\F\ \S\ \T\ \R\ \E\`), the truncation escape (`\P\`),
4940
+ * `\.br\` (→ newline), and hex (`\Xdddd…\`) are resolved; presentational
4941
+ * escapes (`\H\`/`\N\`, formatting, charset, vendor `\Z..\`) are **preserved
4942
+ * verbatim** so nothing is lost. Never throws.
4943
+ *
4944
+ * This is the one-call inverse of {@link encodeText} for delimiter-bearing
4945
+ * content. It does **not** interpret formatting/highlight: for a normalized
4946
+ * display string use {@link renderText}.
4947
+ *
4948
+ * @param input - the field's escape-bearing text.
4949
+ * @param enc - encoding characters; defaults to the HL7 standard `|^~\&`.
4950
+ * @returns the decoded value string.
4951
+ *
4952
+ * @example
4953
+ * ```ts
4954
+ * import { decodeText } from "@cosyte/hl7";
4955
+ * decodeText("Doe\\S\\John"); // "Doe^John": \S\ → component separator
4956
+ * decodeText("line1\\.br\\line2"); // "line1\nline2"
4957
+ * ```
4958
+ */
4959
+ declare function decodeText(input: string, enc?: EncodingCharacters): string;
4960
+ /**
4961
+ * **Encode-safe** direction: escape an arbitrary string so it can be placed in
4962
+ * an HL7 field as data without ever breaking framing. Every reserved character
4963
+ *: the escape char (escaped **first**, so decoding is unambiguous), the field,
4964
+ * component, subcomponent, and repetition separators, the declared truncation
4965
+ * char, and the framing-critical `\n`/`\r`: is replaced by its escape
4966
+ * sequence, so the value **cannot inject a delimiter or forge a component /
4967
+ * subcomponent / repetition boundary**.
4968
+ *
4969
+ * The hard invariant, property-tested over arbitrary strings:
4970
+ * `decodeText(encodeText(s, enc), enc) === s`, and a message field carrying
4971
+ * `encodeText(s)` **cannot forge a component / subcomponent / repetition
4972
+ * boundary or break framing**: the value never escapes its field.
4973
+ *
4974
+ * Two caveats are inherent to HL7 field encoding, not to this codec, and apply
4975
+ * to *whole-field* re-parse (they do not weaken the no-injection guarantee):
4976
+ * the two-character string `""` is HL7's explicit-null token, so a field whose
4977
+ * entire value is `""` re-parses as null; and the default parser trims field
4978
+ * whitespace, so a value with leading/trailing spaces re-parses trimmed. Encode
4979
+ * such values into a component/subcomponent position, or parse with trimming
4980
+ * off, to preserve them exactly.
4981
+ *
4982
+ * @param input - the arbitrary string to encode.
4983
+ * @param enc - encoding characters; defaults to the HL7 standard `|^~\&`.
4984
+ * @returns the spec-clean, delimiter-safe field body.
4985
+ *
4986
+ * @example
4987
+ * ```ts
4988
+ * import { encodeText, parseHL7 } from "@cosyte/hl7";
4989
+ * // A value full of delimiters cannot break out of its field:
4990
+ * const hostile = "a|b^c~d\\e&f";
4991
+ * const body = encodeText(hostile); // "a\\F\\b\\S\\c\\R\\d\\E\\e\\T\\f"
4992
+ * const msg = parseHL7(`MSH|^~\\&|A|B|C|D|20260101||ADT^A01|1|P|2.5\rNTE|1||${body}`);
4993
+ * msg.segments("NTE")[0]?.field(3).value === hostile; // true: round-trips exactly
4994
+ * ```
4995
+ */
4996
+ declare function encodeText(input: string, enc?: EncodingCharacters): string;
4997
+
4998
+ /**
4999
+ * The `@cosyte/hl7` **text codec**: a first-class, documented namespace for
5000
+ * getting the human string out of a field and safely encoding an arbitrary
5001
+ * string in.
5002
+ *
5003
+ * Exposed on the package as the `text` namespace object so a consumer can, in
5004
+ * one call:
5005
+ *
5006
+ * - `text.decode(field.text)`: resolve delimiter/hex/`\.br\` escapes to a value;
5007
+ * - `text.render(field.text)`: normalize formatting + highlight to a display model;
5008
+ * - `text.encode(anyString)`: encode-safe: no delimiter injection (Phase T's primitive).
5009
+ *
5010
+ * ```ts
5011
+ * import { text } from "@cosyte/hl7";
5012
+ * text.render("Result \\H\\HIGH\\N\\\\.br\\see note").text; // "Result HIGH\nsee note"
5013
+ * text.encode("a|b^c").length > 0; // delimiter-safe
5014
+ * ```
5015
+ *
5016
+ * The same functions are also available as top-level named exports
5017
+ * (`decodeText`, `encodeText`, `renderText`) for tree-shaking-friendly imports.
5018
+ */
5019
+
5020
+ declare namespace index$1 {
5021
+ export { decodeText as decode, encodeText as encode, renderText as render };
5022
+ }
5023
+
4486
5024
  /**
4487
5025
  * Dot-path tokenizer and resolver for the `@cosyte/hl7` structural
4488
5026
  * model. Parses strings like `PID.5.1`, `OBX[2].5`, `PID.3[0].1` into a
4489
5027
  * discriminated-token descriptor, then resolves that descriptor against a
4490
5028
  * `readonly RawSegment[]` tree to produce the decoded leaf string (or
4491
- * `undefined` on missing path). Zero runtime deps — a hand-rolled linear scan
5029
+ * `undefined` on missing path). Zero runtime deps: a hand-rolled linear scan
4492
5030
  * (analog: `src/parser/dates.ts::matchTokenFormat`).
4493
5031
  *
4494
5032
  * Indexing conventions (locked in Phase 3 CONTEXT.md):
4495
- * - `[N]` is ALWAYS 0-indexed — applies to segment repeats AND field repeats (D-01).
4496
- * - Dot-numbers are ALWAYS 1-indexed — matches HL7 spec and Phase 2's 1-indexed
5033
+ * - `[N]` is ALWAYS 0-indexed: applies to segment repeats AND field repeats (D-01).
5034
+ * - Dot-numbers are ALWAYS 1-indexed: matches HL7 spec and Phase 2's 1-indexed
4497
5035
  * `RawSegment.fields` (D-02). `PID.5` → `fields[5]`.
4498
5036
  * - MSH.1 / MSH.2 are the separator char and encoding-chars string, both
4499
5037
  * stored at `fields[0]` / `fields[1]` by Phase 2 tokenize.ts (D-05).
@@ -4553,7 +5091,7 @@ declare function parsePath(path: string): DotPath;
4553
5091
  * leaf value. Returns `undefined` whenever the path does not resolve (missing
4554
5092
  * segment, out-of-range field/component/subcomponent/repetition), and never
4555
5093
  * throws on a missing value. Throws `TypeError` only when `path` itself is
4556
- * malformed — callers relying on "never throws" should pre-validate or wrap
5094
+ * malformed: callers relying on "never throws" should pre-validate or wrap
4557
5095
  * in try/catch.
4558
5096
  *
4559
5097
  * @example
@@ -4567,14 +5105,14 @@ declare function parsePath(path: string): DotPath;
4567
5105
  declare function resolvePath(path: string, segments: readonly RawSegment[], _enc: EncodingCharacters): string | undefined;
4568
5106
 
4569
5107
  /**
4570
- * `HL7` namespace — type-only re-exports of the 10 composite interfaces
5108
+ * `HL7` namespace: type-only re-exports of the 10 composite interfaces
4571
5109
  * (XPN, XAD, CX, CWE, CE, XTN, PL, TS, NM, HD). Consumed via
4572
5110
  * `export * as HL7 from "./model/types/namespace.js";` in the top-level barrel
4573
5111
  * (`src/index.ts`). Named exports of the same interfaces live in the public
4574
5112
  * barrel alongside this namespace for developers who prefer the direct
4575
5113
  * `import type { XPN } ...` style (D-13).
4576
5114
  *
4577
- * The namespace is TYPES-ONLY — parser functions (`parseXpn`, `parseXad`, ...)
5115
+ * The namespace is TYPES-ONLY: parser functions (`parseXpn`, `parseXad`, ...)
4578
5116
  * are exported as value exports from the main barrel, not under `HL7`.
4579
5117
  */
4580
5118
 
@@ -4595,7 +5133,7 @@ declare namespace namespace {
4595
5133
  }
4596
5134
 
4597
5135
  /**
4598
- * `pickMrn` — pick the Medical Record Number string from a PID-3 identifier
5136
+ * `pickMrn`: pick the Medical Record Number string from a PID-3 identifier
4599
5137
  * list. Isolated from `patient.ts` so Phase 6 profile hooks can substitute
4600
5138
  * a profile-aware variant without patching the helper that calls it.
4601
5139
  *
@@ -4606,12 +5144,12 @@ declare namespace namespace {
4606
5144
  * Pick the Medical Record Number string from a list of PID-3 CX identifiers.
4607
5145
  *
4608
5146
  * D-07: prefer the first CX whose `identifierTypeCode === "MR"` (HL7 v2.5+
4609
- * canonical MRN marker). D-10: the match is case-SENSITIVE — lowercase
5147
+ * canonical MRN marker). D-10: the match is case-SENSITIVE: lowercase
4610
5148
  * `"mr"` does NOT match; spec mandates uppercase.
4611
5149
  *
4612
5150
  * D-08: when no MR-typed identifier is found, fall back to the first CX's
4613
5151
  * `idNumber`. Returns `undefined` when the first CX has no `idNumber` (even
4614
- * if later CXs do — the fallback is strictly "first CX", not "first CX with
5152
+ * if later CXs do: the fallback is strictly "first CX", not "first CX with
4615
5153
  * idNumber", because we need a deterministic answer).
4616
5154
  *
4617
5155
  * D-21: no warning emitted. Callers who need strict MR resolution can walk
@@ -4627,7 +5165,7 @@ declare namespace namespace {
4627
5165
  * // → "MRN001"
4628
5166
  *
4629
5167
  * pickMrn([{ idNumber: "X1" }]);
4630
- * // → "X1" (fallback — no MR entry)
5168
+ * // → "X1" (fallback: no MR entry)
4631
5169
  *
4632
5170
  * pickMrn([]);
4633
5171
  * // → undefined
@@ -4636,7 +5174,7 @@ declare namespace namespace {
4636
5174
  declare function pickMrn(identifiers: readonly CX[]): string | undefined;
4637
5175
 
4638
5176
  /**
4639
- * `buildMessage` — top-level outbound factory for the `@cosyte/hl7`
5177
+ * `buildMessage`: top-level outbound factory for the `@cosyte/hl7`
4640
5178
  * package. Synthesizes a complete MSH `RawSegment` from `BuildMessageInit`
4641
5179
  * and returns a real `Hl7Message` (not a builder subtype). Callers chain
4642
5180
  * `.addSegment(...)` (Phase 3 mutation method, unchanged) to append PID,
@@ -4651,7 +5189,7 @@ declare function pickMrn(identifiers: readonly CX[]): string | undefined;
4651
5189
  * - D-10: `BuildMessageInit` shape below.
4652
5190
  * - D-11: internally synthesises a complete MSH `RawSegment` and hands to
4653
5191
  * `new Hl7Message({...})`.
4654
- * - D-12: controlId auto-gen — YYYYMMDDHHmmssSSS + 6 alnum = 23 chars.
5192
+ * - D-12: controlId auto-gen: YYYYMMDDHHmmssSSS + 6 alnum = 23 chars.
4655
5193
  * - D-13: `timestamp` accepts `Date | string`; `Date` formats to
4656
5194
  * `YYYYMMDDHHmmss` UTC.
4657
5195
  * - D-14: encoding chars always `DEFAULT_ENCODING_CHARACTERS`.
@@ -4661,9 +5199,9 @@ declare function pickMrn(identifiers: readonly CX[]): string | undefined;
4661
5199
  *
4662
5200
  * **Absent vs. explicit null at the wire level:** at the HL7 wire level,
4663
5201
  * an empty-string field and an omitted field produce IDENTICAL output
4664
- * (both emit as absent — `||` in the line). If you need to distinguish
5202
+ * (both emit as absent: `||` in the line). If you need to distinguish
4665
5203
  * "explicitly null" (HL7 `""`) from "absent" in an outbound message, use
4666
- * `buildMessage({...}).setField(path, '""')` after construction — the
5204
+ * `buildMessage({...}).setField(path, '""')` after construction: the
4667
5205
  * Phase 3 `setField` mutation method sets `RawField.isNull = true`, which
4668
5206
  * the emitter preserves as the literal two-char string `""` per D-02.
4669
5207
  */
@@ -4678,7 +5216,7 @@ declare function pickMrn(identifiers: readonly CX[]): string | undefined;
4678
5216
  * empty string produce IDENTICAL wire output (both emit as an absent
4679
5217
  * positional field). To emit an HL7 explicit null (`""`) at a specific
4680
5218
  * position in an outbound message, build the message first and then call
4681
- * `.setField(path, '""')` — the Phase 3 mutation method sets `isNull=true`
5219
+ * `.setField(path, '""')`: the Phase 3 mutation method sets `isNull=true`
4682
5220
  * on the underlying `RawField`, and the emitter preserves that as the
4683
5221
  * literal two-char output per D-02.
4684
5222
  *
@@ -4707,7 +5245,7 @@ interface BuildMessageInit {
4707
5245
  *
4708
5246
  * The string is split on `^` into MSH-9 components; each component is
4709
5247
  * emitted verbatim. Literal `^` characters in a component are NOT
4710
- * representable via this field — splitting is unconditional. Callers
5248
+ * representable via this field: splitting is unconditional. Callers
4711
5249
  * needing that edge case should build the message and then use
4712
5250
  * `.setField("MSH.9.1", ...)` etc. after construction.
4713
5251
  *
@@ -4752,7 +5290,7 @@ interface BuildMessageInit {
4752
5290
  *
4753
5291
  * **Empty string vs. omitted field (W1):** at the HL7 wire level, passing
4754
5292
  * `sendingApp: ""` and omitting `sendingApp` produce IDENTICAL output
4755
- * (both emit as absent — `||` at the MSH-3 position). If you need to
5293
+ * (both emit as absent: `||` at the MSH-3 position). If you need to
4756
5294
  * emit an HL7 explicit null (`""`, the two-char literal) at a specific
4757
5295
  * position, build the message first, then use `setField`:
4758
5296
  *
@@ -4784,23 +5322,273 @@ interface BuildMessageInit {
4784
5322
  */
4785
5323
  declare function buildMessage(init: BuildMessageInit): Hl7Message;
4786
5324
 
5325
+ /**
5326
+ * Shared field/segment assembly primitives for the typed builders
5327
+ * (`buildAdt`/`buildOru`: roadmap Phase T). Centralises the MSH synthesis and
5328
+ * the sparse positional-segment assembly so each builder stays declarative and
5329
+ * every builder emits an identical, spec-clean MSH.
5330
+ *
5331
+ * Zero runtime deps: pure functions over the raw positional tree.
5332
+ */
5333
+
5334
+ /**
5335
+ * The MSH envelope shared by every typed builder: the addressing + control
5336
+ * metadata that is independent of the message body. Mirrors `BuildMessageInit`
5337
+ * minus `type` (each builder derives MSH-9 from its own trigger).
5338
+ */
5339
+ interface MessageEnvelope {
5340
+ readonly sendingApp?: string;
5341
+ readonly sendingFacility?: string;
5342
+ readonly receivingApp?: string;
5343
+ readonly receivingFacility?: string;
5344
+ /** Auto-generated via `generateControlId()` when omitted. */
5345
+ readonly controlId?: string;
5346
+ /**
5347
+ * `Date` → HL7 `YYYYMMDDHHmmss` (UTC, seconds); a pre-formatted HL7 TS string
5348
+ * passes through verbatim. Defaults to `new Date()`.
5349
+ */
5350
+ readonly timestamp?: Date | string;
5351
+ /** Defaults to `"2.5"`. */
5352
+ readonly version?: string;
5353
+ /** Defaults to `"P"` (production). */
5354
+ readonly processingId?: string;
5355
+ }
5356
+
5357
+ /**
5358
+ * `buildAdt`: author a spec-clean HL7 v2 **ADT** (admit/discharge/transfer)
5359
+ * message from typed inputs (roadmap Phase T). The conservative-emit mirror of
5360
+ * the read helpers (`msg.patient`, `msg.visit`): a caller supplies structured
5361
+ * values (an {@link XPN} name, {@link CX} identifiers, a {@link TS} birth date,
5362
+ * a {@link PL} location, …) and `buildAdt` assembles `MSH + EVN + PID + PV1`
5363
+ * with correct `^`/`&`/`~` structure via the HL7-R encode-safe path: never
5364
+ * hand-assembling delimiters, never injecting one.
5365
+ *
5366
+ * **Structurally complete + zero-warning.** The emitted message carries the
5367
+ * segment groups the parser's own structure net marks Required for the ADT
5368
+ * events it recognises (patient = PID, visit = PV1), so it re-parses with
5369
+ * **zero warnings** and `msg.structure.missingGroups` empty.
5370
+ *
5371
+ * **Never fabricate.** Only values the caller supplies are emitted; an omitted
5372
+ * optional field becomes an empty/absent field, never a defaulted clinical
5373
+ * value. `patient` is **required**: an ADT patient event with no patient is a
5374
+ * typed `TypeError`, not a guessed PID.
5375
+ *
5376
+ * Spec traceability: HL7 v2 Ch. 3 (ADT: MSH/EVN/PID/PV1), Ch. 2 datatypes.
5377
+ * Zero runtime deps.
5378
+ */
5379
+
5380
+ /** Typed PID (patient identification) content for {@link buildAdt}. */
5381
+ interface AdtPatient {
5382
+ /** PID-1 Set ID. */
5383
+ readonly setId?: string;
5384
+ /** PID-3 Patient Identifier List: one or more CX identifiers (MRN, SSN, …). */
5385
+ readonly identifiers?: CX | readonly CX[];
5386
+ /** PID-5 Patient Name. */
5387
+ readonly name?: XPN | readonly XPN[];
5388
+ /** PID-6 Mother's Maiden Name. */
5389
+ readonly mothersMaidenName?: XPN;
5390
+ /** PID-7 Date/Time of Birth. */
5391
+ readonly birthDateTime?: TS | string;
5392
+ /** PID-8 Administrative Sex (e.g. `"F"`, `"M"`, `"U"`). */
5393
+ readonly administrativeSex?: string;
5394
+ /** PID-11 Patient Address: one or more XAD addresses. */
5395
+ readonly address?: XAD | readonly XAD[];
5396
+ /** PID-13 Phone Number - Home: one or more XTN telecoms. */
5397
+ readonly phoneHome?: XTN | readonly XTN[];
5398
+ /** PID-18 Patient Account Number. */
5399
+ readonly accountNumber?: CX;
5400
+ }
5401
+ /** Typed PV1 (patient visit) content for {@link buildAdt}. */
5402
+ interface AdtVisit {
5403
+ /** PV1-1 Set ID. */
5404
+ readonly setId?: string;
5405
+ /** PV1-2 Patient Class (e.g. `"I"` inpatient, `"O"` outpatient, `"E"` emergency). */
5406
+ readonly patientClass?: string;
5407
+ /** PV1-3 Assigned Patient Location. */
5408
+ readonly assignedLocation?: PL;
5409
+ /** PV1-7 Attending Doctor. */
5410
+ readonly attendingDoctor?: XCN | readonly XCN[];
5411
+ /** PV1-8 Referring Doctor. */
5412
+ readonly referringDoctor?: XCN | readonly XCN[];
5413
+ /** PV1-19 Visit Number. */
5414
+ readonly visitNumber?: CX;
5415
+ /** PV1-44 Admit Date/Time. */
5416
+ readonly admitDateTime?: TS | string;
5417
+ }
5418
+ /** Typed EVN (event type) content for {@link buildAdt}. */
5419
+ interface AdtEvent {
5420
+ /** EVN-2 Recorded Date/Time. */
5421
+ readonly recordedDateTime?: TS | string;
5422
+ /** EVN-6 Event Occurred. */
5423
+ readonly eventOccurred?: TS | string;
5424
+ }
5425
+ /** Input for {@link buildAdt}: the MSH envelope plus the typed segment bodies. */
5426
+ interface BuildAdtInit extends MessageEnvelope {
5427
+ /** PID content. **Required**: never fabricated. */
5428
+ readonly patient: AdtPatient;
5429
+ /** PV1 content. Optional; an (empty) PV1 is emitted regardless so the visit group is present. */
5430
+ readonly visit?: AdtVisit;
5431
+ /** EVN content (EVN-1 is the trigger event; EVN-2/6 optional). */
5432
+ readonly event?: AdtEvent;
5433
+ }
5434
+ /**
5435
+ * Build a spec-clean ADT message for `event` (the MSH-9.2 trigger, e.g.
5436
+ * `"A01"`, `"A04"`, `"A08"`) from typed inputs.
5437
+ *
5438
+ * The result is a real {@link Hl7Message}: `msg.toString()` serialises it,
5439
+ * `parseHL7(msg.toString())` round-trips with zero warnings, and
5440
+ * `msg.patient` / `msg.visit` read back the values supplied.
5441
+ *
5442
+ * @param event - the ADT trigger event (MSH-9.2). Required, non-empty.
5443
+ * @param init - the MSH envelope + typed PID/PV1/EVN content (`patient` required).
5444
+ * @throws TypeError when `event` is empty or `init.patient` is absent.
5445
+ *
5446
+ * @example
5447
+ * ```ts
5448
+ * import { buildAdt, parseHL7 } from "@cosyte/hl7";
5449
+ * const msg = buildAdt("A01", {
5450
+ * sendingApp: "CLINIC",
5451
+ * receivingApp: "LAB",
5452
+ * patient: {
5453
+ * identifiers: { idNumber: "MRN001", identifierTypeCode: "MR" },
5454
+ * name: { familyName: "Test", givenName: "Ann" },
5455
+ * birthDateTime: "19880705",
5456
+ * administrativeSex: "F",
5457
+ * },
5458
+ * visit: { patientClass: "I", assignedLocation: { pointOfCare: "ICU", room: "1", bed: "A" } },
5459
+ * });
5460
+ * const round = parseHL7(msg.toString());
5461
+ * round.warnings.length; // 0
5462
+ * round.patient?.familyName; // "Test"
5463
+ * round.structure.missingGroups; // []
5464
+ * ```
5465
+ */
5466
+ declare function buildAdt(event: string, init: BuildAdtInit): Hl7Message;
5467
+
5468
+ /**
5469
+ * `buildOru`: author a spec-clean HL7 v2 **ORU^R01** (observation result)
5470
+ * message from typed inputs (roadmap Phase T). The conservative-emit mirror of
5471
+ * the read helpers (`msg.orders`, `msg.observations`): a caller supplies a
5472
+ * typed patient, an optional order (OBR), and one or more typed observations
5473
+ * (OBX), and `buildOru` assembles `MSH + PID + OBR + OBX…` with correct
5474
+ * `^`/`&`/`~` structure via the HL7-R encode-safe path.
5475
+ *
5476
+ * **Structurally complete + zero-warning.** The emitted message carries the
5477
+ * ORU^R01 result group the parser's structure net marks Required (OBR/OBX), so
5478
+ * it re-parses with **zero warnings** and `msg.structure.missingGroups` empty.
5479
+ *
5480
+ * **Never fabricate.** Only supplied values are emitted; omitted fields become
5481
+ * empty/absent. `patient` and at least one `observations` entry are
5482
+ * **required**: an ORU with no subject or no result is a typed `TypeError`,
5483
+ * not a guessed PID or a fabricated OBX.
5484
+ *
5485
+ * Spec traceability: HL7 v2 Ch. 7 (ORU: MSH/PID/OBR/OBX), Ch. 2 datatypes.
5486
+ * Zero runtime deps.
5487
+ */
5488
+
5489
+ /**
5490
+ * Typed PID content for {@link buildOru}. Reuses {@link AdtPatient}: the
5491
+ * patient-identification shape is identical across message families.
5492
+ */
5493
+ type OruPatient = AdtPatient;
5494
+ /** Typed OBR (observation request / order) content for {@link buildOru}. */
5495
+ interface OruOrder {
5496
+ /** OBR-1 Set ID. */
5497
+ readonly setId?: string;
5498
+ /** OBR-2 Placer Order Number. */
5499
+ readonly placerOrderNumber?: string;
5500
+ /** OBR-3 Filler Order Number. */
5501
+ readonly fillerOrderNumber?: string;
5502
+ /** OBR-4 Universal Service Identifier. */
5503
+ readonly universalServiceId?: CWE;
5504
+ /** OBR-7 Observation Date/Time. */
5505
+ readonly observationDateTime?: TS | string;
5506
+ /** OBR-16 Ordering Provider. */
5507
+ readonly orderingProvider?: XCN | readonly XCN[];
5508
+ /** OBR-25 Result Status (e.g. `"F"` final, `"P"` preliminary, `"C"` corrected). */
5509
+ readonly resultStatus?: string;
5510
+ }
5511
+ /** Typed OBX (observation / result) content for {@link buildOru}. */
5512
+ interface OruObservation {
5513
+ /** OBX-1 Set ID. */
5514
+ readonly setId?: string;
5515
+ /** OBX-2 Value Type (e.g. `"NM"`, `"ST"`, `"CE"`, `"TX"`). */
5516
+ readonly valueType?: string;
5517
+ /** OBX-3 Observation Identifier. */
5518
+ readonly identifier?: CWE;
5519
+ /** OBX-5 Observation Value (emitted verbatim: the caller owns its formatting). */
5520
+ readonly value?: string;
5521
+ /** OBX-6 Units. */
5522
+ readonly units?: CWE;
5523
+ /** OBX-7 References Range. */
5524
+ readonly referenceRange?: string;
5525
+ /** OBX-8 Abnormal Flags (e.g. `"H"`, `"L"`, `"N"`). */
5526
+ readonly abnormalFlags?: string;
5527
+ /** OBX-11 Observation Result Status (e.g. `"F"` final, `"P"` preliminary). */
5528
+ readonly observationResultStatus?: string;
5529
+ /** OBX-14 Date/Time of the Observation. */
5530
+ readonly observationDateTime?: TS | string;
5531
+ }
5532
+ /** Input for {@link buildOru}: the MSH envelope plus the typed segment bodies. */
5533
+ interface BuildOruInit extends MessageEnvelope {
5534
+ /** PID content. **Required**: never fabricated. */
5535
+ readonly patient: OruPatient;
5536
+ /** OBR content. Optional; an (empty) OBR is emitted regardless so the result group is well-formed. */
5537
+ readonly order?: OruOrder;
5538
+ /** OBX content. **Required, non-empty**: an ORU with no result is a typed error. */
5539
+ readonly observations: readonly OruObservation[];
5540
+ }
5541
+ /**
5542
+ * Build a spec-clean ORU^R01 observation-result message from typed inputs.
5543
+ *
5544
+ * The result is a real {@link Hl7Message}: `msg.toString()` serialises it,
5545
+ * `parseHL7(msg.toString())` round-trips with zero warnings, and
5546
+ * `msg.observations()` reads back the results supplied.
5547
+ *
5548
+ * @param init - the MSH envelope + typed PID/OBR/OBX content. `patient` and a
5549
+ * non-empty `observations` list are required.
5550
+ * @throws TypeError when `patient` is absent or `observations` is empty.
5551
+ *
5552
+ * @example
5553
+ * ```ts
5554
+ * import { buildOru, parseHL7 } from "@cosyte/hl7";
5555
+ * const msg = buildOru({
5556
+ * sendingApp: "LAB",
5557
+ * receivingApp: "EHR",
5558
+ * patient: { identifiers: { idNumber: "MRN001", identifierTypeCode: "MR" },
5559
+ * name: { familyName: "Test", givenName: "Ann" } },
5560
+ * order: { universalServiceId: { identifier: "CBC", text: "Complete Blood Count", nameOfCodingSystem: "L" },
5561
+ * resultStatus: "F" },
5562
+ * observations: [
5563
+ * { setId: "1", valueType: "NM",
5564
+ * identifier: { identifier: "WBC", text: "White Blood Cells", nameOfCodingSystem: "LN" },
5565
+ * value: "7.2", units: { identifier: "10*3/uL" }, observationResultStatus: "F" },
5566
+ * ],
5567
+ * });
5568
+ * const round = parseHL7(msg.toString());
5569
+ * round.warnings.length; // 0
5570
+ * round.observations()[0]?.value; // "7.2"
5571
+ * ```
5572
+ */
5573
+ declare function buildOru(init: BuildOruInit): Hl7Message;
5574
+
4787
5575
  /**
4788
5576
  * Frozen HL7 control-vocabulary tables for ACK generation (Phase C). These
4789
- * are read-only enums sourced from the HL7 v2 standard — `@cosyte/hl7` is the
5577
+ * are read-only enums sourced from the HL7 v2 standard: `@cosyte/hl7` is the
4790
5578
  * single owner of this vocabulary; siblings (notably `@cosyte/mllp`) consume
4791
5579
  * `buildAck` rather than re-declaring these codes.
4792
5580
  *
4793
- * Provenance (re-verify before editing — HL7 tables move):
4794
- * - **Table 0008** Acknowledgment code — https://terminology.hl7.org/CodeSystem-v2-0008.html
4795
- * - **Table 0357** Message error condition codes — https://terminology.hl7.org/CodeSystem-v2-0357.html
4796
- * - **Table 0516** Error severity — HL7 v2 Chapter 2 §2.14.5 (ERR-4)
4797
- * - **Table 0155** Accept/application acknowledgment conditions (MSH-15/16) —
5581
+ * Provenance (re-verify before editing: HL7 tables move):
5582
+ * - **Table 0008** Acknowledgment code: https://terminology.hl7.org/CodeSystem-v2-0008.html
5583
+ * - **Table 0357** Message error condition codes: https://terminology.hl7.org/CodeSystem-v2-0357.html
5584
+ * - **Table 0516** Error severity: HL7 v2 Chapter 2 §2.14.5 (ERR-4)
5585
+ * - **Table 0155** Accept/application acknowledgment conditions (MSH-15/16),
4798
5586
  * HL7 v2 Chapter 2 §2.14.9.15–16
4799
5587
  *
4800
5588
  * Zero runtime deps.
4801
5589
  */
4802
5590
  /**
4803
- * HL7 Table 0008 — Acknowledgment code (MSA-1). The two acknowledgment
5591
+ * HL7 Table 0008: Acknowledgment code (MSA-1). The two acknowledgment
4804
5592
  * **vocabularies**:
4805
5593
  * - **original** mode: `AA` Application Accept · `AE` Application Error ·
4806
5594
  * `AR` Application Reject.
@@ -4838,14 +5626,14 @@ type AckCode = (typeof ACK_CODES)[keyof typeof ACK_CODES];
4838
5626
  */
4839
5627
  declare function isPositiveAck(code: string | undefined): boolean;
4840
5628
  /**
4841
- * Downgrade a positive acknowledgment code to its matching error code —
5629
+ * Downgrade a positive acknowledgment code to its matching error code,
4842
5630
  * `AA` → `AE` (original mode), `CA` → `CE` (enhanced mode). Every other code
4843
5631
  * passes through unchanged.
4844
5632
  *
4845
5633
  * This is the **single upstream source of truth** for the fail-safe downgrade
4846
5634
  * pair: `buildAck` applies it when the inbound carries no MSH-10 correlation
4847
5635
  * id, and `@cosyte/mllp`'s `ack-from-hl7` adapter applies it when the inbound
4848
- * cannot be parsed at all — neither ever fabricates an unverifiable positive
5636
+ * cannot be parsed at all: neither ever fabricates an unverifiable positive
4849
5637
  * acknowledgment, and neither carries its own copy of the mapping.
4850
5638
  *
4851
5639
  * @example
@@ -4858,7 +5646,7 @@ declare function isPositiveAck(code: string | undefined): boolean;
4858
5646
  */
4859
5647
  declare function downgradePositiveAck(code: AckCode): AckCode;
4860
5648
  /**
4861
- * HL7 Table 0516 — Error severity (ERR-4). A v2.5+ construct (ERR was
5649
+ * HL7 Table 0516: Error severity (ERR-4). A v2.5+ construct (ERR was
4862
5650
  * structured differently in v2.3.1).
4863
5651
  *
4864
5652
  * @example
@@ -4878,13 +5666,13 @@ declare const ERR_SEVERITIES: {
4878
5666
  /** Error-severity union (HL7 Table 0516, ERR-4). */
4879
5667
  type ErrSeverity = (typeof ERR_SEVERITIES)[keyof typeof ERR_SEVERITIES];
4880
5668
  /**
4881
- * HL7 Table 0357 — Message error condition codes (ERR-3.1 → ERR-3.2 text).
5669
+ * HL7 Table 0357: Message error condition codes (ERR-3.1 → ERR-3.2 text).
4882
5670
  * Frozen read-only map of `code → standard display text`. The code system
4883
5671
  * name emitted in ERR-3.3 is {@link ERR_CONDITION_CODE_SYSTEM}.
4884
5672
  *
4885
5673
  * Codes `104` (value too long) and `105` (table value not found) are v2.7+
4886
5674
  * additions; the rest are present from v2.5. `buildAck` emits whatever code it
4887
- * is told — it never invents a condition — and looks up the display text here.
5675
+ * is told (it never invents a condition) and looks up the display text here.
4888
5676
  *
4889
5677
  * @example
4890
5678
  * ```ts
@@ -4896,7 +5684,7 @@ declare const ERR_CONDITION_CODES: Readonly<Record<string, string>>;
4896
5684
  /** Code-system name emitted in ERR-3.3 for Table 0357 condition codes. */
4897
5685
  declare const ERR_CONDITION_CODE_SYSTEM = "HL70357";
4898
5686
  /**
4899
- * HL7 Table 0155 — Accept/application acknowledgment conditions (MSH-15 /
5687
+ * HL7 Table 0155: Accept/application acknowledgment conditions (MSH-15 /
4900
5688
  * MSH-16): `AL` Always · `NE` Never · `ER` Error/reject conditions only ·
4901
5689
  * `SU` Successful completion only. Exposed read-only for adapters that
4902
5690
  * surface the inbound sender's stated acknowledgment expectations.
@@ -4922,12 +5710,12 @@ type AckCondition = (typeof ACK_CONDITIONS)[keyof typeof ACK_CONDITIONS];
4922
5710
  type AckMode = "original" | "enhanced";
4923
5711
 
4924
5712
  /**
4925
- * `buildAck` — generate a spec-clean HL7 v2 acknowledgment (ACK) message from
5713
+ * `buildAck`: generate a spec-clean HL7 v2 acknowledgment (ACK) message from
4926
5714
  * an inbound message (Phase C). The boundary with `@cosyte/mllp` is resolved
4927
5715
  * (hl7 roadmap §10.1): **hl7 owns ACK *content*** (this file + the control
4928
5716
  * tables); mllp owns *policy/timing* (the commit contract) and *framing*.
4929
5717
  *
4930
- * `buildAck` is **mechanical** — it builds the disposition it is *told* via
5718
+ * `buildAck` is **mechanical**: it builds the disposition it is *told* via
4931
5719
  * `options.code`; it never decides accept-vs-reject. The one safety override is
4932
5720
  * the fail-safe below: it refuses to fabricate a positive `AA`/`CA` for an
4933
5721
  * inbound message that carries no MSH-10 correlation id.
@@ -4941,7 +5729,7 @@ type AckMode = "original" | "enhanced";
4941
5729
 
4942
5730
  /**
4943
5731
  * One ERR segment's worth of error detail for `buildAck`. Carries **codes and
4944
- * locations only — never echoed PHI values** (the phi-redaction-review gate
5732
+ * locations only: never echoed PHI values** (the phi-redaction-review gate
4945
5733
  * binds this contract).
4946
5734
  *
4947
5735
  * @example
@@ -4958,7 +5746,7 @@ interface AckErrorDetail {
4958
5746
  * HL7 Table 0357 message error condition code (ERR-3.1). Defaults to `"207"`
4959
5747
  * (Application internal error). The standard display text is looked up from
4960
5748
  * Table 0357 and emitted in ERR-3.2; unknown codes emit with empty text
4961
- * (the code is preserved verbatim — never dropped).
5749
+ * (the code is preserved verbatim: never dropped).
4962
5750
  */
4963
5751
  readonly conditionCode?: string;
4964
5752
  /** HL7 Table 0516 severity (ERR-4). Defaults to `"E"` (Error). */
@@ -4966,7 +5754,7 @@ interface AckErrorDetail {
4966
5754
  /**
4967
5755
  * Error location (ERR-2, an HL7 ERL). A structural path such as `"PID^1^5"`
4968
5756
  * (segment id ^ segment sequence ^ field position). **Must not contain a
4969
- * patient data value** — locations point at *where*, never *what*.
5757
+ * patient data value**: locations point at *where*, never *what*.
4970
5758
  */
4971
5759
  readonly location?: string;
4972
5760
  }
@@ -4983,7 +5771,7 @@ interface BuildAckOptions {
4983
5771
  /**
4984
5772
  * The acknowledgment disposition to emit in MSA-1 (HL7 Table 0008). One of
4985
5773
  * `AA`/`AE`/`AR` (original) or `CA`/`CE`/`CR` (enhanced accept-level).
4986
- * Required — `buildAck` builds the disposition it is told. An unknown code
5774
+ * Required: `buildAck` builds the disposition it is told. An unknown code
4987
5775
  * is a programming error and throws `TypeError`.
4988
5776
  */
4989
5777
  readonly code: AckCode;
@@ -4995,7 +5783,7 @@ interface BuildAckOptions {
4995
5783
  /**
4996
5784
  * Optional explicit acknowledgment mode. When omitted it is derived from the
4997
5785
  * inbound MSH-15/16 via {@link detectAckMode}. `buildAck` emits `code`
4998
- * verbatim regardless of mode — this field is advisory metadata for adapters
5786
+ * verbatim regardless of mode: this field is advisory metadata for adapters
4999
5787
  * (e.g. `@cosyte/mllp`'s commit-policy layer) that need the detected mode.
5000
5788
  */
5001
5789
  readonly mode?: AckMode;
@@ -5005,7 +5793,7 @@ interface BuildAckOptions {
5005
5793
  * acknowledgment type) and MSH-16 (application acknowledgment type), per HL7 v2
5006
5794
  * Chapter 2 §2.9: **original** when *both* are absent/empty; **enhanced** when
5007
5795
  * *either* is present. This split is spec-exact (unlike the disposition mapping,
5008
- * which has no single correct model — see the package README).
5796
+ * which has no single correct model: see the package README).
5009
5797
  *
5010
5798
  * @example
5011
5799
  * ```ts
@@ -5018,33 +5806,33 @@ declare function detectAckMode(inbound: Hl7Message): AckMode;
5018
5806
  * Build a spec-clean ACK (`MSH` + `MSA` [+ `ERR`…]) responding to `inbound`.
5019
5807
  *
5020
5808
  * Behavior:
5021
- * - **MSH** — sender/receiver are swapped (inbound MSH-5/6 → ACK MSH-3/4;
5809
+ * - **MSH**: sender/receiver are swapped (inbound MSH-5/6 → ACK MSH-3/4;
5022
5810
  * inbound MSH-3/4 → ACK MSH-5/6); MSH-7 is the current UTC time; MSH-9 is
5023
5811
  * `ACK` (with the inbound trigger event echoed as `ACK^<trigger>^ACK` when
5024
5812
  * present); MSH-10 is a freshly generated control id; MSH-11 (processing id)
5025
5813
  * and MSH-12 (version) echo the inbound values.
5026
- * - **MSA** — MSA-1 = `code`; **MSA-2 echoes the full inbound MSH-10 field**
5027
- * (the raw field structure is carried over whole — a vendor-quirk id like
5814
+ * - **MSA**: MSA-1 = `code`; **MSA-2 echoes the full inbound MSH-10 field**
5815
+ * (the raw field structure is carried over whole: a vendor-quirk id like
5028
5816
  * `ID^X` is never truncated to its first component). The echo carries the
5029
5817
  * inbound field's escape-fidelity overlay (HL7-ESC), so an id bearing a hex
5030
5818
  * escape (`ID\X41\Q`) or a preserved escape (`\H\`) echoes **byte-verbatim**,
5031
- * not canonicalized — exactly the bytes the sender put on the wire, which is
5819
+ * not canonicalized: exactly the bytes the sender put on the wire, which is
5032
5820
  * what MSA-2 correlation compares. The only structural transform is
5033
5821
  * trailing-empty canonicalization (D-02). (A sender that used *custom*
5034
5822
  * encoding characters is **re-delimited spec-cleanly**: the overlay carries
5035
5823
  * the sender's raw bytes in the sender's alphabet, so echoing them verbatim
5036
5824
  * under the ACK's default alphabet would corrupt the field's structure and
5037
- * break correlation — the overlay is therefore bypassed and the decoded id is
5825
+ * break correlation: the overlay is therefore bypassed and the decoded id is
5038
5826
  * re-escaped under default, which re-parses back to the same control id.
5039
5827
  * Default-delimiter senders, the norm, keep the byte-exact overlay echo.)
5040
- * - **ERR** — one segment per supplied {@link AckErrorDetail}: ERR-2 location
5828
+ * - **ERR**: one segment per supplied {@link AckErrorDetail}: ERR-2 location
5041
5829
  * (when given), ERR-3 the Table 0357 condition code as a CWE
5042
5830
  * (`code^text^HL70357`), ERR-4 the Table 0516 severity.
5043
5831
  *
5044
5832
  * **Fail-safe (roadmap §Phase C).** If the inbound message has no MSH-10, the
5045
5833
  * ACK cannot be correlated. `buildAck` then leaves MSA-2 empty and, if a
5046
5834
  * positive accept (`AA`/`CA`) was requested, **downgrades it** to the matching
5047
- * error code (`AE`/`CE`) — it never fabricates an unverifiable positive ACK.
5835
+ * error code (`AE`/`CE`): it never fabricates an unverifiable positive ACK.
5048
5836
  * The returned message carries an `ACK_NO_CORRELATION_ID` warning. (This is the
5049
5837
  * inbound-side complement to `@cosyte/mllp`'s "no commit ⇒ never AA".)
5050
5838
  *
@@ -5063,16 +5851,16 @@ declare function detectAckMode(inbound: Hl7Message): AckMode;
5063
5851
  declare function buildAck(inbound: Hl7Message, options: BuildAckOptions): Hl7Message;
5064
5852
 
5065
5853
  /**
5066
- * `interpretAck` — read-side helper that interprets an inbound HL7 v2
5854
+ * `interpretAck`: read-side helper that interprets an inbound HL7 v2
5067
5855
  * acknowledgment (ACK) message into a typed {@link Acknowledgment} view
5068
5856
  * (Phase C). The mechanical inverse of `buildAck`: it reads MSA-1 (code),
5069
5857
  * MSA-2 (the correlated control id), and every ERR segment.
5070
5858
  *
5071
- * Fail-safe: an absent or unrecognized MSA-1 yields `accepted: false` — the
5859
+ * Fail-safe: an absent or unrecognized MSA-1 yields `accepted: false`: the
5072
5860
  * interpreter NEVER reports an acknowledgment as accepted on ambiguous input.
5073
5861
  *
5074
5862
  * Spec traceability: HL7 v2 Chapter 2 §2.14.8 (MSA), §2.14.5 (ERR). Codes are
5075
- * surfaced verbatim (Table 0008 / 0357 / 0516) — no validation or lookup.
5863
+ * surfaced verbatim (Table 0008 / 0357 / 0516): no validation or lookup.
5076
5864
  *
5077
5865
  * Zero runtime deps.
5078
5866
  */
@@ -5080,18 +5868,18 @@ declare function buildAck(inbound: Hl7Message, options: BuildAckOptions): Hl7Mes
5080
5868
  /**
5081
5869
  * One ERR segment interpreted from an ACK. All fields are surfaced verbatim
5082
5870
  * (no table lookup) and OMITTED when the underlying component is absent
5083
- * (exactOptionalPropertyTypes). Codes/locations only — never PHI.
5871
+ * (exactOptionalPropertyTypes). Codes/locations only: never PHI.
5084
5872
  */
5085
5873
  interface AckErrorEntry {
5086
- /** ERR-3.1 — HL7 Table 0357 condition code. */
5874
+ /** ERR-3.1: HL7 Table 0357 condition code. */
5087
5875
  readonly conditionCode?: string;
5088
- /** ERR-3.2 — condition code display text. */
5876
+ /** ERR-3.2: condition code display text. */
5089
5877
  readonly conditionText?: string;
5090
- /** ERR-3.3 — condition code system name (e.g. `HL70357`). */
5878
+ /** ERR-3.3: condition code system name (e.g. `HL70357`). */
5091
5879
  readonly conditionCodeSystem?: string;
5092
- /** ERR-4 — HL7 Table 0516 severity (`I`/`W`/`E`). */
5880
+ /** ERR-4: HL7 Table 0516 severity (`I`/`W`/`E`). */
5093
5881
  readonly severity?: string;
5094
- /** ERR-2 — error location (an HL7 ERL), surfaced verbatim. */
5882
+ /** ERR-2: error location (an HL7 ERL), surfaced verbatim. */
5095
5883
  readonly location?: string;
5096
5884
  }
5097
5885
  /**
@@ -5115,7 +5903,7 @@ interface Acknowledgment {
5115
5903
  readonly code?: string;
5116
5904
  /**
5117
5905
  * MSA-2 message control id (the correlated inbound MSH-10), surfaced as the
5118
- * field's **canonical wire text** (`Field.text`) — the whole field,
5906
+ * field's **canonical wire text** (`Field.text`): the whole field,
5119
5907
  * delimiters included, never truncated to the first component. Note this is
5120
5908
  * the *re-escaped* form: a properly-escaped id arrives as its wire bytes
5121
5909
  * (`ID\S\X`), and an HL7 explicit-null MSA-2 surfaces as the literal
@@ -5147,7 +5935,7 @@ interface Acknowledgment {
5147
5935
  declare function interpretAck(msg: Hl7Message): Acknowledgment;
5148
5936
 
5149
5937
  /**
5150
- * `defineProfile()` — public factory for building `Profile` objects with
5938
+ * `defineProfile()`: public factory for building `Profile` objects with
5151
5939
  * validation + `describe()` attached (PROF-01, PROF-04, PROF-05).
5152
5940
  *
5153
5941
  * Wave 1 (Plan 06-01) ships the single-profile (no-extends) path;
@@ -5197,7 +5985,7 @@ interface DefineProfileOptions {
5197
5985
  * unknown top-level keys with typo hints (D-07), and missing/empty
5198
5986
  * name.
5199
5987
  *
5200
- * Wave 1 (Plan 06-01) ships the no-extends path — `opts.extends` is
5988
+ * Wave 1 (Plan 06-01) ships the no-extends path: `opts.extends` is
5201
5989
  * ACCEPTED but IGNORED, resulting in `lineage === [opts.name]`
5202
5990
  * regardless. Wave 2 (Plan 06-02) adds full lineage computation + merge
5203
5991
  * semantics.
@@ -5223,7 +6011,7 @@ declare function defineProfile(opts: DefineProfileOptions): Profile;
5223
6011
 
5224
6012
  /**
5225
6013
  * Process-scoped default profile management (PROF-08 / D-18). This module
5226
- * holds the first mutable module-scoped state in the codebase — an
6014
+ * holds the first mutable module-scoped state in the codebase: an
5227
6015
  * intentional trade-off documented in PROJECT.md Key Decisions:
5228
6016
  * `setDefaultProfile` EXISTS but is DISCOURAGED. It is scoped to the
5229
6017
  * current Node process, NOT shared across workers, NOT a symbol-keyed
@@ -5245,7 +6033,7 @@ declare function defineProfile(opts: DefineProfileOptions): Profile;
5245
6033
  * arg of `parseHL7` (D-20): customSegments, dateFormats, onWarning chain,
5246
6034
  * and profile attribution all apply the same way.
5247
6035
  *
5248
- * Explicit args ALWAYS win — `parseHL7(raw, myProfile)` uses `myProfile`
6036
+ * Explicit args ALWAYS win: `parseHL7(raw, myProfile)` uses `myProfile`
5249
6037
  * regardless of the default; `parseHL7(raw, { profile: null })` opts out
5250
6038
  * of the default for a single call without changing the registered
5251
6039
  * default.
@@ -5274,7 +6062,7 @@ declare function defineProfile(opts: DefineProfileOptions): Profile;
5274
6062
  declare function setDefaultProfile(profile: Profile | null): void;
5275
6063
  /**
5276
6064
  * Return the current default profile, or `undefined` if none is
5277
- * registered. Consistent with `msg.profile` convention — `undefined`
6065
+ * registered. Consistent with `msg.profile` convention: `undefined`
5278
6066
  * rather than `null`.
5279
6067
  *
5280
6068
  * @example
@@ -5292,7 +6080,7 @@ declare function getDefaultProfile(): Profile | undefined;
5292
6080
  * `ZCA` (care team membership). BIP-04.
5293
6081
  *
5294
6082
  * The AM/PM meridian variant (`MM/DD/YYYY HH:mm AM/PM`) is intentionally
5295
- * NOT shipped — the library's format-token set does not include AM/PM
6083
+ * NOT shipped: the library's format-token set does not include AM/PM
5296
6084
  * (`SUPPORTED_DATE_TOKENS` = YYYY/MM/DD/HH/mm/ss/SSSS). Consumers needing
5297
6085
  * meridian support can extend this profile or supply their own format
5298
6086
  * handler.
@@ -5350,7 +6138,7 @@ declare const cerner: Profile;
5350
6138
  * feeds, plus two Z-segments: `ZDP` (department context) and `ZRS`
5351
6139
  * (result status). BIP-01.
5352
6140
  *
5353
- * Authored from the public `defineProfile()` API — zero privileged
6141
+ * Authored from the public `defineProfile()` API: zero privileged
5354
6142
  * internal coupling. Consumers extend this profile via
5355
6143
  * `defineProfile({ name: '...', extends: profiles.epic, ... })`.
5356
6144
  *
@@ -5380,7 +6168,7 @@ declare const epic: Profile;
5380
6168
  * `YYYY-MM-DD` (ISO date-only). Two Z-segments: `ZLB` (lab-override
5381
6169
  * flags) and `ZNT` (lab note). BIP-05.
5382
6170
  *
5383
- * The canonical HL7 format `YYYYMMDDHHmmss` is NOT shipped here — it's
6171
+ * The canonical HL7 format `YYYYMMDDHHmmss` is NOT shipped here: it's
5384
6172
  * already the parser's primary (zero-warning) match for TS/DTM.
5385
6173
  *
5386
6174
  * @example
@@ -5404,22 +6192,54 @@ declare const epic: Profile;
5404
6192
  declare const genericLab: Profile;
5405
6193
 
5406
6194
  /**
5407
- * Meditech MAGIC / Expanse HL7 quirks. Ships minute-precision timestamps
5408
- * (`YYYYMMDDHHmm`) — a non-HL7 format Meditech commonly uses in ADT and
5409
- * scheduling feeds (HL7 spec is `YYYYMMDDHHmmss` with seconds). One
5410
- * Z-segment: `ZVI` (visit info). BIP-03.
6195
+ * MEDITECH (MAGIC / 6.x / Expanse) HL7 quirks. Ships minute-precision
6196
+ * timestamps (`YYYYMMDDHHMM`, no seconds) and two DFT charge-capture
6197
+ * Z-segments: `ZF1` (provider-encounter copay data) and `ZF2`
6198
+ * (encounter-procedure data). BIP-03.
6199
+ *
6200
+ * Grounded in **publicly downloadable** MEDITECH interface specifications
6201
+ * (ADR 0018: public specs count as real artifacts), not invented:
6202
+ *
6203
+ * - The **minute-precision** date/time format is confirmed by *two*
6204
+ * public MEDITECH specs: "MEDITECH Admissions and Registration to Other
6205
+ * Vendor Ancillary" (Version 2.4, © 2021 Medical Information Technology,
6206
+ * Inc.) ("Date and Time in Admissions. Format is YYYYMMDDHHMM") and
6207
+ * "MEDITECH Ancillary Charges (LAB/PHA/ITS/IDM)" (Version 2.1, © 2021),
6208
+ * whose MSH-7 is length **12** (= `YYYYMMDDHHMM`) and whose EVN-2/PID-7
6209
+ * are documented "Format is YYYYMMDDHHMM". Minute precision is
6210
+ * HL7-conformant (TS/DTM permit variable precision), so declaring it here
6211
+ * is not about accepting an illegal value: it records MEDITECH's
6212
+ * characteristic no-seconds convention so date resolution across a
6213
+ * MEDITECH feed is explicit rather than incidental.
6214
+ * - `ZF1` and `ZF2` are the DFT (charge) Z-segments defined verbatim in
6215
+ * the Ancillary Charges spec (Version 2.1): `ZF1` = "PROVIDER ENCOUNTER
6216
+ * COPAY DATA" (ZF1-1 PROVIDER ENCOUNTER, ZF1-2 MIS SERVICE GROUP, ZF1-3
6217
+ * SERVICE GROUP COPAY, ZF1-4 VISIT COPAY, ZF1-5 COPAY MINIMUM, ZF1-6
6218
+ * COPAY MAXIMUM); `ZF2` = "ENCOUNTER PROCEDURE DATA" (ZF2-1 SET ID, ZF2-2
6219
+ * PROVIDER ENCOUNTER, ZF2-3 ENCOUNTER DATE, ZF2-4 ENCOUNTER PROCEDURE,
6220
+ * ZF2-5 ENCOUNTER PROCEDURE QUANTITY, ZF2-6 ENCOUNTER PROCEDURE CHARGE,
6221
+ * ZF2-7 PRV PROCEDURE AMOUNT PAID, ZF2-8 PRV PROCEDURE AMOUNT DUE).
6222
+ *
6223
+ * (This replaced an earlier `ZVI` "visit info" segment that was a
6224
+ * community-sourced prior with no citable public grounding: HL7-I
6225
+ * re-grounding, ADR 0018. Field positions here are transcribed directly
6226
+ * from the spec's segment tables.)
6227
+ *
6228
+ * Authored from the public `defineProfile()` API: zero privileged
6229
+ * internal coupling. Consumers extend this profile via
6230
+ * `defineProfile({ name: '...', extends: profiles.meditech, ... })`.
5411
6231
  *
5412
6232
  * @example
5413
6233
  * ```ts
5414
6234
  * import { parseHL7, profiles } from "@cosyte/hl7";
5415
6235
  * const msg = parseHL7(raw, profiles.meditech);
5416
- * const zvi = msg.allSegments().find((s) => s.type === "ZVI");
5417
- * console.log(zvi?.get("visitReason")?.value);
6236
+ * const zf1 = msg.allSegments().find((s) => s.type === "ZF1");
6237
+ * console.log(zf1?.get("visitCopay")?.value);
5418
6238
  * ```
5419
6239
  */
5420
6240
  /**
5421
- * Built-in Meditech MAGIC/Expanse profile (BIP-03). See file header for
5422
- * rationale; use via `parseHL7(raw, profiles.meditech)`.
6241
+ * Built-in MEDITECH MAGIC/6.x/Expanse profile (BIP-03). See file header for
6242
+ * rationale and spec citations; use via `parseHL7(raw, profiles.meditech)`.
5423
6243
  *
5424
6244
  * @example
5425
6245
  * ```ts
@@ -5429,22 +6249,173 @@ declare const genericLab: Profile;
5429
6249
  */
5430
6250
  declare const meditech: Profile;
5431
6251
 
6252
+ /**
6253
+ * Philips Vue PACS ("IS Link") imaging HL7 interface quirks. The Vue PACS
6254
+ * IS Link component receives RIS-side ORM/ADT feeds and carries its
6255
+ * PACS-specific data in six custom Z-segments the HL7 standard does not
6256
+ * define: one per *filler role*:
6257
+ *
6258
+ * - **`ZDS`**: Order Filler: the DICOM **Study Instance UID** (field 1,
6259
+ * first component), the RIS↔PACS bridge (as in the IHE Radiology TF and
6260
+ * the `visage` profile); IS Link uses it to update the accession number.
6261
+ * - **`ZLK`**: Order Filler: study/order **linking** ids (external
6262
+ * workitem id, order link id) that group studies and orders.
6263
+ * - **`ZAO`**: Order Filler: order **additional details** (a base64 XML
6264
+ * key/value blob) plus modality, body part, transfer/acquisition status,
6265
+ * technician + radiologist names/ids, and vendor "custom" string/number/
6266
+ * date slots.
6267
+ * - **`ZEB`**: Patient Filler: an **encrypted** patient-info blob (base64).
6268
+ * - **`ZAP`**: Patient Filler: patient **additional details** (base64 XML)
6269
+ * plus patient "custom" string/number/date slots.
6270
+ * - **`ZAV`**: Visit Filler: visit **additional details** (base64 XML).
6271
+ *
6272
+ * Grounded in the public **Vue PACS 12.2.8 HL7 Interface Specifications**
6273
+ * (Philips, document HA1669 Rev A), §§5.11–5.16: a publicly downloadable
6274
+ * vendor interface spec, not an invented quirk (ADR 0018). The spec's
6275
+ * `TS` timestamps are the HL7-native `YYYYMMDDHHMMSS` form (§2.6), so this
6276
+ * profile declares **no** custom `dateFormats`: only the Z-segments.
6277
+ *
6278
+ * Field positions are transcribed verbatim from the spec's segment tables,
6279
+ * including two of its own gaps/quirks: `ZAO` has **no field 7** (the table
6280
+ * jumps 6 → 8) and `ZAP` has **no field 2** (jumps 1 → 3); the three
6281
+ * `ZAO`/`ZAP` "Custom Date" rows are all printed "…Date 1" in the spec (a
6282
+ * transcription slip) but sit at consecutive positions, so they are named
6283
+ * `…CustomDate1/2/3` here to keep each field name unique.
6284
+ *
6285
+ * `ZEB` holds *encrypted* patient information and `ZAP`/`ZAV` carry
6286
+ * patient/visit blobs: naming the field is exactly how a consumer learns
6287
+ * that segment is PHI-bearing and must not be logged. This profile only
6288
+ * *names* the fields; it never decodes, decrypts, or rewrites them.
6289
+ *
6290
+ * Authored from the public `defineProfile()` API: zero privileged internal
6291
+ * coupling. Consumers extend this profile via
6292
+ * `defineProfile({ name: '...', extends: profiles.philips, ... })`.
6293
+ *
6294
+ * @example
6295
+ * ```ts
6296
+ * import { parseHL7, profiles } from "@cosyte/hl7";
6297
+ * const msg = parseHL7(raw, profiles.philips);
6298
+ * const zds = msg.allSegments().find((s) => s.type === "ZDS");
6299
+ * console.log(zds?.get("studyInstanceUid")?.value); // "1.2.826.0.1.3680043.10.99999.20250326.7"
6300
+ * ```
6301
+ */
6302
+ /**
6303
+ * Built-in Philips Vue PACS ("IS Link") imaging profile (BIP-08). See file
6304
+ * header for rationale; use via `parseHL7(raw, profiles.philips)`.
6305
+ *
6306
+ * @example
6307
+ * ```ts
6308
+ * import { parseHL7, profiles } from "@cosyte/hl7";
6309
+ * const msg = parseHL7(raw, profiles.philips);
6310
+ * ```
6311
+ */
6312
+ declare const philips: Profile;
6313
+
6314
+ /**
6315
+ * VA VistA Radiology / Nuclear Medicine imaging HL7 interface quirks. The
6316
+ * Veterans Affairs VistA Radiology package exchanges HL7 **v2.4** messages
6317
+ * with commercial RIS/PACS systems and carries the DICOM **Study Instance
6318
+ * UID** in a `ZDS` Z-segment (field 1, `RP` "Reference Pointer" composite,
6319
+ * the UID sits in the first component, ZDS-1.1 "Pointer"), so the receiving
6320
+ * image manager can correlate the HL7 order/result with the DICOM study.
6321
+ * This is the same IHE Radiology cross-vendor bridge segment declared by the
6322
+ * `visage` and `philips` profiles: `ZDS` is an IHE extension, not a
6323
+ * VA-proprietary quirk; the value this profile adds is a **named federal
6324
+ * source** grounded in a distinct public spec, plus coverage of the shape the
6325
+ * VA spec documents that the imaging-vendor specs do not: `ZDS` on **ORU**
6326
+ * result messages (VistA sends `ZDS` in **both ORM and ORU**), not just on
6327
+ * the ORM order.
6328
+ *
6329
+ * Grounded in the public **Radiology/Nuclear Medicine 5.0 HL7 Interface
6330
+ * Specification** (Version 3.6, revised for Patch RA*5.0*203, June 2024, U.S.
6331
+ * Department of Veterans Affairs), which documents "ZDS Segment Fields in ORU
6332
+ * and ORM" with `ZDS-1` = Study Instance UID (`RP`: 1.1 Pointer, 1.2
6333
+ * Application ID, 1.3 Type of Data, 1.4 Subtype). It is a publicly
6334
+ * downloadable federal interface spec on the VA VistA Documentation Library
6335
+ * (`va.gov/vdl`), not an invented quirk (ADR 0018). The spec's messaging is
6336
+ * HL7-native v2.4, so its `TS` timestamps use the `YYYYMMDDHHMMSS` form: this
6337
+ * profile therefore declares **no** custom `dateFormats`, only the ZDS
6338
+ * segment.
6339
+ *
6340
+ * Authored from the public `defineProfile()` API: zero privileged internal
6341
+ * coupling. Consumers extend this profile via
6342
+ * `defineProfile({ name: '...', extends: profiles.va, ... })`.
6343
+ *
6344
+ * @example
6345
+ * ```ts
6346
+ * import { parseHL7, profiles } from "@cosyte/hl7";
6347
+ * const msg = parseHL7(raw, profiles.va);
6348
+ * const zds = msg.allSegments().find((s) => s.type === "ZDS");
6349
+ * console.log(zds?.get("studyInstanceUid")?.value); // "1.2.826.0.1.3680043.10.99999.20250326.9"
6350
+ * ```
6351
+ */
6352
+ /**
6353
+ * Built-in VA VistA Radiology / Nuclear Medicine imaging profile (BIP-09).
6354
+ * See file header for rationale; use via `parseHL7(raw, profiles.va)`.
6355
+ *
6356
+ * @example
6357
+ * ```ts
6358
+ * import { parseHL7, profiles } from "@cosyte/hl7";
6359
+ * const msg = parseHL7(raw, profiles.va);
6360
+ * ```
6361
+ */
6362
+ declare const va: Profile;
6363
+
6364
+ /**
6365
+ * Visage 7 imaging/PACS HL7 interface quirks. Radiology/PACS order feeds
6366
+ * carry the DICOM **Study Instance UID** in a `ZDS` Z-segment (field 1,
6367
+ * first component) so the receiving image manager can correlate the HL7
6368
+ * order with the DICOM study: the classic RIS/PACS ↔ HL7 bridge segment
6369
+ * defined by the IHE Radiology Technical Framework. BIP-07.
6370
+ *
6371
+ * Grounded in the public **Visage 7 – HL7 Interface Specification**
6372
+ * (V23.00, Jun 2026, Visage Imaging GmbH), §4.4 "ORM Messages" + the ZDS
6373
+ * segment table ("Study Instance UID … contained in the first component of
6374
+ * the first field of the ZDS Segment"): a publicly downloadable vendor
6375
+ * interface spec, not an invented quirk (ADR 0018). Dates in that spec use
6376
+ * the HL7-native `YYYYMMDDHHMMSS` form, so this profile declares **no**
6377
+ * custom `dateFormats`: only the ZDS segment.
6378
+ *
6379
+ * Authored from the public `defineProfile()` API: zero privileged internal
6380
+ * coupling. Consumers extend this profile via
6381
+ * `defineProfile({ name: '...', extends: profiles.visage, ... })`.
6382
+ *
6383
+ * @example
6384
+ * ```ts
6385
+ * import { parseHL7, profiles } from "@cosyte/hl7";
6386
+ * const msg = parseHL7(raw, profiles.visage);
6387
+ * const zds = msg.allSegments().find((s) => s.type === "ZDS");
6388
+ * console.log(zds?.get("studyInstanceUid")?.value); // "1.2.826.0.1.3680043.10.99999.20250326.1"
6389
+ * ```
6390
+ */
6391
+ /**
6392
+ * Built-in Visage 7 imaging/PACS profile (BIP-07). See file header for
6393
+ * rationale; use via `parseHL7(raw, profiles.visage)`.
6394
+ *
6395
+ * @example
6396
+ * ```ts
6397
+ * import { parseHL7, profiles } from "@cosyte/hl7";
6398
+ * const msg = parseHL7(raw, profiles.visage);
6399
+ * ```
6400
+ */
6401
+ declare const visage: Profile;
6402
+
5432
6403
  /**
5433
6404
  * Public barrel for the `@cosyte/hl7` profile subsystem. Assembles
5434
- * the `profiles` namespace object (5 built-ins) and re-exports the public
6405
+ * the `profiles` namespace object (8 built-ins) and re-exports the public
5435
6406
  * profile API: `defineProfile`, `setDefaultProfile`, `getDefaultProfile`,
5436
6407
  * plus the two type exports `DefineProfileOptions` and
5437
6408
  * `CustomSegmentDefinition`.
5438
6409
  *
5439
- * D-26 contract: individual built-ins are NOT top-level named exports —
6410
+ * D-26 contract: individual built-ins are NOT top-level named exports,
5440
6411
  * consumers access them via `profiles.epic`, `profiles.cerner`, etc.
5441
6412
  * ("epic" is too generic a name for a top-level export.)
5442
6413
  */
5443
6414
 
5444
6415
  /**
5445
- * Namespace object exposing the 5 shipped built-in vendor profiles (epic,
5446
- * cerner, meditech, athena, genericLab). Each is authored via the public
5447
- * `defineProfile()` API (BIP-01..05).
6416
+ * Namespace object exposing the 8 shipped built-in vendor profiles (epic,
6417
+ * cerner, meditech, athena, genericLab, visage, philips, va). Each is authored
6418
+ * via the public `defineProfile()` API (BIP-01..09).
5448
6419
  *
5449
6420
  * @example
5450
6421
  * ```ts
@@ -5459,6 +6430,9 @@ declare const profiles: {
5459
6430
  readonly epic: typeof epic;
5460
6431
  readonly genericLab: typeof genericLab;
5461
6432
  readonly meditech: typeof meditech;
6433
+ readonly philips: typeof philips;
6434
+ readonly va: typeof va;
6435
+ readonly visage: typeof visage;
5462
6436
  };
5463
6437
 
5464
6438
  /**
@@ -5468,7 +6442,7 @@ declare const profiles: {
5468
6442
  *
5469
6443
  * Derived from HL7 v2.5.1 chapters 3-7 (core message segments, order/result
5470
6444
  * tree, financial tree, scheduling, master files). Z-segments
5471
- * (`/^Z[A-Z0-9]{2}$/`) are NOT in this set — they're always user-defined
6445
+ * (`/^Z[A-Z0-9]{2}$/`) are NOT in this set: they're always user-defined
5472
6446
  * and must be declared in a profile to avoid the warning.
5473
6447
  *
5474
6448
  * Frozen as `ReadonlySet<string>` for O(1) lookup without mutation risk.
@@ -5489,7 +6463,7 @@ declare const profiles: {
5489
6463
  declare const KNOWN_SEGMENTS: ReadonlySet<string>;
5490
6464
 
5491
6465
  /**
5492
- * Coding-system provenance (HL7 Table 0396, READ-ONLY) — roadmap Phase F.
6466
+ * Coding-system provenance (HL7 Table 0396, READ-ONLY): roadmap Phase F.
5493
6467
  *
5494
6468
  * Answers one question about a coded element: **"what coding system does this
5495
6469
  * code CLAIM?"** It surfaces the sender's CWE.3 / CE.3 "Name of Coding System"
@@ -5502,20 +6476,20 @@ declare const KNOWN_SEGMENTS: ReadonlySet<string>;
5502
6476
  * - **No lookup, no network, no bundled codeset.** Zero runtime deps; this is
5503
6477
  * a frozen acronym→name map, nothing more.
5504
6478
  * - **Fail-safe.** An unregistered / local / mistyped system id is surfaced
5505
- * **verbatim** with `known: false` — never dropped, never guessed.
6479
+ * **verbatim** with `known: false`: never dropped, never guessed.
5506
6480
  *
5507
6481
  * Because provenance is the *sender's claim*, not a verified fact, a consumer
5508
6482
  * MUST still treat the code per its own trust policy. The value of this module
5509
- * is letting that consumer ask "which system?" before interpreting a code — a
6483
+ * is letting that consumer ask "which system?" before interpreting a code: a
5510
6484
  * "PCN" allergen or an "I10" diagnosis is only safe to read once you know the
5511
6485
  * system it belongs to.
5512
6486
  *
5513
- * Spec traceability: HL7 Table 0396 (Coding System) — the registry of
6487
+ * Spec traceability: HL7 Table 0396 (Coding System): the registry of
5514
6488
  * coding-system acronyms carried in the CWE.3 / CE.3 component. v2.7+ expects
5515
6489
  * the registered acronym. See `docs-content/spec-notes-coding-system.md` for
5516
6490
  * the per-entry source and the `I10` (ICD-10 vs ICD-10-CM) nuance.
5517
6491
  *
5518
- * Zero runtime deps — pure data + pure functions.
6492
+ * Zero runtime deps: pure data + pure functions.
5519
6493
  */
5520
6494
  /**
5521
6495
  * One recognized HL7 Table 0396 coding system: its registered acronym (the
@@ -5536,14 +6510,14 @@ interface KnownCodingSystem {
5536
6510
  }
5537
6511
  /**
5538
6512
  * The safety-relevant subset of HL7 Table 0396 this library recognizes for
5539
- * provenance. Deliberately small and frozen — it is NOT the full Table 0396
6513
+ * provenance. Deliberately small and frozen: it is NOT the full Table 0396
5540
6514
  * registry. Each entry's source is recorded in
5541
6515
  * `docs-content/spec-notes-coding-system.md`.
5542
6516
  *
5543
6517
  * Note on `I10`: Table 0396 registers `I10` as **ICD-10** (the WHO base
5544
6518
  * classification). US v2 feeds frequently send `I10` when they mean
5545
6519
  * ICD-10-**CM**, but that clinical-modification specificity is the sender's
5546
- * convention, not what the acronym registers — so this map reports the
6520
+ * convention, not what the acronym registers: so this map reports the
5547
6521
  * registered claim (`"ICD-10"`) and does not silently upgrade it to CM.
5548
6522
  *
5549
6523
  * @example
@@ -5554,14 +6528,14 @@ interface KnownCodingSystem {
5554
6528
  */
5555
6529
  declare const KNOWN_CODING_SYSTEMS: readonly KnownCodingSystem[];
5556
6530
  /**
5557
- * A coding-system provenance answer — the system a code CLAIMS, never
6531
+ * A coding-system provenance answer: the system a code CLAIMS, never
5558
6532
  * validated. `claimed` is always present and verbatim (never dropped); the
5559
6533
  * resolved `id` / `name` are present only when the claim maps to a registered
5560
6534
  * Table 0396 entry.
5561
6535
  */
5562
6536
  interface CodingSystemInfo {
5563
6537
  /**
5564
- * The coding-system id exactly as it appeared in CWE.3 / CE.3 — preserved
6538
+ * The coding-system id exactly as it appeared in CWE.3 / CE.3: preserved
5565
6539
  * verbatim (original case and spelling), never altered, never dropped.
5566
6540
  */
5567
6541
  readonly claimed: string;
@@ -5575,12 +6549,12 @@ interface CodingSystemInfo {
5575
6549
  /**
5576
6550
  * Resolve a raw coding-system id (a CWE.3 / CE.3 "Name of Coding System"
5577
6551
  * value) to its provenance. Returns `undefined` when there is no claim to
5578
- * resolve — `id` is `undefined`, empty, or whitespace-only.
6552
+ * resolve: `id` is `undefined`, empty, or whitespace-only.
5579
6553
  *
5580
6554
  * Matching is case-insensitive and tolerant of surrounding whitespace, and
5581
6555
  * normalizes the well-known aliases in {@link KNOWN_CODING_SYSTEMS} (e.g.
5582
6556
  * `"LOINC"` → `LN`, `"SNOMED"` → `SCT`, `"RxNorm"` → `RXN`). An unrecognized
5583
- * id is returned verbatim with `known: false` — never guessed.
6557
+ * id is returned verbatim with `known: false`: never guessed.
5584
6558
  *
5585
6559
  * @example
5586
6560
  * ```ts
@@ -5594,7 +6568,7 @@ interface CodingSystemInfo {
5594
6568
  declare function codingSystem(id: string | undefined): CodingSystemInfo | undefined;
5595
6569
  /**
5596
6570
  * Structural shape of any coded element that carries a primary + alternate
5597
- * coding system — both {@link CWE} and {@link CE} satisfy it. Kept structural
6571
+ * coding system: both {@link CWE} and {@link CE} satisfy it. Kept structural
5598
6572
  * (not a union) so callers can pass a `dg.code` / `obs.code` directly.
5599
6573
  */
5600
6574
  interface CodedSystemFields {
@@ -5646,10 +6620,10 @@ declare function alternateCodingSystemOf(coded: CodedSystemFields): CodingSystem
5646
6620
  *
5647
6621
  * `splitBatch()` demarcates the individual `MSH`-led messages by **MSH
5648
6622
  * boundaries**, parses each one with {@link parseHL7} (so every message is
5649
- * returned either as a parsed `Hl7Message` **or** as a typed failure entry —
6623
+ * returned either as a parsed `Hl7Message` **or** as a typed failure entry,
5650
6624
  * a malformed message mid-stream is isolated, never suppresses its siblings),
5651
6625
  * and reconciles the declared envelope counts (BTS-1 batch message count,
5652
- * FTS-1 file batch count) against the actual counts — surfacing a
6626
+ * FTS-1 file batch count) against the actual counts: surfacing a
5653
6627
  * {@link batchCountMismatch} warning on any mismatch **without ever dropping
5654
6628
  * the tail**. A bare single message with no envelope passes straight through
5655
6629
  * as a one-message result.
@@ -5657,7 +6631,7 @@ declare function alternateCodingSystemOf(coded: CodedSystemFields): CodingSystem
5657
6631
  * This is a **separate surface** from `parseHL7` on purpose: `parseHL7` rejects
5658
6632
  * non-`MSH`-first input outright (that is correct for a single-message
5659
6633
  * parser), so batch demarcation lives here. `splitBatch` is a **splitter**, not
5660
- * an enforcer — it does not send batch ACKs, does not enforce any profile's
6634
+ * an enforcer: it does not send batch ACKs, does not enforce any profile's
5661
6635
  * mandatory-envelope rule (it warns via {@link batchMissingTrailer}; the caller
5662
6636
  * decides to reject), and does not de-batch across transport framing (that is
5663
6637
  * `@cosyte/mllp`). See `docs-content/spec-notes-batch.md`.
@@ -5676,7 +6650,7 @@ type BatchEnvelopeName = "FHS" | "BHS" | "BTS" | "FTS";
5676
6650
  /**
5677
6651
  * A raw batch-envelope segment (`FHS`/`BHS`/`BTS`/`FTS`) surfaced by
5678
6652
  * {@link splitBatch}. `fields` is the segment split on its own field separator
5679
- * with `fields[0]` holding the segment name — deliberately the raw token
6653
+ * with `fields[0]` holding the segment name: deliberately the raw token
5680
6654
  * array, not a typed model: first-class FHS/BHS field helpers are deferred
5681
6655
  * (roadmap Phase L defers "typed FHS/BHS helpers beyond raw fields"). Note the
5682
6656
  * HL7 MSH-family indexing quirk: for `FHS`/`BHS`, `fields[1]` is the
@@ -5704,7 +6678,7 @@ interface BatchEnvelopeSegment {
5704
6678
  * One message extracted from a batch stream. Discriminated on `ok`: a
5705
6679
  * successful parse carries the `Hl7Message` (whose own `.warnings` hold any
5706
6680
  * per-message Tier-2 deviations); a message that hit one of the four Tier-3
5707
- * fatal conditions carries the `Hl7ParseError` instead — **isolated**, so the
6681
+ * fatal conditions carries the `Hl7ParseError` instead: **isolated**, so the
5708
6682
  * rest of the batch still yields. `raw` is the message's verbatim source
5709
6683
  * (re-parseable by {@link parseHL7}); `position` is the message's `MSH` (or,
5710
6684
  * for pre-`MSH` stray content, its first) segment index in the stream.
@@ -5733,7 +6707,7 @@ type BatchMessageEntry = {
5733
6707
  * One batch within a stream: a run of messages delimited by a `BHS` header
5734
6708
  * and/or a `BTS` trailer (both optional in §2.10.3, so a `BTS` closes a
5735
6709
  * preceding run into a batch even with no `BHS`). A run of messages with
5736
- * **neither** a header nor a trailer is *not* a batch — those messages live in
6710
+ * **neither** a header nor a trailer is *not* a batch: those messages live in
5737
6711
  * {@link BatchSplitResult.messages} only, so they never inflate a batch count.
5738
6712
  * `declaredMessageCount` is BTS-1 when the trailer declared a usable
5739
6713
  * non-negative integer (it is **optional [0..1]** in the spec, so it may be
@@ -5761,7 +6735,7 @@ interface Batch {
5761
6735
  }
5762
6736
  /**
5763
6737
  * The result of {@link splitBatch}: the flattened `messages` (every message
5764
- * across every batch, in stream order — the primary surface), the nested
6738
+ * across every batch, in stream order: the primary surface), the nested
5765
6739
  * `batches`, the raw file envelope segments, and the batch-level `warnings`
5766
6740
  * (count-mismatch / missing-trailer). `hadEnvelope` is `false` for a bare
5767
6741
  * passthrough (no FHS/BHS/BTS/FTS seen).
@@ -5777,7 +6751,7 @@ interface Batch {
5777
6751
  */
5778
6752
  interface BatchSplitResult {
5779
6753
  /**
5780
- * Every message split out of the stream, in order — the primary surface. This
6754
+ * Every message split out of the stream, in order: the primary surface. This
5781
6755
  * includes messages that belong to no explicit batch (a bare stream, or
5782
6756
  * content outside any `BHS`/`BTS`), so it is a superset of the messages
5783
6757
  * reachable via `batches`.
@@ -5806,16 +6780,16 @@ interface BatchSplitResult {
5806
6780
  * - handles a file with **multiple batches** and a batch with multiple messages;
5807
6781
  * - a **bare single message** (no envelope) passes straight through as one entry;
5808
6782
  * - a **malformed message mid-batch is isolated** (returned as a typed failure
5809
- * entry) — its siblings are still returned, the tail is never dropped;
6783
+ * entry): its siblings are still returned, the tail is never dropped;
5810
6784
  * - reconciles BTS-1 (batch message count) and FTS-1 (file batch count) and
5811
- * emits {@link batchCountMismatch} on a mismatch — counts only, never PHI;
6785
+ * emits {@link batchCountMismatch} on a mismatch: counts only, never PHI;
5812
6786
  * - emits {@link batchMissingTrailer} when a `BHS`/`FHS` header opens a scope no
5813
- * `BTS`/`FTS` closes — a warning, never a throw (the caller decides to reject).
6787
+ * `BTS`/`FTS` closes: a warning, never a throw (the caller decides to reject).
5814
6788
  *
5815
6789
  * The second argument, when given, is forwarded verbatim to {@link parseHL7}
5816
6790
  * for **each** message (profile, `strict`, `charset`, `dateFormats`, …). Under
5817
6791
  * `strict`, a message that would warn surfaces as a failure entry (still
5818
- * isolated). `splitBatch` itself never throws — an empty stream yields an empty
6792
+ * isolated). `splitBatch` itself never throws: an empty stream yields an empty
5819
6793
  * result.
5820
6794
  *
5821
6795
  * @example
@@ -5833,13 +6807,622 @@ interface BatchSplitResult {
5833
6807
  * for (const entry of messages) {
5834
6808
  * if (entry.ok) console.log(entry.message.version); // "2.5"
5835
6809
  * }
5836
- * console.log(warnings.length); // 0 — declared counts match
6810
+ * console.log(warnings.length); // 0: declared counts match
5837
6811
  * ```
5838
6812
  */
5839
6813
  declare function splitBatch(raw: string | Buffer): BatchSplitResult;
5840
6814
  declare function splitBatch(raw: string | Buffer, profile: Profile): BatchSplitResult;
5841
6815
  declare function splitBatch(raw: string | Buffer, options: ParseOptions): BatchSplitResult;
5842
6816
 
6817
+ /**
6818
+ * Public types for the conformance-profile engine (roadmap Phase U). A
6819
+ * **consumer authors** a declarative {@link ConformanceProfile}: a bounded
6820
+ * subset of the HL7 v2 Message-Profile / NIST-IGAMT model (usage codes,
6821
+ * cardinality, length, value-set binding against a consumer-supplied code
6822
+ * list): and {@link validateAgainstProfile} runs it against a parsed message,
6823
+ * returning typed {@link ConformanceFinding}s.
6824
+ *
6825
+ * This is the **sanctioned functionality-plane replacement for the retired
6826
+ * vendor-corpus arc**: instead of hl7 shipping vendor/IHE/regulatory profiles
6827
+ * or code sets, the consumer brings their own interface spec and hl7 validates
6828
+ * against it. hl7 ships **no** profile, **no** code set, and makes **no**
6829
+ * network call: the profile and every value set are supplied by the caller.
6830
+ *
6831
+ * Two invariants govern the whole surface:
6832
+ *
6833
+ * 1. **"No findings" is NOT a conformance attestation.** An empty
6834
+ * {@link ConformanceResult.findings} means "nothing THIS profile checked was
6835
+ * violated": never "this message is conformant." The profile only covers
6836
+ * what the author declared; everything undeclared is unchecked.
6837
+ * 2. **No PHI in findings.** A finding names the structural **locus** (segment
6838
+ * name, field / component index, repetition, occurrence) and the rule that
6839
+ * fired: **never** the offending field value. A "value not in set" finding
6840
+ * says *where* and *which value set*, never *what the value was*.
6841
+ *
6842
+ * @see validateAgainstProfile
6843
+ */
6844
+ /**
6845
+ * The six HL7 v2 conformance **usage codes** (HL7 Conformance Methodology,
6846
+ * Message Profiles; IHE ITI TF Vol.2 Appendix C). They constrain whether an
6847
+ * element must, may, or must not appear:
6848
+ *
6849
+ * - **`R`**: Required. The element SHALL be present (with a value). Absent →
6850
+ * {@link FINDING_CODES.PROFILE_REQUIRED_ABSENT}.
6851
+ * - **`RE`**: Required but may be Empty. The element is supported and SHALL be
6852
+ * sent when the sender has the data; its **absence is never a violation**
6853
+ * (this engine cannot know whether the sender had the data).
6854
+ * - **`C`**: Conditional. Presence depends on a predicate. This bounded engine
6855
+ * ships **no predicate language** (a documented defer: roadmap §5), so a
6856
+ * `C` element's **presence is not evaluated** (treated as optional); its
6857
+ * length / value-set / cardinality rules still apply when it IS present.
6858
+ * - **`CE`**: Conditional but may be Empty. Same non-evaluation as `C`.
6859
+ * - **`O`**: Optional. No presence constraint.
6860
+ * - **`X`**: Not supported / not permitted. The element SHALL NOT be present.
6861
+ * Present → {@link FINDING_CODES.PROFILE_NOT_PERMITTED}.
6862
+ *
6863
+ * @example
6864
+ * ```ts
6865
+ * import type { UsageCode } from "@cosyte/hl7";
6866
+ * const usage: UsageCode = "R";
6867
+ * ```
6868
+ */
6869
+ type UsageCode = "R" | "RE" | "C" | "CE" | "O" | "X";
6870
+ /**
6871
+ * The frozen set of valid {@link UsageCode}s, for runtime validation and
6872
+ * introspection. `USAGE_CODES.R === "R"`.
6873
+ *
6874
+ * @example
6875
+ * ```ts
6876
+ * import { USAGE_CODES } from "@cosyte/hl7";
6877
+ * USAGE_CODES.includes("R" as const); // true
6878
+ * ```
6879
+ */
6880
+ declare const USAGE_CODES: readonly UsageCode[];
6881
+ /**
6882
+ * A repetition-count constraint. `min` / `max` are inclusive bounds on the
6883
+ * number of repetitions (for a field rule) or occurrences (for a segment
6884
+ * rule). `max` may be the literal `"*"` for "unbounded". Omitted bounds are
6885
+ * unconstrained on that side.
6886
+ *
6887
+ * **Cardinality `min` is checked only when the element is present.** An absent
6888
+ * **Required** element is reported as {@link FINDING_CODES.PROFILE_REQUIRED_ABSENT}
6889
+ * (a usage finding), not a cardinality finding: so a missing `R` field with
6890
+ * `cardinality.min = 1` yields exactly one finding, never two.
6891
+ *
6892
+ * @example
6893
+ * ```ts
6894
+ * import type { Cardinality } from "@cosyte/hl7";
6895
+ * const once: Cardinality = { min: 1, max: 1 };
6896
+ * const many: Cardinality = { min: 1, max: "*" };
6897
+ * ```
6898
+ */
6899
+ interface Cardinality {
6900
+ readonly min?: number;
6901
+ readonly max?: number | "*";
6902
+ }
6903
+ /**
6904
+ * A rule for one **field position** within a segment (roadmap Phase U). Every
6905
+ * constraint is optional; a rule with only a `field` index is a no-op.
6906
+ *
6907
+ * @remarks
6908
+ * `field` is the 1-indexed HL7 position (MSH offset handled internally, exactly
6909
+ * like `Segment.field(n)`: `{ field: 9 }` on `MSH` targets MSH-9). Length and
6910
+ * value-set checks read the value at `component` (default **1**), so a coded
6911
+ * field's code (`CWE.1` / `CE.1`) is checked by default; set `component` to
6912
+ * check a different component. Both are applied **per present repetition**.
6913
+ */
6914
+ interface FieldRule {
6915
+ /** 1-indexed HL7 field position (e.g. `3` for PID-3, `9` for MSH-9). */
6916
+ readonly field: number;
6917
+ /**
6918
+ * Optional human label for the field (e.g. `"Patient Identifier List"`).
6919
+ * Structural documentation for the profile author only: findings identify a
6920
+ * field by its PHI-free structural locus (segment + index), never by this
6921
+ * label, so the label is never echoed into a finding message.
6922
+ */
6923
+ readonly name?: string;
6924
+ /** Usage constraint (see {@link UsageCode}). Omitted ⇒ Optional. */
6925
+ readonly usage?: UsageCode;
6926
+ /** Repetition-count constraint for this field. */
6927
+ readonly cardinality?: Cardinality;
6928
+ /** Maximum character length of the checked component value (inclusive). */
6929
+ readonly length?: number;
6930
+ /**
6931
+ * Consumer-supplied permitted-value list. The checked component value must be
6932
+ * a member (case-sensitive exact match). **hl7 ships no code set**: this is
6933
+ * BYO terminology; membership is a literal string check, never a LOINC /
6934
+ * SNOMED / ICD / RxNorm lookup and never a network call.
6935
+ */
6936
+ readonly valueSet?: readonly string[];
6937
+ /**
6938
+ * 1-indexed component whose value the `length` / `valueSet` checks read.
6939
+ * Defaults to `1` (the first component: a coded element's code).
6940
+ */
6941
+ readonly component?: number;
6942
+ /**
6943
+ * Severity for findings this rule produces. Defaults to `"error"`. A profile
6944
+ * author can downgrade a data-quality rule (e.g. a length or value-set check)
6945
+ * to `"warning"` or `"info"` without changing the check itself.
6946
+ */
6947
+ readonly severity?: FindingSeverity;
6948
+ }
6949
+ /**
6950
+ * A rule for one **segment type** (roadmap Phase U). `usage` constrains whether
6951
+ * the segment must / must not appear; `cardinality` constrains how many times;
6952
+ * `fields` are the per-field rules, applied to **every** occurrence of the
6953
+ * segment.
6954
+ */
6955
+ interface SegmentRule {
6956
+ /** Segment name: 3 chars, `[A-Z][A-Z0-9]{2}` (standard or `Z…` segment). */
6957
+ readonly segment: string;
6958
+ /**
6959
+ * Usage for the segment as a whole. `R` ⇒ at least one occurrence required;
6960
+ * `X` ⇒ none permitted; `RE` / `O` ⇒ no presence constraint; `C` / `CE` ⇒
6961
+ * presence not evaluated (no predicate language). Omitted ⇒ Optional.
6962
+ */
6963
+ readonly usage?: UsageCode;
6964
+ /** Occurrence-count constraint for this segment across the message. */
6965
+ readonly cardinality?: Cardinality;
6966
+ /** Per-field rules, applied to each occurrence of this segment. */
6967
+ readonly fields?: readonly FieldRule[];
6968
+ /** Severity for the segment-level presence / cardinality findings. Default `"error"`. */
6969
+ readonly severity?: FindingSeverity;
6970
+ }
6971
+ /**
6972
+ * A **user-authored, declarative** conformance profile (roadmap Phase U). The
6973
+ * consumer supplies this; hl7 ships none. It is a bounded subset of the HL7 v2
6974
+ * Message-Profile model: usage / cardinality / length / consumer-supplied
6975
+ * value set: with **no** conditional-predicate language, **no** bundled code
6976
+ * set, and **no** network binding (all deliberate scope boundaries).
6977
+ *
6978
+ * @example
6979
+ * ```ts
6980
+ * import type { ConformanceProfile } from "@cosyte/hl7";
6981
+ *
6982
+ * // A minimal ADT profile the CONSUMER authors: example, NOT an attestation.
6983
+ * const profile: ConformanceProfile = {
6984
+ * name: "example-adt-min",
6985
+ * segments: [
6986
+ * { segment: "MSH", usage: "R", fields: [{ field: 10, name: "Control ID", usage: "R" }] },
6987
+ * { segment: "PID", usage: "R", cardinality: { min: 1, max: 1 }, fields: [
6988
+ * { field: 3, name: "Patient Identifiers", usage: "R", cardinality: { min: 1, max: 1 } },
6989
+ * { field: 8, name: "Administrative Sex", usage: "RE", valueSet: ["M", "F", "U"] },
6990
+ * ] },
6991
+ * { segment: "ZZZ", usage: "X" },
6992
+ * ],
6993
+ * };
6994
+ * ```
6995
+ */
6996
+ interface ConformanceProfile {
6997
+ /** A name for provenance: echoed into {@link ConformanceResult.profileName}. */
6998
+ readonly name: string;
6999
+ /** The segment rules, evaluated in array order (stable finding order). */
7000
+ readonly segments: readonly SegmentRule[];
7001
+ }
7002
+ /**
7003
+ * Severity of a {@link ConformanceFinding}. `error` is a constraint violation;
7004
+ * `warning` / `info` are author-downgraded advisories (via a rule's
7005
+ * `severity`). {@link FINDING_CODES.PROFILE_MALFORMED} is always `error`.
7006
+ */
7007
+ type FindingSeverity = "error" | "warning" | "info";
7008
+ /**
7009
+ * The frozen registry of finding codes. Stable, additive string codes: a
7010
+ * consumer compares `finding.code === FINDING_CODES.PROFILE_REQUIRED_ABSENT`.
7011
+ * Segment-level vs field-level is disambiguated by whether the finding's
7012
+ * {@link FindingLocus.field} is present, not by separate codes.
7013
+ *
7014
+ * @example
7015
+ * ```ts
7016
+ * import { validateAgainstProfile, FINDING_CODES } from "@cosyte/hl7";
7017
+ * const { findings } = validateAgainstProfile(msg, profile);
7018
+ * const missing = findings.filter((f) => f.code === FINDING_CODES.PROFILE_REQUIRED_ABSENT);
7019
+ * ```
7020
+ */
7021
+ declare const FINDING_CODES: {
7022
+ /** A Required (`R`) segment or field is absent (or present-but-empty). */
7023
+ readonly PROFILE_REQUIRED_ABSENT: "PROFILE_REQUIRED_ABSENT";
7024
+ /** A Not-permitted (`X`) segment or field is present. */
7025
+ readonly PROFILE_NOT_PERMITTED: "PROFILE_NOT_PERMITTED";
7026
+ /** A segment-occurrence or field-repetition count is outside its cardinality. */
7027
+ readonly PROFILE_CARDINALITY: "PROFILE_CARDINALITY";
7028
+ /** A checked component value exceeds the declared maximum length. */
7029
+ readonly PROFILE_LENGTH: "PROFILE_LENGTH";
7030
+ /** A checked component value is not a member of the consumer-supplied value set. */
7031
+ readonly PROFILE_VALUE_NOT_IN_SET: "PROFILE_VALUE_NOT_IN_SET";
7032
+ /** The profile ITSELF is structurally malformed (a diagnostic, not a message finding). */
7033
+ readonly PROFILE_MALFORMED: "PROFILE_MALFORMED";
7034
+ };
7035
+ /**
7036
+ * Discriminant union of every {@link ConformanceFinding} code. Enables
7037
+ * exhaustive `switch` narrowing (the `switch-exhaustiveness-check` lint rule).
7038
+ */
7039
+ type FindingCode = (typeof FINDING_CODES)[keyof typeof FINDING_CODES];
7040
+ /**
7041
+ * The **structural** locus a finding refers to: segment name plus, where
7042
+ * applicable, the field position, component, repetition, and segment
7043
+ * occurrence. Every member is a name or an index: a locus is **inherently
7044
+ * PHI-free** and never carries a field value.
7045
+ *
7046
+ * A finding with no {@link field} is **segment-level** (presence / cardinality
7047
+ * of the segment itself); a finding with a `field` is **field-level**. For a
7048
+ * {@link FINDING_CODES.PROFILE_MALFORMED} diagnostic (a defect in the profile,
7049
+ * not the message) `segment` may be the sentinel `"(profile)"`.
7050
+ */
7051
+ interface FindingLocus {
7052
+ /** Segment name (e.g. `"PID"`), or `"(profile)"` for a profile-shape defect. */
7053
+ readonly segment: string;
7054
+ /** 1-indexed field position, when the finding is field-level. */
7055
+ readonly field?: number;
7056
+ /** 1-indexed component, when a component-scoped check (length / value-set) fired. */
7057
+ readonly component?: number;
7058
+ /** 0-indexed field repetition, when the finding is repetition-scoped. */
7059
+ readonly repetition?: number;
7060
+ /** 0-indexed segment occurrence, when the segment type repeats. */
7061
+ readonly occurrence?: number;
7062
+ }
7063
+ /**
7064
+ * One typed conformance finding. Carries the {@link FindingCode}, a
7065
+ * {@link FindingSeverity}, the structural {@link FindingLocus}, and a
7066
+ * human-readable `message` describing the rule that fired.
7067
+ *
7068
+ * **The `message` is PHI-safe by construction**: it names the locus, the rule,
7069
+ * and (for a value-set miss) the SIZE of the value set, but **never** the
7070
+ * offending field value.
7071
+ *
7072
+ * @example
7073
+ * ```ts
7074
+ * import type { ConformanceFinding } from "@cosyte/hl7";
7075
+ * const f: ConformanceFinding = {
7076
+ * code: "PROFILE_VALUE_NOT_IN_SET",
7077
+ * severity: "error",
7078
+ * locus: { segment: "PID", field: 8, component: 1 },
7079
+ * message: 'PID-8 component 1 value is not in the profile value set (3 permitted codes).',
7080
+ * };
7081
+ * ```
7082
+ */
7083
+ interface ConformanceFinding {
7084
+ readonly code: FindingCode;
7085
+ readonly severity: FindingSeverity;
7086
+ readonly locus: FindingLocus;
7087
+ readonly message: string;
7088
+ }
7089
+ /**
7090
+ * The result of {@link validateAgainstProfile}: the profile's `name` and the
7091
+ * ordered list of `findings`.
7092
+ *
7093
+ * **`findings.length === 0` is NOT a conformance attestation.** It means every
7094
+ * rule the profile declared was satisfied: nothing about the parts of the
7095
+ * message the profile did not cover, and nothing about clinical correctness.
7096
+ * Read it as "no declared rule was violated," never as "conformant."
7097
+ */
7098
+ interface ConformanceResult {
7099
+ readonly profileName: string;
7100
+ readonly findings: readonly ConformanceFinding[];
7101
+ }
7102
+
7103
+ /**
7104
+ * The conformance-profile engine (roadmap Phase U): `validateAgainstProfile`.
7105
+ * Runs a **consumer-authored** declarative {@link ConformanceProfile} against a
7106
+ * parsed {@link Hl7Message} and returns typed {@link ConformanceFinding}s.
7107
+ *
7108
+ * The sanctioned functionality-plane replacement for the retired vendor-corpus
7109
+ * arc: the consumer brings the profile and every value set; hl7 ships **no**
7110
+ * profile, **no** code set, and makes **no** network call. Four invariants the
7111
+ * engine holds absolutely:
7112
+ *
7113
+ * 1. **Never throws.** Any message × any profile (even a malformed profile, or a
7114
+ * value cast through `any`) yields a {@link ConformanceResult}, never an
7115
+ * exception. A malformed profile becomes `PROFILE_MALFORMED` findings.
7116
+ * 2. **Valid ⇒ zero findings**, and **zero findings is NOT an attestation**,
7117
+ * it means no *declared* rule was violated, nothing more (see
7118
+ * {@link ConformanceResult}).
7119
+ * 3. **No PHI in findings.** Findings name the structural locus and the rule,
7120
+ * never the offending value (see `src/conformance/findings.ts`).
7121
+ * 4. **Read-only.** Validation never mutates the message.
7122
+ */
7123
+
7124
+ /**
7125
+ * Validate a parsed HL7 v2 message against a **user-authored** declarative
7126
+ * conformance profile (roadmap Phase U) and return typed findings.
7127
+ *
7128
+ * **Never throws.** A well-formed profile is evaluated rule by rule; a
7129
+ * malformed profile is reported as `PROFILE_MALFORMED` findings (the engine
7130
+ * does not validate against a profile it cannot trust: never a silent pass).
7131
+ * Either way you get a {@link ConformanceResult}. For fail-fast authoring, run
7132
+ * {@link defineConformanceProfile} first: it throws on a malformed profile.
7133
+ *
7134
+ * **`findings.length === 0` is NOT a conformance attestation.** It means every
7135
+ * rule the profile declared was satisfied: nothing about the parts of the
7136
+ * message the profile did not cover, and nothing about clinical correctness.
7137
+ *
7138
+ * **No PHI in findings**: each finding names the structural locus (segment /
7139
+ * field / component / repetition) and the rule, never the offending value.
7140
+ *
7141
+ * **Read-only**: the message is never mutated.
7142
+ *
7143
+ * @param message - a parsed message from {@link parseHL7}.
7144
+ * @param profile - the consumer's declarative {@link ConformanceProfile}.
7145
+ * @returns the profile name and the ordered findings (empty ⇒ no declared rule violated).
7146
+ *
7147
+ * @example
7148
+ * ```ts
7149
+ * import { parseHL7, validateAgainstProfile, type ConformanceProfile } from "@cosyte/hl7";
7150
+ *
7151
+ * const profile: ConformanceProfile = {
7152
+ * name: "example-adt-min",
7153
+ * segments: [
7154
+ * { segment: "PID", usage: "R", fields: [
7155
+ * { field: 3, name: "Patient Identifiers", usage: "R" },
7156
+ * { field: 8, name: "Administrative Sex", usage: "RE", valueSet: ["M", "F", "U"] },
7157
+ * ] },
7158
+ * ],
7159
+ * };
7160
+ *
7161
+ * const msg = parseHL7(raw);
7162
+ * const { findings } = validateAgainstProfile(msg, profile);
7163
+ * for (const f of findings) console.log(f.severity, f.code, f.message);
7164
+ * // findings.length === 0 ⇒ no declared rule violated (NOT an attestation)
7165
+ * ```
7166
+ */
7167
+ declare function validateAgainstProfile(message: Hl7Message, profile: ConformanceProfile): ConformanceResult;
7168
+
7169
+ /**
7170
+ * Profile-shape validation for the conformance engine (roadmap Phase U). A
7171
+ * conformance profile is **consumer-authored configuration**, so it can be
7172
+ * malformed. Two entry points share one total defect collector:
7173
+ *
7174
+ * - {@link collectProfileDefects}: **total over `unknown`, never throws.** It
7175
+ * returns a list of structural {@link ProfileDefect}s (empty ⇒ well-formed).
7176
+ * {@link validateAgainstProfile} calls it first and, on any defect, returns
7177
+ * `PROFILE_MALFORMED` findings instead of validating a profile it cannot
7178
+ * trust (never a silent pass).
7179
+ * - {@link defineConformanceProfile}: the **fail-fast authoring** helper. It
7180
+ * runs the same collector and **throws {@link ProfileDefinitionError}** on the
7181
+ * first-through-all defects, returning the profile typed on success. Use it at
7182
+ * profile-authoring time; the engine itself never throws (task invariant).
7183
+ *
7184
+ * A defect `detail` describes the profile's SHAPE (`segments[2].fields[0].field
7185
+ * must be a positive integer`): profile structure only, never PHI.
7186
+ *
7187
+ * @internal (the two functions are re-exported from the package root)
7188
+ */
7189
+
7190
+ /**
7191
+ * One structural defect in a profile: the PHI-free `detail` plus a best-effort
7192
+ * {@link FindingLocus} (so the engine can attach it to a `PROFILE_MALFORMED`
7193
+ * finding). When the defect is above segment level, `locus.segment` is the
7194
+ * sentinel `"(profile)"`.
7195
+ *
7196
+ * @internal
7197
+ */
7198
+ interface ProfileDefect {
7199
+ readonly locus: FindingLocus;
7200
+ readonly detail: string;
7201
+ }
7202
+ /**
7203
+ * Collect every structural defect in a candidate conformance profile. **Total
7204
+ * over `unknown` and never throws**: a caller may pass any value (even one
7205
+ * cast through `any`) and get back a defect list rather than an exception. An
7206
+ * empty result means the profile is well-formed enough to validate against.
7207
+ *
7208
+ * @internal
7209
+ */
7210
+ declare function collectProfileDefects(profile: unknown): readonly ProfileDefect[];
7211
+ /**
7212
+ * The **fail-fast authoring** gate for a conformance profile (roadmap Phase U's
7213
+ * "malformed profile → typed `ProfileDefinitionError`, build-time, before
7214
+ * validation"). Runs {@link collectProfileDefects}; on any defect, throws a
7215
+ * single {@link ProfileDefinitionError} listing every defect. On success,
7216
+ * returns the profile typed as {@link ConformanceProfile}.
7217
+ *
7218
+ * This is **optional**: {@link validateAgainstProfile} tolerates a raw profile
7219
+ * object and never throws: but it lets an author catch a typo when the profile
7220
+ * is written rather than when it is run.
7221
+ *
7222
+ * @throws {ProfileDefinitionError} when the profile is structurally malformed.
7223
+ *
7224
+ * @example
7225
+ * ```ts
7226
+ * import { defineConformanceProfile } from "@cosyte/hl7";
7227
+ * const profile = defineConformanceProfile({
7228
+ * name: "example-adt-min",
7229
+ * segments: [{ segment: "PID", usage: "R" }],
7230
+ * });
7231
+ * // A typo throws at authoring time:
7232
+ * // defineConformanceProfile({ name: "x", segments: [{ segment: "pid" }] });
7233
+ * // → ProfileDefinitionError: segments[0].segment must be a valid segment name…
7234
+ * ```
7235
+ */
7236
+ declare function defineConformanceProfile(profile: unknown): ConformanceProfile;
7237
+
7238
+ /**
7239
+ * Barrel for the conformance-profile engine (roadmap Phase U). Re-exports the
7240
+ * engine, the fail-fast profile-authoring gate, and the public types. Also
7241
+ * available as the `conformance` namespace object from the package root.
7242
+ *
7243
+ * @see validateAgainstProfile: run a user-authored profile against a message.
7244
+ * @see defineConformanceProfile: optional fail-fast profile-authoring gate.
7245
+ */
7246
+
7247
+ type index_Cardinality = Cardinality;
7248
+ type index_ConformanceFinding = ConformanceFinding;
7249
+ type index_ConformanceProfile = ConformanceProfile;
7250
+ type index_ConformanceResult = ConformanceResult;
7251
+ declare const index_FINDING_CODES: typeof FINDING_CODES;
7252
+ type index_FieldRule = FieldRule;
7253
+ type index_FindingCode = FindingCode;
7254
+ type index_FindingLocus = FindingLocus;
7255
+ type index_FindingSeverity = FindingSeverity;
7256
+ type index_ProfileDefect = ProfileDefect;
7257
+ type index_SegmentRule = SegmentRule;
7258
+ declare const index_USAGE_CODES: typeof USAGE_CODES;
7259
+ type index_UsageCode = UsageCode;
7260
+ declare const index_collectProfileDefects: typeof collectProfileDefects;
7261
+ declare const index_defineConformanceProfile: typeof defineConformanceProfile;
7262
+ declare const index_validateAgainstProfile: typeof validateAgainstProfile;
7263
+ declare namespace index {
7264
+ export { type index_Cardinality as Cardinality, type index_ConformanceFinding as ConformanceFinding, type index_ConformanceProfile as ConformanceProfile, type index_ConformanceResult as ConformanceResult, index_FINDING_CODES as FINDING_CODES, type index_FieldRule as FieldRule, type index_FindingCode as FindingCode, type index_FindingLocus as FindingLocus, type index_FindingSeverity as FindingSeverity, type index_ProfileDefect as ProfileDefect, type index_SegmentRule as SegmentRule, index_USAGE_CODES as USAGE_CODES, type index_UsageCode as UsageCode, index_collectProfileDefects as collectProfileDefects, index_defineConformanceProfile as defineConformanceProfile, index_validateAgainstProfile as validateAgainstProfile };
7265
+ }
7266
+
7267
+ /**
7268
+ * Streaming / incremental parse for the `@cosyte/hl7` parser (roadmap
7269
+ * Phase S). Real ELR / IIS / lab feeds and files ship many messages and can be
7270
+ * far too large to buffer whole; a live source (an already-de-framed MLLP feed,
7271
+ * a growing file) has no "whole" to buffer at all. `parseStream()` consumes a
7272
+ * **chunked** byte/string source: a Node `Readable`, an async-iterable, or a
7273
+ * plain iterable of chunks: and **yields one {@link StreamMessageEntry} per
7274
+ * `MSH`-delimited message** as each boundary completes, holding only
7275
+ * **O(one message)** of state (the in-flight message's lines plus the current
7276
+ * partial-segment buffer): never the whole stream.
7277
+ *
7278
+ * Design (HL7 v2 Ch. 2; note this is engineering guidance, not a spec-mandated
7279
+ * streaming grammar: the base standard prescribes no incremental parse):
7280
+ *
7281
+ * - **`MSH` at segment start is the message boundary.** A message runs from an
7282
+ * `MSH` segment up to (but not including) the next `MSH` (or a batch-envelope
7283
+ * segment, or end of stream). This mirrors {@link splitBatch}'s in-memory
7284
+ * demarcation exactly, so the streamed decomposition of a buffer is identical
7285
+ * to the whole-buffer one.
7286
+ * - **Batch-aware.** The four batch-envelope segments (`FHS`/`BHS`/`BTS`/`FTS`,
7287
+ * §2.10.3) act as message boundaries (they flush the current message) and are
7288
+ * **never yielded as messages**, so `yielded count == MSH count`. Envelope
7289
+ * **count reconciliation** (BTS-1 / FTS-1) is {@link splitBatch}'s job, not this
7290
+ * surface's: `parseStream` streams *messages*, not a batch report.
7291
+ * - **Chunk-boundary invariant.** Segments (including the `MSH|^~\&` header) are
7292
+ * only demarcated once their terminator arrives, so a message split across two
7293
+ * chunks (mid-segment, mid-field, even mid-`MSH`) is reassembled correctly.
7294
+ * Feeding the same bytes in 1-byte chunks vs. one big chunk yields **identical**
7295
+ * messages. A `\r\n` terminator split across a chunk boundary is not mistaken
7296
+ * for a bare `\r` + empty segment (a trailing `\r` waits for the next chunk).
7297
+ * - **Terminator tolerance.** `\r`, `\r\n`, and `\n` are all accepted as segment
7298
+ * terminators (Postel's Law: real feeds mix them), matching the core parser's
7299
+ * `normalize`.
7300
+ * - **Isolation, never dropped tails.** Each message is parsed by the shipped
7301
+ * {@link parseHL7} (no second grammar; raw extraction semantics unchanged) and
7302
+ * surfaced as either an `ok` entry (its own `.warnings` hold per-message
7303
+ * deviations) or a typed **failure** entry carrying the `Hl7ParseError`. A
7304
+ * corrupt message mid-stream is isolated: it **never suppresses** the messages
7305
+ * after it. A final message that ends without a segment terminator is still
7306
+ * yielded in full, flagged via a stream-level {@link unterminatedStreamMessage}
7307
+ * warning (never a throw), so a truncated feed is surfaced, never silently
7308
+ * dropped.
7309
+ *
7310
+ * Transport framing (MLLP `<SB>…<EB><CR>`) is **out of scope**: this consumes an
7311
+ * already-de-framed stream; `@cosyte/mllp` owns the wire. See
7312
+ * `docs-content/spec-notes-stream.md`.
7313
+ */
7314
+
7315
+ /**
7316
+ * A chunked source `parseStream` can consume: a Node `Readable`, any
7317
+ * async-iterable, or any plain iterable of chunks. Chunks are `string`
7318
+ * (text stream) or `Buffer`/`Uint8Array` (binary stream). A real Node stream in
7319
+ * binary mode yields `Buffer`s; in text mode it yields `string`s: a source is
7320
+ * expected to be **homogeneous** (all-text or all-binary), which every real
7321
+ * `Readable` is. A binary chunk is decoded 1:1 via `latin1` (a lossless
7322
+ * byte↔codepoint mapping) so each message's own MSH-18 charset resolution runs
7323
+ * on its original bytes, exactly as {@link splitBatch} does.
7324
+ *
7325
+ * @example
7326
+ * ```ts
7327
+ * import { createReadStream } from "node:fs";
7328
+ * import { parseStream } from "@cosyte/hl7";
7329
+ *
7330
+ * const src: Hl7StreamSource = createReadStream("feed.hl7");
7331
+ * for await (const entry of parseStream(src)) {
7332
+ * if (entry.ok) handle(entry.message);
7333
+ * else quarantine(entry.raw, entry.error.code);
7334
+ * }
7335
+ * ```
7336
+ */
7337
+ type Hl7StreamSource = AsyncIterable<string | Buffer | Uint8Array> | Iterable<string | Buffer | Uint8Array>;
7338
+ /**
7339
+ * One message yielded by {@link parseStream}. Discriminated on `ok`, mirroring
7340
+ * {@link splitBatch}'s per-message entry: a successful parse carries the
7341
+ * `Hl7Message` (whose own `.warnings` hold per-message Tier-2 deviations); a
7342
+ * message that hit one of the four Tier-3 fatals carries the `Hl7ParseError`
7343
+ * instead: **isolated**, so the rest of the stream still yields.
7344
+ *
7345
+ * `raw` is the message's verbatim source (re-parseable by {@link parseHL7});
7346
+ * `position.segmentIndex` is the message's `MSH` (or, for stray pre-`MSH`
7347
+ * content, its first) segment index in the overall stream: the streaming
7348
+ * analogue of {@link splitBatch}'s message position. `streamWarnings` holds
7349
+ * **stream-level** diagnostics that are not per-message parse warnings: today
7350
+ * only {@link unterminatedStreamMessage} on a final message that lacked a
7351
+ * terminator. It is kept separate from `message.warnings` (which stays exactly
7352
+ * what a whole-buffer `parseHL7` of the same bytes would produce) and is
7353
+ * **empty** for every message but a possibly-truncated final one. Both the entry
7354
+ * and `streamWarnings` are frozen.
7355
+ *
7356
+ * @example
7357
+ * ```ts
7358
+ * import { parseStream, WARNING_CODES } from "@cosyte/hl7";
7359
+ * for await (const entry of parseStream(source)) {
7360
+ * for (const w of entry.streamWarnings) {
7361
+ * if (w.code === WARNING_CODES.UNTERMINATED_STREAM_MESSAGE) {
7362
+ * // the feed may have been cut off mid-message
7363
+ * }
7364
+ * }
7365
+ * }
7366
+ * ```
7367
+ */
7368
+ type StreamMessageEntry = {
7369
+ readonly ok: true;
7370
+ readonly message: Hl7Message;
7371
+ readonly raw: string;
7372
+ readonly position: Hl7Position;
7373
+ readonly streamWarnings: readonly Hl7ParseWarning[];
7374
+ } | {
7375
+ readonly ok: false;
7376
+ readonly error: Hl7ParseError;
7377
+ readonly raw: string;
7378
+ readonly position: Hl7Position;
7379
+ readonly streamWarnings: readonly Hl7ParseWarning[];
7380
+ };
7381
+ /**
7382
+ * Incrementally parse a chunked HL7 v2 byte / text stream, yielding one
7383
+ * {@link StreamMessageEntry} per `MSH`-delimited message as its boundary
7384
+ * completes, with **O(one-message)** memory: the whole stream is never
7385
+ * retained. Demarcates by `MSH` boundaries inside the optional
7386
+ * `[FHS] { [BHS] { MSH… } [BTS] } [FTS]` batch frame (HL7 v2 Ch. 2 §2.10.3):
7387
+ *
7388
+ * - a message split across chunk boundaries (mid-segment, mid-field, even
7389
+ * mid-`MSH|^~\&`) is reassembled correctly: feeding the same bytes in 1-byte
7390
+ * chunks vs. one chunk yields **identical** messages;
7391
+ * - `\r`, `\r\n`, and `\n` segment terminators are all tolerated (a `\r\n` split
7392
+ * across a chunk boundary is not mistaken for a bare `\r`);
7393
+ * - each message is parsed by the shipped {@link parseHL7} (no second grammar),
7394
+ * `ok` entries carry the `Hl7Message`, a Tier-3 fatal is an isolated failure
7395
+ * entry; a **malformed message never suppresses later messages**;
7396
+ * - batch-envelope segments (`FHS`/`BHS`/`BTS`/`FTS`) are treated as boundaries
7397
+ * and never yielded as messages, so `yielded count == MSH count` (envelope
7398
+ * count reconciliation is {@link splitBatch}'s job);
7399
+ * - a final message with no trailing terminator is still yielded, flagged with a
7400
+ * stream-level {@link unterminatedStreamMessage} warning: **never a throw, the
7401
+ * tail is never dropped**.
7402
+ *
7403
+ * The second argument, when given, is forwarded verbatim to {@link parseHL7} for
7404
+ * **each** message (profile, `strict`, `charset`, `dateFormats`, …), exactly as
7405
+ * {@link splitBatch} forwards it.
7406
+ *
7407
+ * @example
7408
+ * ```ts
7409
+ * import { parseStream } from "@cosyte/hl7";
7410
+ *
7411
+ * async function* chunks() {
7412
+ * yield "MSH|^~\\&|A|F|B|G|20260101||ADT^A01|1|P|2.5\rPID|||1\r";
7413
+ * yield "MSH|^~\\&|A|F|B|G|20260101||ADT^A01|2|P|2.5\rPID|||2\r";
7414
+ * }
7415
+ *
7416
+ * let count = 0;
7417
+ * for await (const entry of parseStream(chunks())) {
7418
+ * if (entry.ok) count += 1; // 2: one per MSH, streamed, released each time
7419
+ * }
7420
+ * ```
7421
+ */
7422
+ declare function parseStream(source: Hl7StreamSource): AsyncGenerator<StreamMessageEntry, void, void>;
7423
+ declare function parseStream(source: Hl7StreamSource, profile: Profile): AsyncGenerator<StreamMessageEntry, void, void>;
7424
+ declare function parseStream(source: Hl7StreamSource, options: ParseOptions): AsyncGenerator<StreamMessageEntry, void, void>;
7425
+
5843
7426
  /**
5844
7427
  * Public entry point for the `@cosyte/hl7` package.
5845
7428
  *
@@ -5861,4 +7444,4 @@ declare function splitBatch(raw: string | Buffer, options: ParseOptions): BatchS
5861
7444
  */
5862
7445
  declare const VERSION: string;
5863
7446
 
5864
- export { ACK_CODES, ACK_CONDITIONS, type AckCode, type AckCondition, type AckErrorDetail, type AckErrorEntry, type AckMode, type Acknowledgment, type Allergy, type Appointment, type AppointmentResource, BUILTIN_DATE_FALLBACKS, type Batch, type BatchEnvelopeName, type BatchEnvelopeSegment, type BatchMessageEntry, type BatchSplitResult, type BuildAckOptions, type BuildMessageInit, type CE, type CWE, type CX, type Charge, type CharsetResolution, type CharsetTreatment, type ClinicalDocument, type CodedSystemFields, type CodingSystemInfo, type CustomSegmentDefinition, DEFAULT_ENCODING_CHARACTERS, type DefineProfileOptions, type Diagnosis, type DotPath, type DtmParts, type DtmPrecision, type DtmToDateOptions, ERR_CONDITION_CODES, ERR_CONDITION_CODE_SYSTEM, ERR_SEVERITIES, type EncodingCharacters, type ErrSeverity, type ExpectedSegmentGroup, FATAL_CODES, type FatalCode, Field, type HD, namespace as HL7, Hl7Message, Hl7ParseError, type Hl7ParseWarning, type Hl7Position, type IdentityEvent, type IdentityEventKind, type IdentityParty, type IdentityRole, type Immunization, type ImmunizationRecordOrigin, type Insurance, KNOWN_CODING_SYSTEMS, KNOWN_SEGMENTS, type KnownCodingSystem, MESSAGE_STRUCTURE_DEFINITIONS, type Medication, type MedicationAmount, type MedicationComponent, type MedicationContext, type MedicationRoute, type MedicationStrength, type MessageStructure, type MessageStructureDefinition, type Meta, type NM, type NextOfKin, type Observation, type ObservationBase, type OnWarningCallback, type Order, type OrderTiming, type PL, type ParseOptions, type Patient, type Profile, ProfileDefinitionError, type RawComponent, type RawField, type RawRepetition, type RawSegment, type RepeatPattern, type RepeatPatternKind, type SN, SUPPORTED_DATE_TOKENS, Segment, type SerializedMessage, type StructureGroup, type TS, type TimingQuantity, VERSION, type Visit, WARNING_CODES, type WarningCode, type XAD, type XCN, type XPN, type XTN, 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 };
7447
+ export { ACK_CODES, ACK_CONDITIONS, type AckCode, type AckCondition, type AckErrorDetail, type AckErrorEntry, type AckMode, type Acknowledgment, type AdtEvent, type AdtPatient, type AdtVisit, type Allergy, type Appointment, type AppointmentResource, BUILTIN_DATE_FALLBACKS, type Batch, type BatchEnvelopeName, type BatchEnvelopeSegment, type BatchMessageEntry, type BatchSplitResult, type BuildAckOptions, type BuildAdtInit, type BuildMessageInit, type BuildOruInit, type CE, type CWE, type CX, type Cardinality, type Charge, type CharsetResolution, type CharsetTreatment, type ClinicalDocument, type CodedSystemFields, type CodingSystemInfo, type CompositeKind, type CompositeValueByKind, type ConformanceFinding, type ConformanceProfile, type ConformanceResult, type CustomSegmentDefinition, DEFAULT_ENCODING_CHARACTERS, type DefineProfileOptions, type Diagnosis, type DotPath, type DtmParts, type DtmPrecision, type DtmToDateOptions, ERR_CONDITION_CODES, ERR_CONDITION_CODE_SYSTEM, ERR_SEVERITIES, type EncodingCharacters, type ErrSeverity, type ExpectedSegmentGroup, FATAL_CODES, FINDING_CODES, type FatalCode, Field, type FieldRule, type FindingCode, type FindingLocus, type FindingSeverity, type HD, namespace as HL7, Hl7Message, Hl7ParseError, type Hl7ParseWarning, type Hl7Position, type Hl7StreamSource, type IdentityEvent, type IdentityEventKind, type IdentityParty, type IdentityRole, type Immunization, type ImmunizationRecordOrigin, type Insurance, KNOWN_CODING_SYSTEMS, KNOWN_SEGMENTS, type KnownCodingSystem, MESSAGE_STRUCTURE_DEFINITIONS, type Medication, type MedicationAmount, type MedicationComponent, type MedicationContext, type MedicationRoute, type MedicationStrength, type MessageStructure, type MessageStructureDefinition, type Meta, type NM, type NextOfKin, type Observation, type ObservationBase, type OnWarningCallback, type Order, type OrderTiming, type OruObservation, type OruOrder, type OruPatient, type PL, type ParseOptions, type Patient, type Profile, ProfileDefinitionError, type RawComponent, type RawField, type RawRepetition, type RawSegment, type RenderTextOptions, type RenderedText, type RepeatPattern, type RepeatPatternKind, type SN, SUPPORTED_DATE_TOKENS, Segment, type SegmentRule, type SerializedMessage, type StreamMessageEntry, type StructureGroup, type TS, type TextRun, type TimingQuantity, USAGE_CODES, type UsageCode, VERSION, type Visit, WARNING_CODES, type WarningCode, type XAD, type XCN, type XPN, type XTN, ackNoCorrelationId, alternateCodingSystemOf, analyzeMessageStructure, batchCountMismatch, batchMissingTrailer, buildAck, buildAdt, buildMessage, buildOru, canonicalCharset, codingSystem, codingSystemOf, index 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, index$1 as text, timestampFallbackFormat, unescape, unknownCharset, unknownEscapeSequence, unknownSegment, unsupportedCharset, unterminatedEscapeSequence, unterminatedStreamMessage, validateAgainstProfile, versionMismatch };