@cosyte/transform 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.
@@ -0,0 +1,1271 @@
1
+ import { FhirComplex } from '@cosyte/fhir';
2
+ import { HD, TS, CX, CWE, XPN, XAD, NM, Hl7Message } from '@cosyte/hl7';
3
+
4
+ /**
5
+ * The stable code registries for the `@cosyte/transform` diagnostic channel.
6
+ *
7
+ * Two registries, both `key === value` so they survive `Object.values(...)` into a snapshot
8
+ * tripwire, and both **part of the public contract**: consumers branch on these codes, so renaming
9
+ * or removing one is a **breaking change** (mirrors the parser archetype's stable-warning-code rule).
10
+ * New codes are **additions only**.
11
+ *
12
+ * - {@link ISSUE_CODES} — non-fatal, typed diagnostics carried on a {@link TransformResult}. Every
13
+ * fail-safe decision the transform makes (a naked timestamp, an unresolvable assigning authority,
14
+ * an unmapped code, a non-UCUM unit, a dropped element) surfaces as one of these — **never** a
15
+ * silently-defaulted or fabricated FHIR value.
16
+ * - {@link FATAL_CODES} — the small set of unrecoverable conditions reserved for message-level
17
+ * entry points. **Nothing in this library throws one today**: the datatype converters and
18
+ * `toFhir` alike fail safe to a value-free issue instead.
19
+ *
20
+ * @packageDocumentation
21
+ */
22
+ /**
23
+ * Stable **non-fatal issue codes** — the typed diagnostics the fail-safe rule emits.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * import { ISSUE_CODES } from "@cosyte/transform";
28
+ * if (issue.code === ISSUE_CODES.TRANSFORM_TIMESTAMP_NO_TIMEZONE) {
29
+ * // a v2 timestamp had a time-of-day but no timezone offset — reduced to date precision
30
+ * }
31
+ * ```
32
+ */
33
+ declare const ISSUE_CODES: {
34
+ /** A v2 DTM/TS carried a time-of-day but no timezone offset. FHIR forbids time-without-zone, so
35
+ * the value was reduced to date precision (or an explicit sender offset applied via options) —
36
+ * **never** a guessed UTC. */
37
+ readonly TRANSFORM_TIMESTAMP_NO_TIMEZONE: "TRANSFORM_TIMESTAMP_NO_TIMEZONE";
38
+ /** A v2 DTM/TS could not be parsed into a valid FHIR date/time; no value was emitted. */
39
+ readonly TRANSFORM_TIMESTAMP_INVALID: "TRANSFORM_TIMESTAMP_INVALID";
40
+ /** The assigning authority (HD) could not be resolved to a FHIR `Identifier.system` URI via the
41
+ * NamingSystem registry. The identifier is emitted with its value and **no** system — a system URI
42
+ * is **never** synthesized from HD.1 alone. */
43
+ readonly TRANSFORM_IDENTIFIER_SYSTEM_UNRESOLVED: "TRANSFORM_IDENTIFIER_SYSTEM_UNRESOLVED";
44
+ /** A coded value could not be mapped to a FHIR concept — either it carried no coding-system context
45
+ * (CWE.3 absent), or it is a table code the IG ConceptMap has **no target** for (e.g. an OBX-11/
46
+ * OBR-25 result status the HL70085/HL70123 map does not carry, or an OBX-8 abnormal flag absent from
47
+ * HL70078). The original code is preserved / the FHIR value left absent; **never** coerced to a
48
+ * neighbor and **never** guessed to `final`/`normal`. */
49
+ readonly TRANSFORM_CODE_UNMAPPED: "TRANSFORM_CODE_UNMAPPED";
50
+ /** A coding-system mnemonic (CWE.3 / CWE.6) was not recognized, so no canonical system URI could
51
+ * be emitted. The code is preserved; a URI is **never** invented. */
52
+ readonly TRANSFORM_CODE_SYSTEM_UNRESOLVED: "TRANSFORM_CODE_SYSTEM_UNRESOLVED";
53
+ /** A unit was not a valid UCUM code (or was not declared UCUM). It is preserved verbatim in
54
+ * `Quantity.unit`; `Quantity.code`/`.system` are left absent — a UCUM code is **never** fabricated
55
+ * and a magnitude is **never** converted. */
56
+ readonly TRANSFORM_UNIT_NOT_UCUM: "TRANSFORM_UNIT_NOT_UCUM";
57
+ /** A v2 numeric value (NM) could not be represented as a FHIR `decimal` without altering it — e.g.
58
+ * a leading `+`, a leading zero, or a trailing dot, which FHIR's `decimal` lexical form forbids. No
59
+ * `Quantity` value is emitted rather than a canonicalized (and therefore altered) magnitude. */
60
+ readonly TRANSFORM_QUANTITY_VALUE_INVALID: "TRANSFORM_QUANTITY_VALUE_INVALID";
61
+ /** A populated source element was not carried to its FHIR target and was dropped — either because
62
+ * the IG map defines no target, or because that target's conversion is **not implemented**
63
+ * (e.g. XTN→ContactPoint telecom, PV1 participants). Surfaced here rather than silently discarded,
64
+ * never a fabricated value. */
65
+ readonly TRANSFORM_ELEMENT_DROPPED: "TRANSFORM_ELEMENT_DROPPED";
66
+ /** An XPN.7 name-type code has no equivalent in the IG's HL70200 → name-use ConceptMap;
67
+ * `HumanName.use` is left absent rather than guessed. */
68
+ readonly TRANSFORM_NAME_USE_UNMAPPED: "TRANSFORM_NAME_USE_UNMAPPED";
69
+ /** An XAD.7 address-type code has no equivalent in the IG's HL70190 → address-use/type
70
+ * ConceptMaps; `Address.use`/`.type` are left absent rather than guessed. */
71
+ readonly TRANSFORM_ADDRESS_USE_UNMAPPED: "TRANSFORM_ADDRESS_USE_UNMAPPED";
72
+ /** The message's trigger event has no IG *message* map, so its resource graph was assembled from
73
+ * the reusable IG *segment* maps rather than a message map. The graph is best-effort and flagged
74
+ * as such — never a fabricated message map. */
75
+ readonly TRANSFORM_SEGMENT_ASSEMBLED: "TRANSFORM_SEGMENT_ASSEMBLED";
76
+ /** A produced FHIR resource failed `@cosyte/fhir` R4 structural validation and was **withheld**
77
+ * from the bundle rather than emitted as a silently-invalid resource — the conservative-emit gate. */
78
+ readonly TRANSFORM_RESOURCE_INVALID: "TRANSFORM_RESOURCE_INVALID";
79
+ /** A FHIR-required element's value could not be faithfully derived from the source, so it was
80
+ * emitted with a `data-absent-reason` extension (value `unknown`) rather than fabricated — e.g.
81
+ * `MessageHeader.source.endpoint` from an MSH-3 application namespace that is not a URL. */
82
+ readonly TRANSFORM_REQUIRED_ELEMENT_UNKNOWN: "TRANSFORM_REQUIRED_ELEMENT_UNKNOWN";
83
+ };
84
+ /** A value from {@link ISSUE_CODES} — the type consumers narrow `issue.code` against. */
85
+ type IssueCode = (typeof ISSUE_CODES)[keyof typeof ISSUE_CODES];
86
+ /**
87
+ * Stable **fatal codes** — the reserved names for unrecoverable input conditions. **Nothing in this
88
+ * library throws one today**; every path, datatype and message level alike, fails safe to a
89
+ * value-free issue instead. They are declared so that a future one is an addition rather than a
90
+ * rename.
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * import { FATAL_CODES } from "@cosyte/transform";
95
+ * void FATAL_CODES.EMPTY_INPUT;
96
+ * ```
97
+ */
98
+ declare const FATAL_CODES: {
99
+ /** The input carried nothing to transform. */
100
+ readonly EMPTY_INPUT: "EMPTY_INPUT";
101
+ /** The input was not a shape this transform accepts. */
102
+ readonly TRANSFORM_UNSUPPORTED_INPUT: "TRANSFORM_UNSUPPORTED_INPUT";
103
+ };
104
+ /** A value from {@link FATAL_CODES} — the type carried by a thrown fatal error. */
105
+ type FatalCode = (typeof FATAL_CODES)[keyof typeof FATAL_CODES];
106
+
107
+ /**
108
+ * The value-free {@link TransformIssue} — the single diagnostic shape the whole library emits.
109
+ *
110
+ * Every issue is **`OperationOutcome`-shaped and PHI-safe by construction**: it carries the *v2
111
+ * location* (segment / field / component index — never a value) and the *FHIR path* it concerns,
112
+ * plus a **static, per-code** severity and human-readable message drawn from {@link ISSUE_REGISTRY}.
113
+ * Nothing in an issue is interpolated from patient data — the factory takes only positional metadata,
114
+ * so there is no code path by which a name, DOB, MRN, or result value can reach a log line (the
115
+ * discipline `@cosyte/fhir` already proved with its value-free `OperationOutcome`).
116
+ *
117
+ * @packageDocumentation
118
+ */
119
+
120
+ /** The severity a {@link TransformIssue} carries — an `OperationOutcome.issue.severity` value. */
121
+ type TransformSeverity = "error" | "warning" | "information";
122
+ /**
123
+ * A single value-free diagnostic.
124
+ *
125
+ * @example
126
+ * ```ts
127
+ * import { ISSUE_CODES } from "@cosyte/transform";
128
+ * // issue.code === ISSUE_CODES.TRANSFORM_TIMESTAMP_NO_TIMEZONE
129
+ * // issue.v2Location === "TS.1"; issue.fhirPath === "dateTime"
130
+ * ```
131
+ */
132
+ interface TransformIssue {
133
+ /** The stable code. One of {@link ISSUE_CODES}. */
134
+ readonly code: IssueCode;
135
+ /** The `OperationOutcome`-style severity, fixed per code. */
136
+ readonly severity: TransformSeverity;
137
+ /** The v2 source location — a segment / field / component **index**, never a value. */
138
+ readonly v2Location: string;
139
+ /** The FHIR path this issue concerns (e.g. `Identifier.system`), when applicable. */
140
+ readonly fhirPath?: string;
141
+ /** A static, value-free description drawn from {@link ISSUE_REGISTRY}. */
142
+ readonly message: string;
143
+ }
144
+ /** The fixed metadata for a code: its severity, its FHIR `issue-type` code, and a static message. */
145
+ interface IssueMeta {
146
+ readonly severity: TransformSeverity;
147
+ /** The FHIR `OperationOutcome.issue.code` (R4 `issue-type` value set) this maps to. */
148
+ readonly fhirIssueType: string;
149
+ /** A static, value-free message. Contains no interpolated data — safe to log verbatim. */
150
+ readonly message: string;
151
+ }
152
+ /**
153
+ * The per-code registry: severity, FHIR `issue-type`, and a static message. Frozen and exhaustive
154
+ * over {@link ISSUE_CODES} (enforced by the `Record<IssueCode, …>` type — a new code will not
155
+ * compile until it has an entry).
156
+ */
157
+ declare const ISSUE_REGISTRY: Readonly<Record<IssueCode, IssueMeta>>;
158
+ /**
159
+ * Construct a value-free {@link TransformIssue}. The severity and message come from
160
+ * {@link ISSUE_REGISTRY}; the caller supplies only positional metadata, so an issue can carry no PHI.
161
+ *
162
+ * @param code - The stable {@link IssueCode}.
163
+ * @param v2Location - The v2 source location (segment / field / component index) — never a value.
164
+ * @param fhirPath - The FHIR path the issue concerns, when applicable.
165
+ * @example
166
+ * ```ts
167
+ * import { issue, ISSUE_CODES } from "@cosyte/transform";
168
+ * const i = issue(ISSUE_CODES.TRANSFORM_TIMESTAMP_NO_TIMEZONE, "TS.1", "dateTime");
169
+ * void i.severity; // "warning"
170
+ * ```
171
+ */
172
+ declare function issue(code: IssueCode, v2Location: string, fhirPath?: string): TransformIssue;
173
+ /**
174
+ * The FHIR `issue-type` code for an {@link IssueCode} — used by the `OperationOutcome` renderer.
175
+ *
176
+ * @param code - The stable {@link IssueCode}.
177
+ * @example
178
+ * ```ts
179
+ * import { fhirIssueTypeFor, ISSUE_CODES } from "@cosyte/transform";
180
+ * fhirIssueTypeFor(ISSUE_CODES.TRANSFORM_IDENTIFIER_SYSTEM_UNRESOLVED); // "not-found"
181
+ * ```
182
+ */
183
+ declare function fhirIssueTypeFor(code: IssueCode): string;
184
+
185
+ /**
186
+ * The {@link ConvertResult} envelope every datatype converter returns.
187
+ *
188
+ * A converter never throws on ambiguity and never returns a "confident wrong" value: it returns the
189
+ * FHIR value it could faithfully produce (or `undefined` when nothing can be safely emitted) together
190
+ * with the value-free {@link TransformIssue}s it raised. This is the fail-safe rule as a type.
191
+ *
192
+ * @packageDocumentation
193
+ */
194
+
195
+ /**
196
+ * The result of one datatype conversion: the produced FHIR value (or `undefined` when the input was
197
+ * empty or un-emittable) plus the diagnostics raised.
198
+ *
199
+ * @template T - The produced FHIR value's type (a `FhirComplex` datatype node, or a lexical string
200
+ * for `dateTime`).
201
+ *
202
+ * @example
203
+ * ```ts
204
+ * import { toFhirHumanName } from "@cosyte/transform";
205
+ * const { value, issues } = toFhirHumanName({ familyName: "Public" });
206
+ * // value is a FHIR HumanName node; issues is [] here
207
+ * void value;
208
+ * void issues;
209
+ * ```
210
+ */
211
+ interface ConvertResult<T> {
212
+ /** The produced FHIR value, or `undefined` when nothing could be safely emitted. */
213
+ readonly value: T | undefined;
214
+ /** The value-free diagnostics raised during the conversion, in emission order. */
215
+ readonly issues: readonly TransformIssue[];
216
+ }
217
+
218
+ /**
219
+ * Render a list of {@link TransformIssue}s as a FHIR `OperationOutcome` resource model.
220
+ *
221
+ * The transform's diagnostic channel is `OperationOutcome`-shaped by design; this is the adapter that
222
+ * materializes it as an actual `@cosyte/fhir` resource node a consumer can serialize, validate, or
223
+ * return alongside a bundle. It is **value-free**: every field is drawn from the issue's static
224
+ * metadata (code, severity, message) and its positional locations (v2 location → `diagnostics`, FHIR
225
+ * path → `expression`) — no patient data is reachable here.
226
+ *
227
+ * @packageDocumentation
228
+ */
229
+
230
+ /** The code system under which the transform's stable issue codes are carried in `details.coding`. */
231
+ declare const TRANSFORM_ISSUE_SYSTEM = "https://cosyte.com/fhir/CodeSystem/transform-issue-codes";
232
+ /**
233
+ * Build a FHIR `OperationOutcome` {@link FhirComplex} from the given issues. An empty list still
234
+ * produces a structurally-valid `OperationOutcome` with a single `information` "all clear" issue
235
+ * (FHIR requires `OperationOutcome.issue` to be non-empty).
236
+ *
237
+ * @param issues - The value-free diagnostics to render.
238
+ * @example
239
+ * ```ts
240
+ * import { toOperationOutcome } from "@cosyte/transform";
241
+ * const oo = toOperationOutcome([]);
242
+ * // oo is a FhirComplex resource node with resourceType "OperationOutcome"
243
+ * void oo;
244
+ * ```
245
+ */
246
+ declare function toOperationOutcome(issues: readonly TransformIssue[]): FhirComplex;
247
+
248
+ /**
249
+ * The NamingSystem registry — how an HL7 v2 identity/coding namespace becomes a FHIR canonical URI.
250
+ *
251
+ * Two resolutions live here, and both are **fail-safe by refusal**:
252
+ *
253
+ * 1. **Assigning authority (HD) → `Identifier.system`.** The IG's CX→Identifier map says CX.4 maps to
254
+ * `Identifier.system` *only when the authority is in an identifier registry* — the URI comes from a
255
+ * NamingSystem lookup, **not** string concatenation. There is no deterministic algorithm from an
256
+ * HD to a URI, so this resolver **never synthesizes a system from HD.1 (the bare namespace
257
+ * mnemonic) alone** — doing so would let two hospitals reusing "MR"/"HOSPMRN" collide and merge two
258
+ * patients. The *only* auto-derivations are the unambiguous ones: `urn:oid:<oid>` when HD.2 is a
259
+ * valid OID with HD.3 = `ISO`, and `urn:uuid:<uuid>` when HD.3 = `UUID`. Everything else must be an
260
+ * explicit, caller-seeded registry entry, or it resolves to `undefined` and the caller emits a
261
+ * typed issue.
262
+ *
263
+ * 2. **v2 coding-system mnemonic → canonical URI.** CWE.3/CWE.6 carry a v2 Table 0396 mnemonic
264
+ * (`LN`, `SCT`, …); FHIR needs the canonical URI (`http://loinc.org`, …). {@link DEFAULT_V2_CODE_SYSTEMS}
265
+ * seeds a small, license-clean set of the universally-fixed FHIR-core systems; an unrecognized
266
+ * mnemonic resolves to `undefined` (the caller preserves the raw code and flags it — a URI is
267
+ * never invented). The full HL7 THO crosswalk is not bundled.
268
+ *
269
+ * @packageDocumentation
270
+ */
271
+
272
+ /**
273
+ * The HL7 v2 Table 0203 identifier-type code system canonical URI — used to build `Identifier.type`.
274
+ * (FHIR R4 terminologies-systems.html)
275
+ */
276
+ declare const V2_0203_SYSTEM = "http://terminology.hl7.org/CodeSystem/v2-0203";
277
+ /**
278
+ * A small, license-clean seed of v2 Table 0396 coding-system mnemonic → canonical URI, for the
279
+ * FHIR-core-fixed systems whose URIs are universally cited (FHIR R4 terminologies-systems.html).
280
+ * The full HL7 THO NamingSystem crosswalk is not bundled; callers extend this via
281
+ * {@link createNamingSystem}. **No terminology *content* is bundled — only identity URIs.**
282
+ */
283
+ declare const DEFAULT_V2_CODE_SYSTEMS: Readonly<Record<string, string>>;
284
+ /** A seed for {@link createNamingSystem}: extra coding systems and explicit assigning authorities. */
285
+ interface NamingSystemSeed {
286
+ /** Extra v2 coding-system mnemonic → canonical URI entries (merged over the defaults). */
287
+ readonly codeSystems?: Readonly<Record<string, string>>;
288
+ /**
289
+ * Explicit assigning-authority entries, keyed by **HD.1 namespace mnemonic** and/or **HD.2
290
+ * universal ID (OID)** → the `Identifier.system` URI. This is the safe, caller-vetted path the IG
291
+ * calls for; the registry never derives a system from a mnemonic on its own.
292
+ */
293
+ readonly authorities?: Readonly<Record<string, string>>;
294
+ }
295
+ /** The resolver consulted by the identity- and code-conversion paths. */
296
+ interface NamingSystemRegistry {
297
+ /**
298
+ * Resolve an assigning authority (HD) to a FHIR `Identifier.system` URI, or `undefined` when it
299
+ * cannot be resolved safely. **Never** synthesizes a URI from HD.1 alone.
300
+ */
301
+ readonly resolveAssigningAuthority: (hd: HD) => string | undefined;
302
+ /** Resolve a v2 coding-system mnemonic to a canonical URI, or `undefined` when unrecognized. */
303
+ readonly resolveCodeSystem: (mnemonic: string) => string | undefined;
304
+ }
305
+ /**
306
+ * Create a {@link NamingSystemRegistry}. With no seed it resolves the built-in FHIR-core code systems
307
+ * and the two unambiguous HD auto-derivations (OID/UUID); a seed adds caller-vetted code systems and
308
+ * explicit assigning-authority URIs.
309
+ *
310
+ * @example
311
+ * ```ts
312
+ * import { createNamingSystem } from "@cosyte/transform";
313
+ * const registry = createNamingSystem({
314
+ * authorities: { HOSPMRN: "urn:oid:1.2.840.114350.1.13.1" },
315
+ * });
316
+ * registry.resolveCodeSystem("LN"); // => "http://loinc.org"
317
+ * ```
318
+ */
319
+ declare function createNamingSystem(seed?: NamingSystemSeed): NamingSystemRegistry;
320
+
321
+ /**
322
+ * The options and context threaded through the datatype converters.
323
+ *
324
+ * These are **types only** — no runtime behavior. {@link TransformOptions} carries the policy knobs a
325
+ * caller can set; {@link TransformContext} additionally carries the
326
+ * {@link NamingSystemRegistry} the identity- and code-resolution paths consult.
327
+ *
328
+ * @packageDocumentation
329
+ */
330
+
331
+ /**
332
+ * Caller/profile policy for a conversion.
333
+ *
334
+ * @remarks
335
+ * `assumeTimezoneOffsetMinutes` is the **only** way a naked v2 timestamp acquires a time-of-day in
336
+ * FHIR: the caller asserts the sender's offset (in minutes east of UTC — e.g. `-300` for US Eastern
337
+ * standard time). It is a *sender-asserted* value, flagged as such; absent it, a naked timestamp is
338
+ * reduced to date precision, **never** assumed to be UTC.
339
+ */
340
+ interface TransformOptions {
341
+ /** The sender's UTC offset in minutes, asserted by the caller to resolve naked timestamps. */
342
+ readonly assumeTimezoneOffsetMinutes?: number;
343
+ /**
344
+ * The {@link NamingSystemRegistry} the message-level transform threads into every datatype
345
+ * conversion (HD → `Identifier.system`, v2 mnemonic → canonical URI). When omitted, a default
346
+ * registry (`createNamingSystem()`) is used — it resolves only the FHIR-core-fixed systems and the
347
+ * two unambiguous HD auto-derivations, so an un-seeded assigning authority surfaces a typed issue
348
+ * rather than a guessed system.
349
+ */
350
+ readonly namingSystem?: NamingSystemRegistry;
351
+ /**
352
+ * Allocator for the `urn:uuid:` `Bundle.entry.fullUrl` / reference identities the assembler mints.
353
+ * Defaults to `crypto.randomUUID`. Inject a deterministic generator to make bundle output
354
+ * reproducible (e.g. for golden fixtures). It must return a fresh, unique value per call — the
355
+ * assembler relies on uniqueness for intra-bundle reference integrity.
356
+ */
357
+ readonly generateId?: () => string;
358
+ }
359
+ /**
360
+ * The context a converter consults. Carries the {@link NamingSystemRegistry} used to resolve an
361
+ * assigning authority (HD) to an `Identifier.system` and a v2 coding-system mnemonic to a canonical
362
+ * URI, plus the {@link TransformOptions}.
363
+ */
364
+ interface TransformContext {
365
+ /** The registry used to resolve HD → system and v2 mnemonic → canonical URI. */
366
+ readonly namingSystem?: NamingSystemRegistry;
367
+ /** Conversion policy. */
368
+ readonly options?: TransformOptions;
369
+ }
370
+
371
+ /**
372
+ * DTM / TS → FHIR `dateTime` — the single most dangerous conversion.
373
+ *
374
+ * Grounded on the IG datatype ConceptMap **DTM → dateTime** (`DTM.1` *is equivalent to* the FHIR
375
+ * `dateTime.$value`, with the instruction to "convert v2 date time format to FHIR date time format")
376
+ * and the **FHIR core datatype rule** it defers to: *"if hours and minutes are specified, a timezone
377
+ * offset SHALL be populated"*, and the R4 `dateTime` grammar requires **full `hh:mm:ss` with an
378
+ * offset** whenever a time is present. Two fail-safe consequences follow:
379
+ *
380
+ * - **Naked timestamp (no offset).** A `20260721143000` cannot become a valid zoned FHIR `dateTime`
381
+ * without inventing an offset — assuming UTC would silently shift the clinical instant by hours. So
382
+ * the value is **reduced to date precision** (`2026-07-21`) and {@link ISSUE_CODES.TRANSFORM_TIMESTAMP_NO_TIMEZONE}
383
+ * is raised — unless the caller asserts the sender's offset via `options.assumeTimezoneOffsetMinutes`.
384
+ * - **Partial-precision time (hour/minute only).** FHIR cannot represent `hh` or `hh:mm` without
385
+ * seconds, and padding `:00` would fabricate precision, so such a value is likewise reduced to date
386
+ * precision and flagged — never padded.
387
+ *
388
+ * Date-only precisions (`2026`, `2026-07`, `2026-07-21`) are preserved exactly — never zero-filled —
389
+ * and need no offset (FHIR permits a bare date).
390
+ *
391
+ * @packageDocumentation
392
+ */
393
+
394
+ /**
395
+ * Convert a parsed HL7 v2 timestamp to a FHIR `dateTime` lexical string, fail-safe on timezone and
396
+ * precision. Returns `{ value: undefined }` only when the timestamp is unparseable.
397
+ *
398
+ * @param ts - A parsed `@cosyte/hl7` `TS` (`DtmParts`).
399
+ * @param options - Conversion policy; `assumeTimezoneOffsetMinutes` supplies a sender-asserted offset.
400
+ * @example
401
+ * ```ts
402
+ * import { parseDtm } from "@cosyte/hl7";
403
+ * import { toFhirDateTime } from "@cosyte/transform";
404
+ * const { value } = toFhirDateTime(parseDtm("20260721"));
405
+ * // value === "2026-07-21"
406
+ * void value;
407
+ * ```
408
+ */
409
+ declare function toFhirDateTime(ts: TS, options?: TransformOptions): ConvertResult<string>;
410
+
411
+ /**
412
+ * CX → FHIR `Identifier` — the patient-identity-integrity path.
413
+ *
414
+ * Grounded on the IG datatype ConceptMap **CX → Identifier**: `CX.1` → `Identifier.value`, `CX.4`
415
+ * (assigning authority HD) → `Identifier.system` *when the authority resolves in a registry* (else
416
+ * the IG maps it to `Identifier.assigner` — a message-level Organization reference this library does
417
+ * not build), and `CX.5` (Table 0203) → `Identifier.type`.
418
+ *
419
+ * The load-bearing fail-safe: the assigning authority is resolved through the
420
+ * {@link NamingSystemRegistry}, which **never synthesizes a system URI from HD.1 (the bare namespace)
421
+ * alone** — two hospitals reusing "MR"/"HOSPMRN" would otherwise collide and merge two patients. On
422
+ * an unresolved authority the identifier is emitted with its **value and no system**, plus a typed
423
+ * {@link ISSUE_CODES.TRANSFORM_IDENTIFIER_SYSTEM_UNRESOLVED} issue — never a guessed system.
424
+ *
425
+ * @packageDocumentation
426
+ */
427
+
428
+ /**
429
+ * Convert a parsed HL7 v2 CX to a FHIR `Identifier` node, fail-safe on the assigning authority.
430
+ * Returns `{ value: undefined }` when the CX carries no identifier value at all.
431
+ *
432
+ * @param cx - A parsed `@cosyte/hl7` `CX`.
433
+ * @param ctx - The transform context; `ctx.namingSystem` resolves the assigning authority (HD).
434
+ * @example
435
+ * ```ts
436
+ * import { toFhirIdentifier, createNamingSystem } from "@cosyte/transform";
437
+ * const { value, issues } = toFhirIdentifier(
438
+ * { idNumber: "12345", assigningAuthority: { namespaceId: "HOSPMRN" } },
439
+ * { namingSystem: createNamingSystem() },
440
+ * );
441
+ * // no registry entry for a bare "HOSPMRN" namespace → value emitted, system absent, one issue
442
+ * void value;
443
+ * void issues;
444
+ * ```
445
+ */
446
+ declare function toFhirIdentifier(cx: CX, ctx?: TransformContext): ConvertResult<FhirComplex>;
447
+
448
+ /**
449
+ * CWE / CE → FHIR `CodeableConcept` — the code-fidelity path.
450
+ *
451
+ * Grounded on the IG datatype ConceptMap **CWE → CodeableConcept**: `CWE.1`→`coding[0].code`,
452
+ * `CWE.2`→`coding[0].display`, `CWE.3`→`coding[0].system` **(indirect — the vocabulary table gives
453
+ * the actual URI)**, `CWE.7`→`coding[0].version`, the alternate triplet `CWE.4/5/6`→`coding[1]` (+
454
+ * `CWE.8`→`coding[1].version`), and `CWE.9`→`text`. `CE` is the 6-component subset of `CWE` and maps
455
+ * through the same shape.
456
+ *
457
+ * Two fail-safes, neither of which ever fabricates a code:
458
+ * - **Unrecognized coding-system mnemonic** (CWE.3/CWE.6) → the code is preserved with **no system**,
459
+ * flagged {@link ISSUE_CODES.TRANSFORM_CODE_SYSTEM_UNRESOLVED}. A canonical URI is never invented.
460
+ * - **A bare code with no coding system at all** (CWE.1 present, CWE.3 absent) → preserved verbatim,
461
+ * flagged {@link ISSUE_CODES.TRANSFORM_CODE_UNMAPPED}. Never coerced to a plausible neighbor.
462
+ *
463
+ * This converter does **no ConceptMap value translation** (that is
464
+ * `toFhirCodeableConceptVia`); it recognizes systems and preserves codes.
465
+ *
466
+ * @packageDocumentation
467
+ */
468
+
469
+ /** The subset of CWE fields a CE also provides — so `toFhirCodeableConcept` accepts both. */
470
+ type CodedElement = Pick<CWE, "identifier" | "text" | "nameOfCodingSystem" | "alternateIdentifier" | "alternateText" | "nameOfAlternateCodingSystem" | "codingSystemVersionId" | "alternateCodingSystemVersionId" | "originalText">;
471
+ /**
472
+ * Convert a parsed HL7 v2 CWE (or CE) to a FHIR `CodeableConcept` node, fail-safe on the coding
473
+ * system and on unmapped codes. Returns `{ value: undefined }` when the element is empty.
474
+ *
475
+ * @param cwe - A parsed `@cosyte/hl7` `CWE` (a `CE` is accepted as its subset).
476
+ * @param ctx - The transform context; `ctx.namingSystem` resolves the coding-system mnemonic.
477
+ * @example
478
+ * ```ts
479
+ * import { toFhirCodeableConcept, createNamingSystem } from "@cosyte/transform";
480
+ * const { value } = toFhirCodeableConcept(
481
+ * { identifier: "789-8", text: "Hemoglobin", nameOfCodingSystem: "LN" },
482
+ * { namingSystem: createNamingSystem() },
483
+ * );
484
+ * // coding[0] === { system: "http://loinc.org", code: "789-8", display: "Hemoglobin" }
485
+ * void value;
486
+ * ```
487
+ */
488
+ declare function toFhirCodeableConcept(cwe: CodedElement, ctx?: TransformContext): ConvertResult<FhirComplex>;
489
+
490
+ /**
491
+ * XPN → FHIR `HumanName`.
492
+ *
493
+ * Grounded on the IG datatype ConceptMap **XPN → HumanName**: `XPN.1`→`family`, `XPN.2`→`given[0]`,
494
+ * `XPN.3`→`given[1]`, `XPN.4`→`suffix`, `XPN.5`→`prefix`, `XPN.6` (degree)→`suffix`,
495
+ * `XPN.7`→`use` (via the IG **HL70200 → name-use** ConceptMap), `XPN.14` (professional suffix)→`suffix`.
496
+ *
497
+ * `XPN.7`→`use` is a **lossy code translation**: only the codes the IG's HL70200→name-use map covers
498
+ * are translated; any other name-type code leaves `use` **absent** and raises
499
+ * {@link ISSUE_CODES.TRANSFORM_NAME_USE_UNMAPPED} — never guessed. Not converted, and flagged:
500
+ * the name-validity period (`XPN.12`/`XPN.13`), whose FHIR `period` needs the timezone policy of the
501
+ * dateTime path.
502
+ *
503
+ * @packageDocumentation
504
+ */
505
+
506
+ /**
507
+ * HL7 v2 Table 0200 name-type code → FHIR `name-use`, exactly per the IG **HL70200 → name-use**
508
+ * ConceptMap (every row is "is equivalent to"). Codes absent here (A, B, C, F, I, K, NB, NOUSE, P,
509
+ * REL, S, T, U, …) have **no FHIR equivalent** and are surfaced, never guessed.
510
+ */
511
+ declare const NAME_USE_MAP: Readonly<Record<string, string>>;
512
+ /**
513
+ * Convert a parsed HL7 v2 XPN to a FHIR `HumanName` node. Returns `{ value: undefined }` when the
514
+ * name carries no emittable part.
515
+ *
516
+ * @param xpn - A parsed `@cosyte/hl7` `XPN`.
517
+ * @example
518
+ * ```ts
519
+ * import { toFhirHumanName } from "@cosyte/transform";
520
+ * const { value } = toFhirHumanName({ familyName: "Public", givenName: "Jane", nameTypeCode: "L" });
521
+ * // value === HumanName { use: "official", family: "Public", given: ["Jane"] }
522
+ * void value;
523
+ * ```
524
+ */
525
+ declare function toFhirHumanName(xpn: XPN): ConvertResult<FhirComplex>;
526
+
527
+ /**
528
+ * XAD → FHIR `Address`.
529
+ *
530
+ * Grounded on the IG datatype ConceptMap **XAD → Address**: `XAD.1`/`XAD.2`→`line`, `XAD.3`→`city`,
531
+ * `XAD.4`→`state`, `XAD.5`→`postalCode`, `XAD.6`→`country`, `XAD.9` (county/parish)→`district`, and
532
+ * the **value-conditional `XAD.7`** split across two independent FHIR axes:
533
+ * - `XAD.7 IN {BA, BI, C, B, H, O}` → `Address.use` (via the IG **HL70190 → address-use** map);
534
+ * - `XAD.7 IN {M, SH}` → `Address.type` (via the IG **HL70190 → address-type** map);
535
+ * - a vacation address (`V` in Table 0190; the datatype map references `HV`) → an ISO-21090 extension
536
+ * the IG defines — **not emitted**, and flagged rather than invented;
537
+ * - any other code → `use`/`type` left absent, flagged {@link ISSUE_CODES.TRANSFORM_ADDRESS_USE_UNMAPPED}.
538
+ *
539
+ * FHIR deliberately separates `use` (home/work/temp) from `type` (postal/physical), so one v2 code
540
+ * cannot always populate both axes — round-trip is not stable, and the drop is surfaced, never hidden.
541
+ * `XAD.8` (other geographic designation) has no FHIR target and is flagged dropped.
542
+ *
543
+ * @packageDocumentation
544
+ */
545
+
546
+ /** HL7 v2 Table 0190 address-type code → FHIR `address-use`, exactly per the IG HL70190→address-use map. */
547
+ declare const ADDRESS_USE_MAP: Readonly<Record<string, string>>;
548
+ /** HL7 v2 Table 0190 address-type code → FHIR `address-type`, exactly per the IG HL70190→address-type map. */
549
+ declare const ADDRESS_TYPE_MAP: Readonly<Record<string, string>>;
550
+ /**
551
+ * Convert a parsed HL7 v2 XAD to a FHIR `Address` node. Returns `{ value: undefined }` when the
552
+ * address carries no emittable part.
553
+ *
554
+ * @param xad - A parsed `@cosyte/hl7` `XAD`.
555
+ * @example
556
+ * ```ts
557
+ * import { toFhirAddress } from "@cosyte/transform";
558
+ * const { value } = toFhirAddress({ street: "1 Main St", city: "Boston", stateOrProvince: "MA", addressType: "H" });
559
+ * // value === Address { use: "home", line: ["1 Main St"], city: "Boston", state: "MA" }
560
+ * void value;
561
+ * ```
562
+ */
563
+ declare function toFhirAddress(xad: XAD): ConvertResult<FhirComplex>;
564
+
565
+ /**
566
+ * NM + units (CWE) → FHIR `Quantity`.
567
+ *
568
+ * Grounded on the IG datatype maps for OBX-5 (NM)→`Quantity.value` and OBX-6 (CWE units)→
569
+ * `Quantity.unit`/`.code`/`.system`. Two hard fail-safes:
570
+ *
571
+ * - **Never convert magnitudes.** The numeric value is carried through **precision-exact** via
572
+ * `@cosyte/fhir`'s string-backed `decimal` (a dose or lab value is never routed through a JS
573
+ * `number`). UCUM magnitude conversion (mg/dL ↔ mmol/L) is analyte-dependent and a
574
+ * clinical-safety footgun — an explicit non-goal, never a transform side effect.
575
+ * - **Never fabricate a UCUM code.** A unit is emitted into `Quantity.code`/`.system` **only** when
576
+ * it is declared UCUM and passes `@cosyte/fhir`'s UCUM shape check. Any other unit is preserved
577
+ * verbatim in `Quantity.unit` with `code`/`system` absent, flagged
578
+ * {@link ISSUE_CODES.TRANSFORM_UNIT_NOT_UCUM}.
579
+ *
580
+ * @packageDocumentation
581
+ */
582
+
583
+ /**
584
+ * Convert a parsed HL7 v2 numeric value plus its units to a FHIR `Quantity` node, fail-safe on the
585
+ * unit. Returns `{ value: undefined }` when the numeric magnitude is absent or non-numeric (a
586
+ * Quantity without a value cannot be safely emitted).
587
+ *
588
+ * @param value - A parsed `@cosyte/hl7` `NM` (its `.raw` carries the exact lexical value).
589
+ * @param units - The units component (an OBX-6 `CWE`); its CWE.1 is the candidate UCUM code.
590
+ * @param ctx - The transform context; used to recognize the UCUM coding system.
591
+ * @example
592
+ * ```ts
593
+ * import { toFhirQuantity } from "@cosyte/transform";
594
+ * const { value } = toFhirQuantity(
595
+ * { raw: "5.4", value: 5.4 },
596
+ * { identifier: "mg/dL", nameOfCodingSystem: "UCUM" },
597
+ * );
598
+ * // value === Quantity { value: 5.4, unit: "mg/dL", system: "http://unitsofmeasure.org", code: "mg/dL" }
599
+ * void value;
600
+ * ```
601
+ */
602
+ declare function toFhirQuantity(value: NM, units: CWE, ctx?: TransformContext): ConvertResult<FhirComplex>;
603
+
604
+ /**
605
+ * `toFhir` — the message-level entry point: assemble a parsed HL7 v2 message into a FHIR R4
606
+ * **message Bundle** (a `MessageHeader` first, then the focal resources), grounded on the IG message
607
+ * and segment maps. The **ADT** family becomes **Patient + Encounter** (+ `RelatedPerson`
608
+ * from NK1); the **ORU^R01** results graph becomes `DiagnosticReport` + `Observation`; the
609
+ * order-entry graph — **ORM_O01 / OML_O21** ORC/OBR → `ServiceRequest` and **RXO** (+ RXR) →
610
+ * `MedicationRequest`; and the thin IG singles — **VXU_V04** RXA/RXR/ORC → `Immunization`,
611
+ * **SIU_S12** SCH/AIS/PID → `Appointment`, and **MDM_T02** TXA/OBX → `DocumentReference`.
612
+ *
613
+ * The fail-safe rule holds at the message level. Two message-level fail-safes join the datatype ones:
614
+ *
615
+ * - **Segment-assembled, not fabricated.** For an ADT trigger the IG maps ({@link IG_MAPPED_ADT_TRIGGERS}),
616
+ * the graph is message-map-grounded. For any other trigger there is no IG *message* map, so the
617
+ * graph is assembled from the reusable IG *segment* maps and flagged
618
+ * {@link ISSUE_CODES.TRANSFORM_SEGMENT_ASSEMBLED} — never a fabricated message map.
619
+ * - **Conservative emit gate.** Every produced resource is run through `@cosyte/fhir.validateResource`
620
+ * before it can join the bundle — `Patient` against the built-in schema in `strict` mode, and the
621
+ * other types against the minimal required-cardinality {@link EMIT_SCHEMAS} in `lenient` mode (so a
622
+ * missing required element errors and withholds, while unmodeled sibling elements do not
623
+ * false-reject). A resource with any structural error is **withheld** from the bundle and flagged
624
+ * {@link ISSUE_CODES.TRANSFORM_RESOURCE_INVALID} rather than shipped as silently-invalid FHIR. When
625
+ * the Patient is withheld, the Encounter's `subject` and any RelatedPerson are dropped rather than
626
+ * left dangling — references always resolve within the bundle.
627
+ *
628
+ * @packageDocumentation
629
+ */
630
+
631
+ /**
632
+ * The immutable result of a message-level transform: the FHIR `Bundle` model and the value-free
633
+ * diagnostics raised assembling it.
634
+ */
635
+ interface TransformResult {
636
+ /** The FHIR R4 `Bundle` resource node (a message Bundle: MessageHeader first, then focal resources). */
637
+ readonly bundle: FhirComplex;
638
+ /** The value-free diagnostics raised during assembly, in emission order. */
639
+ readonly issues: readonly TransformIssue[];
640
+ }
641
+ /**
642
+ * The ADT trigger events the IG ships a **message** map for. Other triggers still transform — from the
643
+ * reusable segment maps — but are flagged {@link ISSUE_CODES.TRANSFORM_SEGMENT_ASSEMBLED}.
644
+ */
645
+ declare const IG_MAPPED_ADT_TRIGGERS: ReadonlySet<string>;
646
+ /**
647
+ * The ORU trigger events the IG ships a **message** map for. The IG maps only `R01`; other ORU triggers
648
+ * still assemble their results graph from the reusable OBR/OBX segment maps but are flagged
649
+ * {@link ISSUE_CODES.TRANSFORM_SEGMENT_ASSEMBLED}.
650
+ */
651
+ declare const IG_MAPPED_ORU_TRIGGERS: ReadonlySet<string>;
652
+ /**
653
+ * The order-message trigger events the IG ships a **message** map for, keyed `CODE^TRIGGER`. Only
654
+ * `ORM^O01` and `OML^O21` are message-map-grounded; other order families (`OMP`, `OMG`, `RDE`, …)
655
+ * still assemble their request graph from the reusable ORC/OBR/RXO/RXR segment maps but are flagged
656
+ * {@link ISSUE_CODES.TRANSFORM_SEGMENT_ASSEMBLED}.
657
+ */
658
+ declare const IG_MAPPED_ORDER_TRIGGERS: ReadonlySet<string>;
659
+ /**
660
+ * The immunization trigger the IG ships a **message** map for. The IG maps only `VXU^V04`; other VXU
661
+ * triggers still assemble their Immunization graph from the reusable RXA/RXR/ORC segment maps but are
662
+ * flagged {@link ISSUE_CODES.TRANSFORM_SEGMENT_ASSEMBLED}.
663
+ */
664
+ declare const IG_MAPPED_IMMUNIZATION_TRIGGERS: ReadonlySet<string>;
665
+ /**
666
+ * The scheduling trigger the IG ships a **message** map for. The IG maps only `SIU^S12`; other SIU
667
+ * triggers still assemble their Appointment from the reusable SCH/AIS/PID segment maps but are flagged
668
+ * {@link ISSUE_CODES.TRANSFORM_SEGMENT_ASSEMBLED}.
669
+ */
670
+ declare const IG_MAPPED_APPOINTMENT_TRIGGERS: ReadonlySet<string>;
671
+ /**
672
+ * The medical-document trigger the IG ships a **message** map for. The IG maps only `MDM^T02`; other MDM
673
+ * triggers still assemble their DocumentReference from the reusable TXA/OBX segment maps but are flagged
674
+ * {@link ISSUE_CODES.TRANSFORM_SEGMENT_ASSEMBLED}.
675
+ */
676
+ declare const IG_MAPPED_DOCUMENT_TRIGGERS: ReadonlySet<string>;
677
+ /**
678
+ * Transform a parsed HL7 v2 message into a FHIR R4 message `Bundle`. Never throws for a well-formed
679
+ * {@link Hl7Message}; every ambiguity, unmapped code, dropped element, or withheld resource surfaces
680
+ * as a value-free {@link TransformIssue}.
681
+ *
682
+ * @param msg - A parsed `@cosyte/hl7` message.
683
+ * @param opts - Transform options: the {@link TransformOptions.namingSystem} registry, the naked-
684
+ * timestamp {@link TransformOptions.assumeTimezoneOffsetMinutes} policy, and a
685
+ * {@link TransformOptions.generateId} allocator for reproducible fullUrls.
686
+ * @example
687
+ * ```ts
688
+ * import { parseHL7 } from "@cosyte/hl7";
689
+ * import { toFhir, createNamingSystem } from "@cosyte/transform";
690
+ * const { bundle, issues } = toFhir(parseHL7(raw), { namingSystem: createNamingSystem() });
691
+ * void bundle;
692
+ * void issues;
693
+ * ```
694
+ */
695
+ declare function toFhir(msg: Hl7Message, opts?: TransformOptions): TransformResult;
696
+
697
+ /**
698
+ * PID → FHIR `Patient` — grounded on the IG **Segment PID to Patient** ConceptMap
699
+ * (`hl7.fhir.uv.v2mappings`, STU1). The field→element rows used here, verified firsthand against the
700
+ * published map:
701
+ *
702
+ * | PID field | FHIR target | via |
703
+ * |---|---|---|
704
+ * | PID-3 Patient Identifier List (CX) | `Patient.identifier` | {@link toFhirIdentifier} |
705
+ * | PID-5 Patient Name (XPN) | `Patient.name` | {@link toFhirHumanName} |
706
+ * | PID-7 Date/Time of Birth (DTM) | `Patient.birthDate` | {@link toFhirDateTime} reduced to a `date` |
707
+ * | PID-8 Administrative Sex (CWE) | `Patient.gender` | {@link ADMINISTRATIVE_GENDER_MAP} (Table 0001) |
708
+ * | PID-11 Patient Address (XAD) | `Patient.address` | {@link toFhirAddress} |
709
+ *
710
+ * Fail-safe throughout: each datatype conversion carries its own value-free issues, an unmapped
711
+ * administrative-sex code leaves `gender` absent (never guessed), and a birth *time* (PID-7 with a
712
+ * time-of-day) is dropped to `date` precision with a flag — the US Core `patient-birthTime` extension
713
+ * is a profile concern this library does not cover. Deferred and flagged, not silently mapped:
714
+ * PID-13/14 telecom (no XTN→ContactPoint converter), and PID-10/15/22/29/30 (US Core race/ethnicity
715
+ * extensions, communication language, deceased).
716
+ *
717
+ * @packageDocumentation
718
+ */
719
+
720
+ /**
721
+ * HL7 v2 Table 0001 (Administrative Sex) → FHIR `administrative-gender`, exactly per the IG
722
+ * **Table HL70001 to Administrative Gender** ConceptMap (every row "is equivalent to"). `A`
723
+ * (Ambiguous) and `N` (Not applicable) both narrow to `other` — the map's stated equivalence, carried
724
+ * as-is. A code absent here (the map defines no `unmapped` default) leaves `gender` absent and is
725
+ * flagged {@link ISSUE_CODES.TRANSFORM_CODE_UNMAPPED} — never coerced to `unknown`.
726
+ */
727
+ declare const ADMINISTRATIVE_GENDER_MAP: Readonly<Record<string, string>>;
728
+
729
+ /**
730
+ * PV1 → FHIR `Encounter` — grounded on the IG **Segment PV1 to Encounter** ConceptMap plus the two
731
+ * **Table HL70004** ConceptMaps (to V3 ActCode, and to Encounter Status), all verified firsthand
732
+ * against the published `hl7.fhir.uv.v2mappings` STU1 maps:
733
+ *
734
+ * | PV1 field | FHIR target | condition / via |
735
+ * |---|---|---|
736
+ * | PV1-2 Patient Class | `Encounter.class` (Coding) | Table 0004 → V3 ActCode ({@link ENCOUNTER_CLASS_V3_MAP}); the self-mapped classes stay in v2-0004 |
737
+ * | PV1-2 Patient Class | `Encounter.status` (code) | Table 0004 → Encounter Status ({@link ENCOUNTER_STATUS_MAP}), *only IF PV1-45 not valued* |
738
+ * | PV1-19 Visit Number | `Encounter.identifier` (type `VN`) | v2-0203 identifier-type system |
739
+ * | PV1-44 Admit Date/Time | `Encounter.period.start` | {@link toFhirDateTime} |
740
+ * | PV1-45 Discharge Date/Time | `Encounter.period.end` + `status = finished` | {@link toFhirDateTime} |
741
+ *
742
+ * Fail-safe: an unmapped patient class leaves `Encounter.class` absent and flags
743
+ * {@link ISSUE_CODES.TRANSFORM_CODE_UNMAPPED} (never coerced); `Encounter.subject` is wired to the
744
+ * bundle's Patient (the identity anchor) and omitted only when no valid Patient was produced.
745
+ * Deferred and flagged, not silently mapped: PV1-3 location (Reference(Location), no Location resource
746
+ * is built), PV1-7/8 attending/referring doctor (Reference(Practitioner), no Practitioner resource
747
+ * is built).
748
+ *
749
+ * @packageDocumentation
750
+ */
751
+
752
+ /**
753
+ * HL7 v2 Table 0004 (Patient Class) → FHIR v3 ActCode (`Encounter.class`), per the IG **Table HL70004
754
+ * to V3 ActCode** ConceptMap (each "is equivalent to"). Only these four v2 classes have a v3 ActCode
755
+ * equivalent; the remaining classes (R/B/C/N/U) map to themselves and stay in the v2-0004 system
756
+ * ({@link V2_0004_SYSTEM}) per the same map's V2→V2 rows.
757
+ */
758
+ declare const ENCOUNTER_CLASS_V3_MAP: Readonly<Record<string, {
759
+ code: string;
760
+ display: string;
761
+ }>>;
762
+ /**
763
+ * HL7 v2 Table 0004 (Patient Class) → FHIR `Encounter.status`, per the IG **Table HL70004 to
764
+ * Encounter Status** ConceptMap. Applied only when PV1-45 (discharge date) is *not* valued — a valued
765
+ * discharge sets `status = finished` per the PV1→Encounter map.
766
+ */
767
+ declare const ENCOUNTER_STATUS_MAP: Readonly<Record<string, string>>;
768
+
769
+ /**
770
+ * OBX → FHIR `Observation` — the highest-clinical-stakes segment map,
771
+ * grounded firsthand on the IG **Segment OBX to Observation** ConceptMap plus its two governing table
772
+ * ConceptMaps (`hl7.fhir.uv.v2mappings`, STU1). The rows used here, verified against the published maps
773
+ * (`ConceptMap-segment-obx-to-observation.html`, `-table-hl70078-to-v3-observationinterpretation.html`,
774
+ * `-table-hl70085-to-observation-status.html`):
775
+ *
776
+ * | OBX field | FHIR target | via |
777
+ * |---|---|---|
778
+ * | OBX-2 Value Type | discriminates OBX-5 → `value[x]` | {@link buildValue} — never assume `Quantity` |
779
+ * | OBX-3 Observation Identifier (CWE) | `Observation.code` | {@link toFhirCodeableConcept} |
780
+ * | OBX-5 Observation Value | `Observation.value[x]` | per OBX-2 |
781
+ * | OBX-6 Units (CWE) | `valueQuantity.unit`/`.code`/`.system` | {@link quantityFromRawMagnitude} |
782
+ * | OBX-7 Reference Range | `Observation.referenceRange.text` | mapped to `.text` (never decomposed) |
783
+ * | OBX-8 Abnormal Flags | `Observation.interpretation` | {@link HL70078_INTERPRETATION_CODES} |
784
+ * | OBX-11 Result Status | `Observation.status` | {@link OBSERVATION_STATUS_MAP} (HL70085) |
785
+ * | OBX-14 Date/Time of Observation | `Observation.effectiveDateTime` | {@link toFhirDateTime} |
786
+ *
787
+ * **The "never a confident wrong result" fail-safes:**
788
+ * - **OBX-2 drives `value[x]`.** `NM`→`valueQuantity`, `CWE`/`CE`/`CF`/`CNE`/`IS`→`valueCodeableConcept`,
789
+ * `SN`→structured (`valueQuantity` with a comparator / `valueRange` / `valueRatio`), `ST`/`TX`/`FT`→
790
+ * `valueString`. A value type with no first-class target here (`NA`, `ED`, `DR`, `TM`, `NR`, unknown)
791
+ * preserves the raw value as `valueString` and flags {@link ISSUE_CODES.TRANSFORM_ELEMENT_DROPPED}
792
+ * (the richer FHIR type is deferred) — never a fabricated `Quantity`.
793
+ * - **A corrected/cancelled result never emits as `final`.** OBX-11 `C`→`corrected`, `X`→`cancelled`,
794
+ * `D`/`W`→`entered-in-error` (HL70085). A status code with **no** HL70085 target leaves
795
+ * `Observation.status` absent (flagged {@link ISSUE_CODES.TRANSFORM_CODE_UNMAPPED}); the required-`status`
796
+ * emit gate then **withholds** the Observation rather than shipping it — never coerced to `final`.
797
+ * - **An unrecognized abnormal flag is surfaced, never coerced to normal.** Each OBX-8 flag in
798
+ * {@link HL70078_INTERPRETATION_CODES} becomes an `interpretation` coding (the map is code-preserving);
799
+ * a flag absent from the table is flagged and dropped, never emitted as `N`/normal.
800
+ *
801
+ * Numeric magnitudes (NM, SN) are read from the **raw OBX-5 field** — not the `@cosyte/hl7`
802
+ * `Observation` view's JS `number` — so a reported lab value's exact lexical precision (`120.50`) is
803
+ * carried through the string-backed FHIR `decimal`, never routed through a lossy `number`.
804
+ *
805
+ * @packageDocumentation
806
+ */
807
+
808
+ /**
809
+ * HL7 v2 Table 0078 (Abnormal Flags) → FHIR v3 ObservationInterpretation (`Observation.interpretation`),
810
+ * per the IG **Table HL70078 to v3 ObservationInterpretation** ConceptMap. Every mapped row is
811
+ * `is equivalent to` an **identically-spelled** v3 code (the map is code-preserving), so this is the set
812
+ * of codes that carry a target — a flag **absent** from this set has no equivalent and is flagged
813
+ * {@link ISSUE_CODES.TRANSFORM_CODE_UNMAPPED}, never coerced (the IG leaves `AC`/`HM`/`OBX`/`QCF`/`TOX`
814
+ * and any local flag unmapped, and declares no `unmapped` default).
815
+ */
816
+ declare const HL70078_INTERPRETATION_CODES: ReadonlySet<string>;
817
+ /**
818
+ * HL7 v2 Table 0085 (Observation Result Status) → FHIR `observation-status` (`Observation.status`),
819
+ * per the IG **Table HL70085 to Observation Status** ConceptMap (each `is equivalent to`). Only these
820
+ * seven source codes carry a target; the codes the IG leaves unmapped (`B`, `I`, `N`, `O`, `R`, `S`,
821
+ * `U`, `V`) are **absent here on purpose** — an OBX-11 with one of them (or any local code) leaves
822
+ * `Observation.status` absent + flagged, and the required-`status` emit gate withholds the Observation.
823
+ * **`C`→`corrected` and `X`→`cancelled` guarantee a corrected/cancelled result never emits as `final`.**
824
+ */
825
+ declare const OBSERVATION_STATUS_MAP: Readonly<Record<string, string>>;
826
+
827
+ /**
828
+ * OBR → FHIR `DiagnosticReport` — the ORU results-report anchor, grounded firsthand
829
+ * on the IG **Segment OBR to DiagnosticReport** ConceptMap and its **Table HL70123 to Diagnostic Report
830
+ * Status** ConceptMap (`hl7.fhir.uv.v2mappings`, STU1;
831
+ * `ConceptMap-segment-obr-to-diagnosticreport.html`,
832
+ * `ConceptMap-table-hl70123-queries-to-diagnostic-report-status.html`):
833
+ *
834
+ * | OBR field | FHIR target | via |
835
+ * |---|---|---|
836
+ * | OBR-2 Placer Order Number | `identifier` (type `PLAC`) | EI.1 → `Identifier.value`, v2-0203 type |
837
+ * | OBR-3 Filler Order Number | `identifier` (type `FILL`) | EI.1 → `Identifier.value`, v2-0203 type |
838
+ * | OBR-4 Universal Service Identifier (CWE) | `DiagnosticReport.code` | {@link toFhirCodeableConcept} |
839
+ * | OBR-7 Observation Date/Time | `effectiveDateTime` / `effectivePeriod.start` | {@link toFhirDateTime} |
840
+ * | OBR-8 Observation End Date/Time | `effectivePeriod.end` (start moves to the period when valued) | — |
841
+ * | OBR-22 Results Rpt/Status Chng Date/Time | `DiagnosticReport.issued` (an `instant`) | {@link toFhirDateTime} |
842
+ * | OBR-24 Diagnostic Serv Sect ID | `DiagnosticReport.category` | v2-0074 coding |
843
+ * | OBR-25 Result Status | `DiagnosticReport.status` | {@link DIAGNOSTIC_REPORT_STATUS_MAP} (HL70123) |
844
+ * | (OBX children) | `DiagnosticReport.result` | reference wiring from the assembler |
845
+ *
846
+ * **Fail-safes.** `DiagnosticReport.status` is required (R4 1..1) and the IG itself notes an unvalued
847
+ * OBR-25 is an error; so an absent OBR-25 — or an OBR-25 code the HL70123 map does not carry (`A`, `M`,
848
+ * `N`, `Y`, `Z`) — leaves `status` absent + flagged {@link ISSUE_CODES.TRANSFORM_CODE_UNMAPPED}, and the
849
+ * required-`status` emit gate withholds the report rather than emitting an invalid one or guessing
850
+ * `final`. `OBR-25 = C`→`corrected` / `X`→`cancelled` are modelled exactly. OBR-22 becomes `issued`
851
+ * only when it is a fully-zoned instant; a date-only/naked OBR-22 is dropped + flagged (never a
852
+ * fabricated UTC), mirroring `Bundle.timestamp`. Deferred and flagged elsewhere, not silently mapped:
853
+ * OBR-32/34/35 performers (need PractitionerRole resources), specimen, and `basedOn` ServiceRequest.
854
+ *
855
+ * @packageDocumentation
856
+ */
857
+
858
+ /**
859
+ * HL7 v2 Table 0123 (Result Status) → FHIR `diagnostic-report-status` (`DiagnosticReport.status`), per
860
+ * the IG **Table HL70123 [Queries] to Diagnostic Report Status** ConceptMap (each `is equivalent to`).
861
+ * Only these **eight** source codes carry a target; the IG leaves `A`, `M`, `N`, `Y`, `Z` unmapped
862
+ * (verified firsthand against the published v1.0.0 ConceptMap — `N` "Procedure completed, results
863
+ * pending" is in the `(not mapped)` group, and the map declares no `unmapped` default), so an OBR-25
864
+ * with one of them leaves `status` absent + flagged and the report is withheld. In particular a
865
+ * results-**pending** `N` is **never** emitted as the post-final `appended`. **`C`→`corrected` and
866
+ * `X`→`cancelled` guarantee a corrected/cancelled report never emits as `final`.**
867
+ */
868
+ declare const DIAGNOSTIC_REPORT_STATUS_MAP: Readonly<Record<string, string>>;
869
+
870
+ /**
871
+ * ORC + OBR → FHIR `ServiceRequest` — the order-entry request, grounded firsthand
872
+ * on the IG **Segment ORC to ServiceRequest** and **Segment OBR to ServiceRequest** ConceptMaps and
873
+ * the **Table HL70119 to Request Status** ConceptMap (`hl7.fhir.uv.v2mappings`, STU1;
874
+ * `ConceptMap-segment-orc-to-servicerequest.html`, `ConceptMap-segment-obr-to-servicerequest.html`,
875
+ * `ConceptMap-table-hl70119-to-request-status.html`). Per the **ORM_O01 / OML_O21 message maps**,
876
+ * `ORC` *creates* the `ServiceRequest` and `OBR` is *incorporated into that same* request, so one
877
+ * builder consumes both:
878
+ *
879
+ * | v2 field | FHIR target | via |
880
+ * |---|---|---|
881
+ * | ORC-1 Order Control | `ServiceRequest.status` | {@link REQUEST_STATUS_MAP} (HL70119), *only IF ORC-5 not valued* |
882
+ * | ORC-2 / OBR-2 Placer Order Number | `identifier` (type `PLAC`) | {@link orderIdentifier} (EI.1, v2-0203) |
883
+ * | ORC-3 / OBR-3 Filler Order Number | `identifier` (type `FILL`) | {@link orderIdentifier} |
884
+ * | ORC-9 Date/Time of Order Event | `authoredOn` | {@link toFhirDateTime}, *IF ORC-1 = `NW`* |
885
+ * | OBR-4 Universal Service Identifier (CWE) | `ServiceRequest.code` | {@link toFhirCodeableConcept} |
886
+ * | OBR-5 Priority (v2-0485) | `ServiceRequest.priority` | {@link SERVICE_REQUEST_PRIORITY_MAP} (HL70485) |
887
+ * | OBR-6 Requested Date/Time | `occurrenceDateTime` | {@link toFhirDateTime} |
888
+ * | OBR-31 Reason for Study (CWE) | `reasonCode` | {@link toFhirCodeableConcept} |
889
+ * | (order message context) | `intent` = `order` | see below |
890
+ * | (message-map wiring) | `subject` / `encounter` | the bundle's Patient / Encounter |
891
+ *
892
+ * **Fail-safes (never a confident wrong request).**
893
+ * - **`status` (required 1..1).** ORC-1 → HL70119 carries a target for only the 19 codes in
894
+ * {@link REQUEST_STATUS_MAP}; the many codes the IG leaves in its `(unmapped)` group (CH, CP, PA,
895
+ * RE, RF, RP, SC, the U* "unable to …" family, …) have **no** target and leave `status` absent +
896
+ * flagged {@link ISSUE_CODES.TRANSFORM_CODE_UNMAPPED}. When **ORC-5** (Order Status) is valued the
897
+ * IG routes status through ORC-5 via an *unspecified* mapping (no code table) — so we cannot derive
898
+ * it, flag ORC-5 unmapped, and leave `status` absent rather than mis-applying the ORC-1 table
899
+ * against the IG's own condition. The required-`status` emit gate then **withholds** the request —
900
+ * never guessed, never coerced.
901
+ * - **`intent` (required 1..1) = `order`.** The IG maps ORC-1/OBR → `intent` as `equivalent` but ships
902
+ * **no value ConceptMap** for it; the ORM_O01/OML_O21 families are, by definition, *order* messages
903
+ * (their message maps create a `ServiceRequest`/`MedicationRequest` per order), so `intent` is fixed
904
+ * to the `request-intent` code `order` from that message context. This is a resource-level constant
905
+ * grounded in the message family — **not** a fabricated per-code translation row. The finer
906
+ * OBR-11-conditioned intent refinement is deferred.
907
+ * - **`subject` (required 1..1).** Wired to the bundle's Patient; a request with no resolvable Patient
908
+ * is withheld rather than emitted with a dangling/absent subject.
909
+ *
910
+ * - **`priority` (0..1) — value-translated.** OBR-5 → `ServiceRequest.priority` via the IG
911
+ * **Table HL70485 to Request Priority** ConceptMap ({@link SERVICE_REQUEST_PRIORITY_MAP}): only
912
+ * `S→stat`, `A→asap`, `R→routine` carry a target (each `equivalent`, and all three are valid
913
+ * `request-priority` members). Every other v2-0485 code — `P`, `C`, `T`, the `T{S,M,H,D,W,L}<integer>`
914
+ * timing-critical family, `PRN` — sits in the IG map's `(unmapped)` group, so a valued OBR-5 the map
915
+ * has no target for leaves `priority` absent + flagged {@link ISSUE_CODES.TRANSFORM_CODE_UNMAPPED},
916
+ * never guessed. (`priority` is 0..1, so an unmapped value simply omits it — the request still emits.)
917
+ *
918
+ * Deferred and flagged elsewhere, not silently mapped: ORC-7/OBR-27 timing (`$this`), ORC-12/OBR-16
919
+ * requester + ORC-21..24 ordering facility/provider (need Practitioner/PractitionerRole/Organization
920
+ * resources), OBR-29 basedOn, specimen, and the ORC-1/ORC-9/OBR-13 order-control/supporting-info
921
+ * extensions.
922
+ *
923
+ * @packageDocumentation
924
+ */
925
+
926
+ /**
927
+ * HL7 v2 Table 0119 (Order Control Codes) → FHIR `request-status` (`ServiceRequest.status`), per the
928
+ * IG **Table HL70119 to Request Status** ConceptMap (each `is equivalent to`). Only these **19** source
929
+ * codes carry a target; every other v2-0119 code sits in the IG's explicit `(unmapped)` group
930
+ * (verified firsthand against the published v1.0.0 ConceptMap — CH/CN/CP/DE/LI/NA/OE/OF/OP/OR/PA/RE/
931
+ * RF/RP/RR/RU/SC/SN/SR/SS/UA/UC/UD/UF/UH/UM/UN/UR/UX/XO/XR/XX/MC are all `unmatched`, and the map
932
+ * declares no `unmapped` default), so an ORC-1 with one of them leaves `status` absent + flagged and
933
+ * the request is withheld. `request-status` has no `cancelled`; the cancel/discontinue codes map to
934
+ * `revoked` and the hold codes to `on-hold`, exactly as the IG table specifies.
935
+ */
936
+ declare const REQUEST_STATUS_MAP: Readonly<Record<string, string>>;
937
+ /**
938
+ * HL7 v2 Table 0485 (Extended Priority Codes) → FHIR `request-priority` (`ServiceRequest.priority`),
939
+ * per the IG **Table HL70485 to Request Priority** ConceptMap (each `is equivalent to`; verified
940
+ * firsthand against the published v1.0.0 ConceptMap). Only these **three** source codes carry a
941
+ * target; every other v2-0485 code — `P` (Preop), `C` (Callback), `T` (Timing critical), the
942
+ * `T{S,M,H,D,W,L}<integer>` timing-critical family, and `PRN` (As needed) — sits in the IG's
943
+ * `(unmapped)` group with no target, so an OBR-5 carrying one leaves `priority` absent + flagged.
944
+ * All three targets (`stat`/`asap`/`routine`) are valid `request-priority` members.
945
+ */
946
+ declare const SERVICE_REQUEST_PRIORITY_MAP: Readonly<Record<string, string>>;
947
+
948
+ /**
949
+ * VXU_V04 → FHIR `Immunization` — the thin IG single for immunization administration,
950
+ * grounded firsthand on the IG **VXU_V04 message map** and the **RXA/RXR/ORC → Immunization**
951
+ * segment maps (`hl7.fhir.uv.v2mappings`, STU1; `ConceptMap-message-vxu-v04-to-bundle.json`,
952
+ * `ConceptMap-segment-rxa-to-immunization.json`, `ConceptMap-segment-rxr-to-immunization.json`,
953
+ * `ConceptMap-segment-orc-to-immunization.json`). Per the VXU message map, **each `ORC` creates an
954
+ * `Immunization`** and the `RXA` (+ `RXR` route) in the same order group are *incorporated into it*, so
955
+ * one builder consumes all three; the order-group `OBX`s become standalone patient `Observation`s
956
+ * (`Observation[2]` in the IG bundle), handled by the assembler.
957
+ *
958
+ * | v2 field | FHIR target | via |
959
+ * |---|---|---|
960
+ * | RXA-5 Administered Code (CE) | `vaccineCode` (required 1..1) | {@link toFhirCodeableConcept} (structural — no IG value map) |
961
+ * | RXA-3 Date/Time Start of Administration (DTM) | `occurrenceDateTime` (required, occurrence[x]) | {@link toFhirDateTime} |
962
+ * | RXA-20 Completion Status + RXA-21 Action Code | `status` (required 1..1) | {@link buildStatus} (HL70322 + IG assignments) |
963
+ * | RXA-6 Administered Amount + RXA-7 Units | `doseQuantity` | {@link quantityFromRawMagnitude} |
964
+ * | RXA-15 Substance Lot Number (ST) | `lotNumber` | verbatim |
965
+ * | RXA-16 Substance Expiration Date (DT) | `expirationDate` (a `date`) | {@link toFhirDateTime}, date-only |
966
+ * | RXA-18 Substance/Treatment Refusal Reason (CWE) | `statusReason` | {@link toFhirCodeableConcept} |
967
+ * | RXA-19 Indication (CWE) | `reasonCode` | {@link toFhirCodeableConcept} |
968
+ * | RXA-22 System Entry Date/Time (DTM) | `recorded` | {@link toFhirDateTime} (ORC-9 fallback) |
969
+ * | RXR-1 Route (CWE) | `route` | {@link ROUTE_VALUE_MAP} (HL70162, value-translated) |
970
+ * | RXR-2 Administration Site (CWE) | `site` | {@link SITE_VALUE_MAP} (HL70550, value-translated) |
971
+ * | ORC-2 / ORC-3 Placer/Filler Order Number | `identifier` (PLAC / FILL) | {@link orderIdentifier} |
972
+ * | ORC-9 Date/Time of Order Event | `recorded` (fallback) | {@link toFhirDateTime} |
973
+ * | (message-map wiring) | `patient` (required 1..1) / `encounter` | the bundle's Patient / Encounter |
974
+ *
975
+ * **Fail-safes (never a confident wrong immunization record).**
976
+ * - **`status` (required 1..1).** The IG ships **three conditioned status rows** (verified firsthand
977
+ * against `ConceptMap-segment-rxa-to-immunization.json`): **RXA-21 = "D"** (delete) → the IG-assigned
978
+ * `entered-in-error`; **RXA-20 not valued and RXA-21 ≠ "D"** → the IG-assigned `completed`; **RXA-20
979
+ * valued and RXA-21 ≠ "D"** → translated via {@link IMMUNIZATION_STATUS_MAP} (the HL70322 →
980
+ * event-status ConceptMap, whose targets `completed`/`not-done` are all valid `immunization-status`
981
+ * members). A **valued** RXA-20 the HL70322 map has no target for is flagged
982
+ * {@link ISSUE_CODES.TRANSFORM_CODE_UNMAPPED}, `status` left absent, and the required-`status` emit gate
983
+ * **withholds** the Immunization — never guessed, never coerced.
984
+ * - **`vaccineCode` (required 1..1) + `occurrence[x]` (required 1..1) + `patient` (required 1..1).** An
985
+ * absent RXA-5, RXA-3, or bundle Patient leaves the resource missing a required element, so it is
986
+ * withheld by the emit gate rather than emitted incomplete.
987
+ * - **Dose.** RXA-6/RXA-7 → `doseQuantity` via {@link quantityFromRawMagnitude}: precision-exact magnitude,
988
+ * non-UCUM unit preserved verbatim with `.code`/`.system` absent + flagged — never a fabricated UCUM code.
989
+ * - **Route/site value translation.** RXR-1 route → {@link ROUTE_VALUE_MAP} (HL70162) and
990
+ * RXR-2 site → {@link SITE_VALUE_MAP} (HL70550) are value-translated additively (derived target coding
991
+ * added, raw coding preserved); a code outside the table is preserved + flagged, never coerced.
992
+ * - **`vaccineCode` is NOT value-translated — by grounding, not omission.** RXA-5 has **no** `mappedVia`
993
+ * value ConceptMap in the IG's RXA→Immunization segment map (verified firsthand), so the code (typically
994
+ * CVX) is carried **structurally** (system recognized, value preserved) — a translation is never
995
+ * invented for it.
996
+ *
997
+ * Deferred and flagged elsewhere, not silently mapped: RXA-10 performer, RXA-17 manufacturer, RXA-27/28
998
+ * location, ORC-12 performer (all need Practitioner/Organization/Location resources this library does not
999
+ * build).
1000
+ *
1001
+ * @packageDocumentation
1002
+ */
1003
+
1004
+ /**
1005
+ * HL7 v2 Table 0322 (Completion Status) → FHIR `Immunization.status`, per the IG **Table HL70322 to
1006
+ * Event Status** ConceptMap (each `is equivalent to`). Table 0322 has exactly these **four** source
1007
+ * codes and every one carries a target; the two distinct targets (`completed`, `not-done`) are both
1008
+ * valid members of the `immunization-status` required binding, so applying this map to
1009
+ * `Immunization.status` is faithful. Consulted only for a **valued** RXA-20 when **RXA-21 ≠ "D"** (the
1010
+ * IG's `mappedVia` condition on that row); the two other IG status rows assign fixed values directly (a
1011
+ * delete → `entered-in-error`, an unvalued RXA-20 → `completed`) and do not consult this map. See
1012
+ * {@link buildStatus}.
1013
+ */
1014
+ declare const IMMUNIZATION_STATUS_MAP: Readonly<Record<string, string>>;
1015
+
1016
+ /**
1017
+ * SIU_S12 → FHIR `Appointment` — the thin IG single for scheduling, grounded
1018
+ * firsthand on the IG **SIU_S12 message map**, the **SCH/AIS/PID → Appointment** segment maps, the
1019
+ * **Table HL70278 → AppointmentStatus** ConceptMap, and the **TQ → Appointment** datatype map
1020
+ * (`hl7.fhir.uv.v2mappings`, STU1; `ConceptMap-message-siu-s12-to-bundle.json`,
1021
+ * `ConceptMap-segment-sch-to-appointment.json`, `ConceptMap-segment-ais-to-appointment.json`,
1022
+ * `ConceptMap-segment-pid-to-appointment.json`, `ConceptMap-table-hl70278-to-appointmentstatus.json`,
1023
+ * `ConceptMap-datatype-tq-to-appointment.json`). Per the message map an SIU message yields **one**
1024
+ * `Appointment` created from the `SCH` segment; `PID` contributes the patient participant and `AIS`
1025
+ * the service type.
1026
+ *
1027
+ * | v2 field | FHIR target | via |
1028
+ * |---|---|---|
1029
+ * | SCH-25 Filler Status Code | `status` (required 1..1) | {@link APPOINTMENT_STATUS_MAP} (HL70278) |
1030
+ * | SCH-1 Placer / SCH-2 Filler Appointment ID | `identifier` | EI.1 → `Identifier.value` |
1031
+ * | SCH-7 Appointment Reason (CWE) | `reasonCode` | {@link toFhirCodeableConcept} (structural — SNOMED target, BYO) |
1032
+ * | SCH-8 Appointment Type (CWE) | `appointmentType` | {@link APPOINTMENT_TYPE_VALUE_MAP} (HL70277, value-translated) |
1033
+ * | SCH-9 Duration + SCH-10 Units | `minutesDuration` | integer, only when SCH-10 is minutes |
1034
+ * | SCH-11 Appointment Timing Quantity (TQ) | `start` / `end` (instant) | TQ.4/TQ.5 → {@link toFhirDateTime} |
1035
+ * | AIS-3 Universal Service Identifier (CWE) | `serviceType` | {@link toFhirCodeableConcept} |
1036
+ * | PID (bundle Patient) | `participant.actor` (required 1..*) | reference wiring |
1037
+ *
1038
+ * **Fail-safes (never a confident wrong appointment).**
1039
+ * - **`status` (required 1..1).** SCH-25 → {@link APPOINTMENT_STATUS_MAP} (HL70278). The three HL70278
1040
+ * codes the IG leaves unmatched (`Discontinued`, `Blocked`, `Overbook`) and an absent SCH-25 leave
1041
+ * `status` absent + flagged {@link ISSUE_CODES.TRANSFORM_CODE_UNMAPPED}; the required-`status` emit gate
1042
+ * then **withholds** the Appointment — never guessed.
1043
+ * - **`participant` (required 1..*).** The bundle Patient is emitted as the required participant. Its
1044
+ * `participant.status` (a required-bound `code` the IG supplies no source for) is emitted as a
1045
+ * `data-absent-reason` primitive (value `unknown`) + flagged {@link ISSUE_CODES.TRANSFORM_REQUIRED_ELEMENT_UNKNOWN}
1046
+ * — the spec-clean way to satisfy a required code whose value is genuinely unknown, never fabricated. An
1047
+ * Appointment with no resolvable Patient (and no other groundable actor this library builds) has no
1048
+ * participant and is withheld.
1049
+ * - **`start`/`end` (instant).** SCH-11's TQ.4/TQ.5 become `start`/`end` only when they are fully-zoned
1050
+ * instants; a naked (unzoned) timing is dropped + flagged rather than assigned a fabricated UTC offset,
1051
+ * mirroring `Bundle.timestamp`.
1052
+ * - **`appointmentType` value translation.** SCH-8 → {@link APPOINTMENT_TYPE_VALUE_MAP}
1053
+ * (HL70277 `Normal`/`Tentative`/`Complete` identity into `v2-0277`); a code outside the table is
1054
+ * preserved + flagged, never coerced. **`reasonCode` is NOT value-translated:** SCH-7's IG map target
1055
+ * is SNOMED CT (`table-hl70276-to-sct`) — encumbered, **not bundled** — so the reason is carried
1056
+ * structurally (BYO ConceptMap), never SNOMED-translated here. (The IG's SCH→Appointment map *also*
1057
+ * carries a redundant SCH-7 → `appointmentType[1]` row via `table-hl70277-to-v2-0277`; it is not
1058
+ * applied — SCH-7 carries HL70276 *reason* codes, not HL70277 *type* codes, so translating them through
1059
+ * the type table would only ever produce spurious unmapped flags. `appointmentType` comes from SCH-8,
1060
+ * the appointment-*type* field, per that same map's SCH-8 → `appointmentType[1]` row.)
1061
+ *
1062
+ * Deferred and flagged elsewhere, not silently mapped: SCH-12/16/20 contact participants and AIP/AIL/AIG
1063
+ * actors (need Practitioner/Location resources), SCH-26/27 `basedOn` ServiceRequest, AIS participant periods.
1064
+ *
1065
+ * @packageDocumentation
1066
+ */
1067
+
1068
+ /**
1069
+ * HL7 v2 Table 0278 (Filler Status Code) → FHIR `appointmentstatus` (`Appointment.status`), per the IG
1070
+ * **Table HL70278 to AppointmentStatus** ConceptMap (each `is equivalent to`). The three source codes
1071
+ * the IG leaves **unmatched** (`Discontinued`, `Blocked`, `Overbook`) are absent here on purpose — an
1072
+ * SCH-25 carrying one of them (or any local code) leaves `Appointment.status` absent + flagged and the
1073
+ * required-`status` emit gate withholds the Appointment.
1074
+ */
1075
+ declare const APPOINTMENT_STATUS_MAP: Readonly<Record<string, string>>;
1076
+
1077
+ /**
1078
+ * The `$translate`-shaped ConceptMap-application engine + the **license-clean** v2-table → FHIR
1079
+ * value maps it applies. This is the layer that value-**translates** a coded v2
1080
+ * field — not merely carrying its code structurally, but mapping the source table code to the FHIR
1081
+ * target coding the IG's segment-map `mappedVia` ConceptMap prescribes.
1082
+ *
1083
+ * **Grounded firsthand on the raw published IG ConceptMaps** (`hl7.fhir.uv.v2mappings`, STU1 —
1084
+ * `ConceptMap-table-*.json`). Each shipped map below cites the exact IG ConceptMap it transcribes and
1085
+ * was verified against that resource's JSON (its `group.element[].target[]` rows and its `unmatched`
1086
+ * `(unmapped)` group). The engine is **fail-safe by refusal**: a source code the IG map has **no
1087
+ * target** for (its `(unmapped)` group) is never coerced to a plausible neighbor — the caller flags it
1088
+ * and preserves the raw coding, or withholds the value, but a target is **never fabricated**.
1089
+ *
1090
+ * **License posture.** Only maps whose target CodeSystem is **freely redistributable** are
1091
+ * shipped here: the HL7 THO v2 tables (`v2-0162`, `v2-0550`, `v2-0277`, `v2-0161`) and HL7 v3
1092
+ * (`v3-RouteOfAdministration`) are HL7's own, license-clean. The IG's `*-to-sct` value maps —
1093
+ * **RXR-4 method** (`table-hl70165-to-sct`) and **SCH-7 reason** (`table-hl70276-to-sct`) — translate
1094
+ * **into SNOMED CT**, which is **license-encumbered and is NOT bundled**; those fields stay
1095
+ * structurally carried (BYO ConceptMap), never value-translated here (see their message modules).
1096
+ *
1097
+ * **Additive, never mutating.** A successful translation preserves the raw source coding
1098
+ * (its code, display, version, and any `CWE.4/5/6` alternate triplet) and *adds* the derived target
1099
+ * coding — recognition never overwrites or discards what the message said; it augments it with the
1100
+ * IG-mapped equivalent. And it only fires when the field's primary coding is genuinely from the map's
1101
+ * **bound source table** (CWE.3 absent, or naming that table): a field that declares a *foreign*
1102
+ * coding system (a local `99…`, SNOMED, …) is carried structurally and flagged — its code is **never**
1103
+ * asserted to be the standard concept just because the string happens to collide with a table code.
1104
+ *
1105
+ * @packageDocumentation
1106
+ */
1107
+
1108
+ /** HL7 v2 Table 0162 (Route of Administration) THO CodeSystem URI. */
1109
+ declare const V2_0162_SYSTEM = "http://terminology.hl7.org/CodeSystem/v2-0162";
1110
+ /** HL7 v3 RouteOfAdministration CodeSystem URI (the IG's remap target for the six common routes). */
1111
+ declare const V3_ROUTE_OF_ADMINISTRATION_SYSTEM = "http://terminology.hl7.org/CodeSystem/v3-RouteOfAdministration";
1112
+ /** HL7 v2 Table 0550 (Body Parts) THO CodeSystem URI. */
1113
+ declare const V2_0550_SYSTEM = "http://terminology.hl7.org/CodeSystem/v2-0550";
1114
+ /** HL7 v2 Table 0277 (Appointment Type Codes) THO CodeSystem URI. */
1115
+ declare const V2_0277_SYSTEM = "http://terminology.hl7.org/CodeSystem/v2-0277";
1116
+ /** HL7 v2 Table 0161 (Allow Substitution) THO CodeSystem URI. */
1117
+ declare const V2_0161_SYSTEM = "http://terminology.hl7.org/CodeSystem/v2-0161";
1118
+ /** A translated FHIR target coding: the target CodeSystem URI + code, and the IG's target display. */
1119
+ interface CodedTarget {
1120
+ /** The FHIR target CodeSystem canonical URI. */
1121
+ readonly system: string;
1122
+ /** The FHIR target code. */
1123
+ readonly code: string;
1124
+ /** The IG map's target display, when it carries one (absent for the identity table maps). */
1125
+ readonly display?: string;
1126
+ }
1127
+ /**
1128
+ * A license-clean v2-table → FHIR value ConceptMap: it translates a **source table code** to its
1129
+ * {@link CodedTarget}, or `undefined` when the code is not in the map's *mapped* group (the IG's
1130
+ * `(unmapped)` group). Never fabricates a target.
1131
+ */
1132
+ interface CodedValueMap {
1133
+ /** The IG ConceptMap id this map transcribes (its citation). */
1134
+ readonly name: string;
1135
+ /** The source table's canonical CodeSystem URI (what the raw v2 code is a member of when mapped). */
1136
+ readonly sourceSystem: string;
1137
+ /**
1138
+ * The CWE.3 (`nameOfCodingSystem`) mnemonics that denote this map's **bound source table** — the
1139
+ * HL7 forms (`"HL70162"`, `"0162"`, …). Translation applies **only** when the field's primary
1140
+ * coding is from the bound table: CWE.3 absent/empty (a positionally-bound bare code) **or** CWE.3 ∈
1141
+ * this set. A CWE that declares a **different** coding system (a local `99…`, or SNOMED) is not a
1142
+ * source-table code, so the map is not applied to it — the raw coding is carried structurally + its
1143
+ * system flagged, never asserted as the standard concept.
1144
+ */
1145
+ readonly sourceMnemonics: ReadonlySet<string>;
1146
+ /** Translate a source table code to its FHIR target, or `undefined` when the IG map has no target. */
1147
+ readonly translate: (code: string) => CodedTarget | undefined;
1148
+ }
1149
+ /**
1150
+ * **RXR-1 Route** — IG `ConceptMap/table-hl70162-to-v2-0162`. Two IG groups, transcribed verbatim:
1151
+ * a 41-code **identity** group (source `v2-0162` → target `v2-0162`, each `equivalent`) and a 6-code
1152
+ * **remap** group into `v3-RouteOfAdministration` (`ID→IDINJ`, `IM→IM`, `IV→IVINJ`, `PO→PO`, `SC→SQ`,
1153
+ * `TD→TRNSDERM`, each `equivalent`, with the IG target displays). The two source-code sets are
1154
+ * disjoint. Any other v2-0162 code (or a non-table code) is unmapped → the raw coding is preserved
1155
+ * and flagged, never coerced.
1156
+ */
1157
+ declare const ROUTE_VALUE_MAP: CodedValueMap;
1158
+ /**
1159
+ * **RXR-2 Administration Site** — IG `ConceptMap/table-hl70550-to-v2-0550`. A single **identity**
1160
+ * group of 443 body-part codes (source `v2-0550` → target `v2-0550`, each `equivalent`), transcribed
1161
+ * verbatim from the published STU1 ConceptMap — **including** its as-published data-quality artifacts
1162
+ * (`CHESTÂ`, a lone `Â`, `KIDNÂ`, where a stray U+00C2 leaked from the IG's source
1163
+ * encoding). They are preserved for source-fidelity; they are inert (a clean `CHEST`/`KIDN` simply
1164
+ * falls through to unmapped). A code not in the table is unmapped → raw coding preserved + flagged.
1165
+ */
1166
+ declare const SITE_VALUE_MAP: CodedValueMap;
1167
+ /**
1168
+ * **SCH-8 Appointment Type** — IG `ConceptMap/table-hl70277-to-v2-0277`. A single **identity** group
1169
+ * of the three v2-0277 codes (`Normal`, `Tentative`, `Complete` → themselves, each `equivalent`,
1170
+ * source and target both `v2-0277`). Any other code is unmapped → raw coding preserved + flagged.
1171
+ */
1172
+ declare const APPOINTMENT_TYPE_VALUE_MAP: CodedValueMap;
1173
+ /**
1174
+ * **RXO-9 Allow Substitutions** — IG `ConceptMap/table-hl70161-to-v2-0161`. A single **identity**
1175
+ * group of the three v2-0161 codes (`N` NOT authorized, `G` generic, `T` therapeutic → themselves,
1176
+ * each `equivalent`, source and target both `v2-0161`), the target for
1177
+ * `MedicationRequest.substitution.allowedCodeableConcept`. Any other code is unmapped → the
1178
+ * substitution is withheld + flagged, never a fabricated substitution permission.
1179
+ */
1180
+ declare const SUBSTITUTION_VALUE_MAP: CodedValueMap;
1181
+ /**
1182
+ * The bound-table target for a coded element's **primary** coding, or `undefined` when the map does
1183
+ * not faithfully apply — i.e. the primary declares a coding system that is **not** this map's bound
1184
+ * table (CWE.3 present and not in {@link CodedValueMap.sourceMnemonics}), the primary code is empty, or
1185
+ * the code is in the IG map's `(unmapped)` group. Never asserts a standard translation for a foreign
1186
+ * coding system, and never fabricates a target.
1187
+ *
1188
+ * @param cwe - The parsed coded element (its `identifier` is the candidate source-table code).
1189
+ * @param map - The license-clean value map to consider applying.
1190
+ * @example
1191
+ * ```ts
1192
+ * import { translateBound, ROUTE_VALUE_MAP } from "@cosyte/transform";
1193
+ * translateBound({ identifier: "IM" }, ROUTE_VALUE_MAP)?.code; // "IM" (v3 route)
1194
+ * translateBound({ identifier: "IM", nameOfCodingSystem: "99LOCAL" }, ROUTE_VALUE_MAP); // undefined
1195
+ * ```
1196
+ */
1197
+ declare function translateBound(cwe: CodedElement, map: CodedValueMap): CodedTarget | undefined;
1198
+ /**
1199
+ * Build a FHIR `CodeableConcept` node for a {@link CodedTarget} — the single translated coding, with
1200
+ * an optional free-`text`. Used by translate-or-withhold callers (e.g. substitution) that build the
1201
+ * CodeableConcept only on a successful translation.
1202
+ *
1203
+ * @param target - The translated target coding.
1204
+ * @param text - The original free text (`CWE.9`) to carry as `CodeableConcept.text`, if any.
1205
+ * @example
1206
+ * ```ts
1207
+ * import { codeableConceptFromTarget, V2_0161_SYSTEM } from "@cosyte/transform";
1208
+ * const cc = codeableConceptFromTarget({ system: V2_0161_SYSTEM, code: "G" });
1209
+ * void cc;
1210
+ * ```
1211
+ */
1212
+ declare function codeableConceptFromTarget(target: CodedTarget, text?: string): FhirComplex;
1213
+ /**
1214
+ * Value-translate a coded v2 element to a FHIR `CodeableConcept` **via** a license-clean
1215
+ * {@link CodedValueMap}, **additively** and fail-safe — never mutating or discarding what the message
1216
+ * said:
1217
+ *
1218
+ * - **Primary code recognized as a bound-table code** ({@link translateBound} — CWE.3 absent or names
1219
+ * the bound table, and the code is in the IG map's mapped group) → the **primary** coding is emitted
1220
+ * in the recognized source-table system (`map.sourceSystem`, carrying `CWE.7` version) and the
1221
+ * **derived** target coding is *appended* when it differs (a remap such as `SC→SQ`); the **alternate
1222
+ * triplet** (`CWE.4/5/6`, via {@link buildCoding}, with its own system resolution + flags) and the
1223
+ * original `CWE.9` text are preserved. No primary unmapped flag — the value was faithfully recognized.
1224
+ * - **Otherwise** — the primary declares a **foreign** coding system (not the bound table), the code is
1225
+ * empty, or it is in the IG's `(unmapped)` group → this defers entirely to the **structural**
1226
+ * {@link toFhirCodeableConcept}, which preserves the raw coding (and its `CWE.4/5/6` alternate and
1227
+ * `CWE.7` version) and flags it ({@link ISSUE_CODES.TRANSFORM_CODE_UNMAPPED} /
1228
+ * `TRANSFORM_CODE_SYSTEM_UNRESOLVED`). A target is **never** fabricated, and a code that declares a
1229
+ * foreign system is **never** asserted to be the standard concept.
1230
+ *
1231
+ * @param cwe - The parsed `@cosyte/hl7` coded element (its `identifier` is the candidate table code).
1232
+ * @param map - The license-clean value map to apply (e.g. {@link ROUTE_VALUE_MAP}).
1233
+ * @param ctx - The transform context (threaded to the structural path + the alternate-triplet resolver).
1234
+ * @example
1235
+ * ```ts
1236
+ * import { toFhirCodeableConceptVia, ROUTE_VALUE_MAP } from "@cosyte/transform";
1237
+ * const { value } = toFhirCodeableConceptVia({ identifier: "IM" }, ROUTE_VALUE_MAP);
1238
+ * // coding === [{ system: ".../v2-0162", code: "IM" },
1239
+ * // { system: ".../v3-RouteOfAdministration", code: "IM", display: "Injection, intramuscular" }]
1240
+ * void value;
1241
+ * ```
1242
+ */
1243
+ declare function toFhirCodeableConceptVia(cwe: CodedElement, map: CodedValueMap, ctx?: TransformContext): ConvertResult<FhirComplex>;
1244
+
1245
+ /**
1246
+ * Public entry point for `@cosyte/transform` — the HL7 v2 → FHIR R4 transformation library.
1247
+ *
1248
+ * `@cosyte/transform` is **not** a parser; it is a **consumer** one tier above the parser suite. It
1249
+ * takes already-parsed `@cosyte/hl7` composites and produces validated `@cosyte/fhir` model nodes,
1250
+ * grounded on the official **HL7 Version 2 to FHIR** Implementation Guide (`hl7.fhir.uv.v2mappings`,
1251
+ * STU Edition 1). Its whole promise is narrow and honest: **IG-grounded, fail-safe transformation
1252
+ * with typed, value-free diagnostics — never a confident wrong FHIR value.**
1253
+ *
1254
+ * This module ships the six safety-critical datatype converters, the immutable
1255
+ * `OperationOutcome`-shaped diagnostic channel and the NamingSystem resolver they consult,
1256
+ * the message-level assembly — HL7 v2 **ADT → FHIR Patient + Encounter**, the
1257
+ * **ORU^R01 → DiagnosticReport + Observation** results graph, the order-entry graph
1258
+ * (**ORM_O01 / OML_O21 → ServiceRequest** and **RXO → MedicationRequest**), and the thin IG
1259
+ * singles (**VXU_V04 → Immunization**, **SIU_S12 → Appointment**, **MDM_T02 → DocumentReference**),
1260
+ * all through `toFhir(msg)` — and the **terminology value-translation** layer: a
1261
+ * `$translate`-shaped {@link toFhirCodeableConceptVia} engine applying the license-clean IG value
1262
+ * ConceptMaps to the previously structural-only coded fields (route/site, appointment type, order
1263
+ * priority, substitution). Terminology **depth beyond these maps**, profiles, and the reverse
1264
+ * FHIR → v2 direction are not implemented.
1265
+ *
1266
+ * @packageDocumentation
1267
+ */
1268
+ /** The library version string, synced with `package.json#version` by the release tooling. */
1269
+ declare const VERSION = "0.0.0";
1270
+
1271
+ export { ADDRESS_TYPE_MAP, ADDRESS_USE_MAP, ADMINISTRATIVE_GENDER_MAP, APPOINTMENT_STATUS_MAP, APPOINTMENT_TYPE_VALUE_MAP, type CodedElement, type CodedTarget, type CodedValueMap, type ConvertResult, DEFAULT_V2_CODE_SYSTEMS, DIAGNOSTIC_REPORT_STATUS_MAP, ENCOUNTER_CLASS_V3_MAP, ENCOUNTER_STATUS_MAP, FATAL_CODES, type FatalCode, HL70078_INTERPRETATION_CODES, IG_MAPPED_ADT_TRIGGERS, IG_MAPPED_APPOINTMENT_TRIGGERS, IG_MAPPED_DOCUMENT_TRIGGERS, IG_MAPPED_IMMUNIZATION_TRIGGERS, IG_MAPPED_ORDER_TRIGGERS, IG_MAPPED_ORU_TRIGGERS, IMMUNIZATION_STATUS_MAP, ISSUE_CODES, ISSUE_REGISTRY, type IssueCode, NAME_USE_MAP, type NamingSystemRegistry, type NamingSystemSeed, OBSERVATION_STATUS_MAP, REQUEST_STATUS_MAP, ROUTE_VALUE_MAP, SERVICE_REQUEST_PRIORITY_MAP, SITE_VALUE_MAP, SUBSTITUTION_VALUE_MAP, TRANSFORM_ISSUE_SYSTEM, type TransformContext, type TransformIssue, type TransformOptions, type TransformResult, type TransformSeverity, V2_0161_SYSTEM, V2_0162_SYSTEM, V2_0203_SYSTEM, V2_0277_SYSTEM, V2_0550_SYSTEM, V3_ROUTE_OF_ADMINISTRATION_SYSTEM, VERSION, codeableConceptFromTarget, createNamingSystem, fhirIssueTypeFor, issue, toFhir, toFhirAddress, toFhirCodeableConcept, toFhirCodeableConceptVia, toFhirDateTime, toFhirHumanName, toFhirIdentifier, toFhirQuantity, toOperationOutcome, translateBound };