@cosyte/terminology 0.0.11 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +178 -0
- package/README.md +33 -33
- package/dist/index.cjs +51 -51
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +359 -359
- package/dist/index.d.ts +359 -359
- package/dist/index.mjs +51 -51
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
- package/vendor/ucum/NOTICE.md +4 -4
package/dist/index.d.cts
CHANGED
|
@@ -5,15 +5,15 @@
|
|
|
5
5
|
* These mirror the FHIR R4 datatypes of the same names (the interchange lingua franca the whole
|
|
6
6
|
* ecosystem speaks), reduced to the fields the terminology operations need. Every instance the
|
|
7
7
|
* engine hands back is deep-frozen, so a translated result is safe to share across a pipeline
|
|
8
|
-
* without defensive copying
|
|
8
|
+
* without defensive copying: the immutability discipline the parsers follow.
|
|
9
9
|
*
|
|
10
10
|
* @packageDocumentation
|
|
11
11
|
*/
|
|
12
12
|
/**
|
|
13
|
-
* A single coded value
|
|
13
|
+
* A single coded value: a `code` drawn from a code `system`, optionally versioned and displayed.
|
|
14
14
|
*
|
|
15
15
|
* Models FHIR R4 `Coding`. `system` is the code system's **canonical URI** (e.g.
|
|
16
|
-
* `http://loinc.org`), not a mnemonic or OID
|
|
16
|
+
* `http://loinc.org`), not a mnemonic or OID: use {@link ../systems/resolve.resolveSystem} to
|
|
17
17
|
* canonicalize before constructing one. `system` is optional because a raw wire code sometimes
|
|
18
18
|
* arrives without one; the engine surfaces that rather than inventing a system.
|
|
19
19
|
*
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
interface Coding {
|
|
29
29
|
/** The code system's canonical URI (e.g. `http://snomed.info/sct`). Optional when unknown. */
|
|
30
30
|
readonly system?: string;
|
|
31
|
-
/** The symbol in the code system's syntax. Required
|
|
31
|
+
/** The symbol in the code system's syntax. Required: a coding without a code is meaningless. */
|
|
32
32
|
readonly code: string;
|
|
33
33
|
/** The code system version this code is drawn from, when known (mappings are release-scoped). */
|
|
34
34
|
readonly version?: string;
|
|
@@ -36,7 +36,7 @@ interface Coding {
|
|
|
36
36
|
readonly display?: string;
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
|
-
* A concept described by one or more {@link Coding}s plus optional free text
|
|
39
|
+
* A concept described by one or more {@link Coding}s plus optional free text: FHIR R4
|
|
40
40
|
* `CodeableConcept`. Included so the value layer is complete for downstream consumers even though
|
|
41
41
|
* {@link ../conceptmap/translate.translate} operates on a single {@link Coding}.
|
|
42
42
|
*
|
|
@@ -60,7 +60,7 @@ interface CodeableConcept {
|
|
|
60
60
|
/**
|
|
61
61
|
* Construct a deep-frozen {@link Coding}.
|
|
62
62
|
*
|
|
63
|
-
* The returned object is `Object.freeze`d so it cannot be mutated in place
|
|
63
|
+
* The returned object is `Object.freeze`d so it cannot be mutated in place: parsed/translated
|
|
64
64
|
* values are immutable by default. Optional fields are only present when supplied (no `undefined`
|
|
65
65
|
* keys), so structural equality checks stay clean.
|
|
66
66
|
*
|
|
@@ -96,14 +96,14 @@ declare function codeableConcept(init: CodeableConcept): CodeableConcept;
|
|
|
96
96
|
* `@cosyte/terminology` is an engine, not a lenient wire-format parser, so its stable codes are
|
|
97
97
|
* **diagnostics** (typed, surfaced outcomes a consumer branches on) and **fatals** (thrown on
|
|
98
98
|
* structurally unusable input), rather than the parsers' "Tier-2 tolerance warnings". The
|
|
99
|
-
* discipline is identical: the code strings are part of the public contract
|
|
99
|
+
* discipline is identical: the code strings are part of the public contract, consumers narrow on
|
|
100
100
|
* them, so renaming or removing one is a **breaking change**, and the full set is snapshotted via
|
|
101
101
|
* `sortedCodeSet` (`@cosyte/test-utils`) as a reviewable tripwire.
|
|
102
102
|
*
|
|
103
103
|
* **Value-free by construction**, and the property is stated as what it actually is: every string a
|
|
104
104
|
* diagnostic or fatal message is assembled from is **owned by the engine**. Three kinds, and no
|
|
105
105
|
* fourth: a string literal; an entry in a frozen table keyed on the engine's own vocabulary; and a
|
|
106
|
-
* **locus this package built
|
|
106
|
+
* **locus this package built**: a 1-based `line`, a column count, or an index path over the
|
|
107
107
|
* caller's own resource made of integers and FHIR field names (`ConceptMap group[0].element[0].target[0]`,
|
|
108
108
|
* `compose.include[2]`). Nothing a caller configured and nothing their release or resource contained
|
|
109
109
|
* is ever one of them, so no such string reaches a `message`, a `stack`, or a `detail`, at any
|
|
@@ -112,16 +112,16 @@ declare function codeableConcept(init: CodeableConcept): CodeableConcept;
|
|
|
112
112
|
* Read that as the rule, and note what it does **not** say. It does not say no factory takes a
|
|
113
113
|
* `string` parameter. Several do: `malformed(path, fault)` in `conceptmap/load.ts` and
|
|
114
114
|
* `valueset/load.ts`, and `cannotExpand(detail, path)`, `truncated(detail, path)` and
|
|
115
|
-
* `underPath(d, prefix)` in `valueset
|
|
115
|
+
* `underPath(d, prefix)` in `valueset/`, where `expand.ts` and `validate.ts` each carry their own
|
|
116
116
|
* copy. It says every **argument** reaching them is engine-owned: each `fault` and `detail` is a
|
|
117
117
|
* literal at the call site, each `path` and `prefix` is built from indices by the loader that
|
|
118
|
-
* raises it. That distinction is the thing to preserve
|
|
118
|
+
* raises it. That distinction is the thing to preserve: an absolute "no factory takes a value
|
|
119
119
|
* parameter" reads as a stronger guarantee than the one the code makes, and those factories are the
|
|
120
120
|
* counter-example to it. Do not write the count down; derive it.
|
|
121
121
|
*
|
|
122
122
|
* Positional context is value-free the same way: a `line` integer, an `ExpansionDiagnostic.path`
|
|
123
123
|
* index path into the caller's own resource (`compose.include[2]`), or a closed-set token
|
|
124
|
-
* (`RXNCONSO` / `RXNREL` / `RXNSAT`)
|
|
124
|
+
* (`RXNCONSO` / `RXNREL` / `RXNSAT`): never a URI, a column name, or a field the file supplied.
|
|
125
125
|
* This matters because a code *in patient context* can be PHI, and a thrown error is the one surface
|
|
126
126
|
* that reaches a log or an error reporter without the consumer choosing to put it there.
|
|
127
127
|
*
|
|
@@ -134,20 +134,20 @@ declare function codeableConcept(init: CodeableConcept): CodeableConcept;
|
|
|
134
134
|
* The **objects** these codes appear on are a different matter, and they carry verbatim text from
|
|
135
135
|
* two *different* provenances, which decide differently:
|
|
136
136
|
*
|
|
137
|
-
* - **Your query, echoed back
|
|
137
|
+
* - **Your query, echoed back**: `LookupUnknown.input`, `LookupResult.code`, `UnknownSystem.input`,
|
|
138
138
|
* `TranslateUnmapped.source`, `CrosswalkUnmapped.source`, `CrosswalkNoMap.source`,
|
|
139
139
|
* `RxNormUnknown.rxcui`, `RxNormRelated.predicates`, `NdcUnmapped.ndc`,
|
|
140
|
-
* `ValueSetMembership.coding`, and **`MapProvenance.sourceSystem
|
|
140
|
+
* `ValueSetMembership.coding`, and **`MapProvenance.sourceSystem`**, which is the `system` off
|
|
141
141
|
* the `Coding` you passed to `translate`, verbatim and unbounded, whenever that coding
|
|
142
142
|
* carries one; the map's own `group.source` is only the fallback for a coding that does not. The
|
|
143
143
|
* query is the one genuinely **patient-derived** input this engine takes (a code off a parsed
|
|
144
144
|
* message, a unit off an observation, an NDC off a prescription), so this is the class that
|
|
145
145
|
* decides a PHI question.
|
|
146
|
-
* - **Your loaded artifact, carried through
|
|
146
|
+
* - **Your loaded artifact, carried through**: `ComplexMapContextRequired.rules` (the map
|
|
147
147
|
* document's own `rule` / `advice` text) and `MapProvenance.targetSystem` / `.conceptMapUrl` /
|
|
148
148
|
* `.conceptMapVersion`, which are read off the loaded map (`group.target`, `map.url`,
|
|
149
149
|
* `map.version`). These are *reference data*, bounded by the map or release you loaded, not by
|
|
150
|
-
* anything a patient supplied. **`MapProvenance` straddles the two lists
|
|
150
|
+
* anything a patient supplied. **`MapProvenance` straddles the two lists**: do not read the whole
|
|
151
151
|
* record as reference data on the strength of the fields that are.
|
|
152
152
|
*
|
|
153
153
|
* Read both lists as illustrative, not closed: **assume any result field may hold what you passed
|
|
@@ -161,7 +161,7 @@ declare function codeableConcept(init: CodeableConcept): CodeableConcept;
|
|
|
161
161
|
* @packageDocumentation
|
|
162
162
|
*/
|
|
163
163
|
/**
|
|
164
|
-
* Stable **diagnostic codes
|
|
164
|
+
* Stable **diagnostic codes**: typed, surfaced, non-throwing outcomes.
|
|
165
165
|
*
|
|
166
166
|
* These are not errors: they are first-class results a caller inspects (an unmapped translation,
|
|
167
167
|
* an unrecognized code system). `key === value` so `Object.values(...)` yields the snapshot set.
|
|
@@ -175,7 +175,7 @@ declare function codeableConcept(init: CodeableConcept): CodeableConcept;
|
|
|
175
175
|
*/
|
|
176
176
|
declare const DIAGNOSTIC_CODES: {
|
|
177
177
|
/**
|
|
178
|
-
* A `$translate` found no target for the source code. A **first-class outcome, never an error
|
|
178
|
+
* A `$translate` found no target for the source code. A **first-class outcome, never an error**:
|
|
179
179
|
* the source is surfaced as `unmapped`, never replaced with a guessed target (the never-fabricate
|
|
180
180
|
* invariant).
|
|
181
181
|
*/
|
|
@@ -186,30 +186,30 @@ declare const DIAGNOSTIC_CODES: {
|
|
|
186
186
|
*/
|
|
187
187
|
readonly TERM_SYSTEM_UNRECOGNIZED: "TERM_SYSTEM_UNRECOGNIZED";
|
|
188
188
|
/**
|
|
189
|
-
* An RRF (pipe-delimited RxNorm/UMLS release) row was structurally unusable
|
|
189
|
+
* An RRF (pipe-delimited RxNorm/UMLS release) row was structurally unusable: too few columns to
|
|
190
190
|
* reach a configured field, or a missing code. The row is **skipped and surfaced** as a load
|
|
191
191
|
* warning (liberal on load), never kept as a partially-parsed concept.
|
|
192
192
|
*/
|
|
193
193
|
readonly TERM_RRF_MALFORMED_ROW: "TERM_RRF_MALFORMED_ROW";
|
|
194
194
|
/**
|
|
195
|
-
* A CSV (RFC-4180, e.g. LOINC `Loinc.csv`) row was structurally unusable
|
|
195
|
+
* A CSV (RFC-4180, e.g. LOINC `Loinc.csv`) row was structurally unusable: too few fields to reach
|
|
196
196
|
* a configured column. The row is **skipped and surfaced** as a load warning, never partial.
|
|
197
197
|
*/
|
|
198
198
|
readonly TERM_CSV_MALFORMED: "TERM_CSV_MALFORMED";
|
|
199
199
|
/**
|
|
200
|
-
* A fixed-width (e.g. ICD-10-CM order file) row was structurally unusable
|
|
200
|
+
* A fixed-width (e.g. ICD-10-CM order file) row was structurally unusable: too short to contain
|
|
201
201
|
* the configured code field, or a missing code. Skipped and surfaced, never partial.
|
|
202
202
|
*/
|
|
203
203
|
readonly TERM_FIXED_WIDTH_MALFORMED: "TERM_FIXED_WIDTH_MALFORMED";
|
|
204
204
|
/**
|
|
205
|
-
* A concept inside a FHIR `CodeSystem` resource was unusable
|
|
205
|
+
* A concept inside a FHIR `CodeSystem` resource was unusable: not an object, or missing its
|
|
206
206
|
* required `code`. Skipped and surfaced (the whole resource still loads); `line` is `0` since a
|
|
207
207
|
* JSON concept is not line-addressable.
|
|
208
208
|
*/
|
|
209
209
|
readonly TERM_FHIR_CONCEPT_MALFORMED: "TERM_FHIR_CONCEPT_MALFORMED";
|
|
210
210
|
/**
|
|
211
211
|
* A `$lookup`/`$validate-code` found no concept for the code in the loaded release. A **first-class
|
|
212
|
-
* typed outcome, never a guess
|
|
212
|
+
* typed outcome, never a guess**: the engine returns `unknown`/`valid: false`, never a fabricated
|
|
213
213
|
* display or a coerced `valid: true` (the never-fabricate invariant, applied to code identity).
|
|
214
214
|
*/
|
|
215
215
|
readonly TERM_CODE_UNKNOWN: "TERM_CODE_UNKNOWN";
|
|
@@ -226,7 +226,7 @@ declare const DIAGNOSTIC_CODES: {
|
|
|
226
226
|
*/
|
|
227
227
|
readonly TERM_CONCEPT_HEADER_NOT_BILLABLE: "TERM_CONCEPT_HEADER_NOT_BILLABLE";
|
|
228
228
|
/**
|
|
229
|
-
* A ValueSet `compose` part could **not be expanded
|
|
229
|
+
* A ValueSet `compose` part could **not be expanded**: an intensional `include`/`exclude` whose
|
|
230
230
|
* code system was not supplied, an unresolvable referenced value set, or a `filter` operator the
|
|
231
231
|
* engine does not implement. Surfaced as a typed outcome that marks the expansion **incomplete**;
|
|
232
232
|
* the engine **never** fabricates a member and **never** returns a silently-empty "no members"
|
|
@@ -234,14 +234,14 @@ declare const DIAGNOSTIC_CODES: {
|
|
|
234
234
|
*/
|
|
235
235
|
readonly TERM_VALUESET_CANNOT_EXPAND: "TERM_VALUESET_CANNOT_EXPAND";
|
|
236
236
|
/**
|
|
237
|
-
* A **pre-computed** `ValueSet.expansion` is **incomplete
|
|
237
|
+
* A **pre-computed** `ValueSet.expansion` is **incomplete**: its `total` exceeds the number of
|
|
238
238
|
* `contains` entries, or it is flagged too-costly (the VSAC `$expand` >1200-code truncation
|
|
239
239
|
* hazard). The engine **never treats a truncated expansion as complete membership**: a code
|
|
240
240
|
* absent from a truncated expansion is `undetermined`, never a confident "not a member".
|
|
241
241
|
*/
|
|
242
242
|
readonly TERM_VALUESET_EXPANSION_TRUNCATED: "TERM_VALUESET_EXPANSION_TRUNCATED";
|
|
243
243
|
/**
|
|
244
|
-
* A UCUM unit expression is **not valid
|
|
244
|
+
* A UCUM unit expression is **not valid**: it does not parse against the UCUM grammar, or it
|
|
245
245
|
* names an atom absent from the vendored UCUM table. A **first-class typed outcome, never an
|
|
246
246
|
* error and never a guess**: {@link validateUcum} returns `{ valid: false, reason }`, never a
|
|
247
247
|
* coerced or "nearest" unit (the never-fabricate invariant, applied to units). The
|
|
@@ -249,7 +249,7 @@ declare const DIAGNOSTIC_CODES: {
|
|
|
249
249
|
*/
|
|
250
250
|
readonly TERM_UCUM_INVALID: "TERM_UCUM_INVALID";
|
|
251
251
|
/**
|
|
252
|
-
* A crosswalk source code has an **authored No-Map
|
|
252
|
+
* A crosswalk source code has an **authored No-Map**: the steward declares it has no valid target
|
|
253
253
|
* in the other classification (a GEM `NoDx`/`NoPCS` sentinel, or a SNOMED complex-map `447638001`
|
|
254
254
|
* "cannot be classified" category). A **first-class typed outcome, never an error and never a
|
|
255
255
|
* guess** (the never-fabricate invariant, applied to crosswalks). Distinct from
|
|
@@ -257,7 +257,7 @@ declare const DIAGNOSTIC_CODES: {
|
|
|
257
257
|
*/
|
|
258
258
|
readonly TERM_CROSSWALK_NO_MAP: "TERM_CROSSWALK_NO_MAP";
|
|
259
259
|
/**
|
|
260
|
-
* A crosswalk source code is **absent from the map entirely
|
|
260
|
+
* A crosswalk source code is **absent from the map entirely**: not an authored No-Map, simply not
|
|
261
261
|
* present. Surfaced as a typed outcome (never a fabricated target, never a silent success), and
|
|
262
262
|
* kept distinct from {@link TERM_CROSSWALK_NO_MAP} so a caller can tell "the steward said no target"
|
|
263
263
|
* from "this code was not in the file".
|
|
@@ -266,26 +266,26 @@ declare const DIAGNOSTIC_CODES: {
|
|
|
266
266
|
/**
|
|
267
267
|
* A SNOMED→ICD-10-CM complex-map group's decision needs **patient context** (an `IFA` age band or
|
|
268
268
|
* gender) the caller did not supply. The engine surfaces the candidate rules + advice and **refuses
|
|
269
|
-
* to pick a branch** it lacks the data for
|
|
269
|
+
* to pick a branch** it lacks the data for: never a silently-chosen target.
|
|
270
270
|
*/
|
|
271
271
|
readonly TERM_CROSSWALK_CONTEXT_REQUIRED: "TERM_CROSSWALK_CONTEXT_REQUIRED";
|
|
272
272
|
/**
|
|
273
|
-
* A GEM file line was structurally unusable
|
|
273
|
+
* A GEM file line was structurally unusable: not three whitespace-delimited fields, or a flag
|
|
274
274
|
* field that is not a 5-digit code. The row is **skipped and surfaced** as a load warning (liberal
|
|
275
275
|
* on load), never kept as a partially-parsed entry.
|
|
276
276
|
*/
|
|
277
277
|
readonly TERM_GEM_MALFORMED_ROW: "TERM_GEM_MALFORMED_ROW";
|
|
278
278
|
/**
|
|
279
|
-
* A SNOMED complex-map RF2 refset row was structurally unusable
|
|
279
|
+
* A SNOMED complex-map RF2 refset row was structurally unusable: missing its
|
|
280
280
|
* `referencedComponentId`/`mapGroup`/`mapPriority`. Skipped and surfaced, never partial.
|
|
281
281
|
*/
|
|
282
282
|
readonly TERM_COMPLEX_MAP_MALFORMED_ROW: "TERM_COMPLEX_MAP_MALFORMED_ROW";
|
|
283
283
|
/**
|
|
284
|
-
* A RxNorm RRF row (`RXNCONSO` / `RXNREL` / `RXNSAT`) was structurally unusable
|
|
284
|
+
* A RxNorm RRF row (`RXNCONSO` / `RXNREL` / `RXNSAT`) was structurally unusable: too few columns to
|
|
285
285
|
* reach a required field, or a missing `RXCUI`/NDC value. The row is **skipped and surfaced** as a
|
|
286
286
|
* load warning (liberal on load), never kept as a partial concept/edge. Rows that are simply *not of
|
|
287
287
|
* interest* (a non-`RXNORM` atom, an atom-level relationship, a non-`NDC` attribute) are skipped
|
|
288
|
-
* **silently
|
|
288
|
+
* **silently**: they are expected, not faults.
|
|
289
289
|
*/
|
|
290
290
|
readonly TERM_RXNORM_MALFORMED_ROW: "TERM_RXNORM_MALFORMED_ROW";
|
|
291
291
|
/**
|
|
@@ -299,7 +299,7 @@ declare const DIAGNOSTIC_CODES: {
|
|
|
299
299
|
*/
|
|
300
300
|
readonly TERM_RXNORM_UNTYPED_CONCEPT: "TERM_RXNORM_UNTYPED_CONCEPT";
|
|
301
301
|
/**
|
|
302
|
-
* A RxNorm graph navigation was asked about an `RXCUI` **absent from the loaded release
|
|
302
|
+
* A RxNorm graph navigation was asked about an `RXCUI` **absent from the loaded release**: a
|
|
303
303
|
* first-class typed outcome, never a fabricated concept and never an empty "success" (the
|
|
304
304
|
* never-fabricate invariant, applied to the drug graph). Distinct from a *present*
|
|
305
305
|
* concept that simply has no edge of the requested relationship (that is a found result with empty
|
|
@@ -307,18 +307,18 @@ declare const DIAGNOSTIC_CODES: {
|
|
|
307
307
|
*/
|
|
308
308
|
readonly TERM_RXNORM_UNKNOWN_RXCUI: "TERM_RXNORM_UNKNOWN_RXCUI";
|
|
309
309
|
/**
|
|
310
|
-
* An NDC could **not be resolved** to any `RXCUI` in the loaded RxNorm release
|
|
310
|
+
* An NDC could **not be resolved** to any `RXCUI` in the loaded RxNorm release: a typed, surfaced
|
|
311
311
|
* absence, never a guessed `RXCUI`. NDC↔RXCUI is many:1 and temporal, so a resolution
|
|
312
312
|
* is always release-scoped; an NDC not present in the loaded release is this diagnostic.
|
|
313
313
|
*/
|
|
314
314
|
readonly TERM_RXNORM_NDC_UNMAPPED: "TERM_RXNORM_NDC_UNMAPPED";
|
|
315
315
|
};
|
|
316
316
|
/**
|
|
317
|
-
* A value from {@link DIAGNOSTIC_CODES}
|
|
317
|
+
* A value from {@link DIAGNOSTIC_CODES}: the type consumers narrow a diagnostic's `code` against.
|
|
318
318
|
*/
|
|
319
319
|
type DiagnosticCode = (typeof DIAGNOSTIC_CODES)[keyof typeof DIAGNOSTIC_CODES];
|
|
320
320
|
/**
|
|
321
|
-
* Stable **fatal codes
|
|
321
|
+
* Stable **fatal codes**: thrown (as a {@link TerminologyError}) when input cannot be loaded into
|
|
322
322
|
* a usable model at all. Always thrown, never swallowed. `key === value`, part of the contract.
|
|
323
323
|
*
|
|
324
324
|
* @example
|
|
@@ -330,33 +330,33 @@ type DiagnosticCode = (typeof DIAGNOSTIC_CODES)[keyof typeof DIAGNOSTIC_CODES];
|
|
|
330
330
|
*/
|
|
331
331
|
declare const FATAL_CODES: {
|
|
332
332
|
/**
|
|
333
|
-
* A `ConceptMap` resource was structurally unusable
|
|
333
|
+
* A `ConceptMap` resource was structurally unusable: wrong `resourceType`, or a group/element
|
|
334
334
|
* missing a required field. Thrown rather than silently loading a partial, misleading map.
|
|
335
335
|
*/
|
|
336
336
|
readonly TERM_CONCEPTMAP_MALFORMED: "TERM_CONCEPTMAP_MALFORMED";
|
|
337
337
|
/**
|
|
338
|
-
* A CodeSystem *source* was structurally unusable
|
|
338
|
+
* A CodeSystem *source* was structurally unusable: a FHIR resource with the wrong `resourceType`,
|
|
339
339
|
* or a delimited source whose configured code/display column is absent from the header. Thrown
|
|
340
340
|
* rather than silently loading an empty or mis-keyed release. (Malformed individual **rows** are
|
|
341
|
-
* skipped-and-surfaced load warnings, not fatals
|
|
341
|
+
* skipped-and-surfaced load warnings, not fatals: only an unusable *source* is fatal.)
|
|
342
342
|
*/
|
|
343
343
|
readonly TERM_CODESYSTEM_MALFORMED: "TERM_CODESYSTEM_MALFORMED";
|
|
344
344
|
/**
|
|
345
|
-
* A `ValueSet` resource was structurally unusable
|
|
345
|
+
* A `ValueSet` resource was structurally unusable: wrong `resourceType`, or a `compose`/`expansion`
|
|
346
346
|
* whose required shape (an `include` that is not an object, a `contains` entry missing its `code`)
|
|
347
347
|
* is corrupt. Thrown rather than silently loading a partial value set that would bind *some* codes
|
|
348
|
-
* and quietly drop others. (A `filter` operator the engine does not implement is **not** fatal
|
|
348
|
+
* and quietly drop others. (A `filter` operator the engine does not implement is **not** fatal; it
|
|
349
349
|
* is the surfaced `TERM_VALUESET_CANNOT_EXPAND` diagnostic at expansion time.)
|
|
350
350
|
*/
|
|
351
351
|
readonly TERM_VALUESET_MALFORMED: "TERM_VALUESET_MALFORMED";
|
|
352
352
|
/**
|
|
353
|
-
* A crosswalk map *source* was structurally unusable
|
|
353
|
+
* A crosswalk map *source* was structurally unusable: e.g. a SNOMED complex-map RF2 refset with
|
|
354
354
|
* empty content or a header missing a required column. Thrown rather than silently loading an empty
|
|
355
355
|
* or mis-keyed map. (Malformed individual **rows** are skipped-and-surfaced warnings, not fatals.)
|
|
356
356
|
*/
|
|
357
357
|
readonly TERM_CROSSWALK_MALFORMED: "TERM_CROSSWALK_MALFORMED";
|
|
358
358
|
/**
|
|
359
|
-
* An **inversion** of a directional crosswalk was requested
|
|
359
|
+
* An **inversion** of a directional crosswalk was requested: a forbidden operation. The GEMs and
|
|
360
360
|
* the SNOMED→ICD-10-CM map are authoritative in **one direction only**; a forward map is not the
|
|
361
361
|
* inverse of the backward map. Thrown by {@link ../crosswalk/gems.invertGem} so the
|
|
362
362
|
* never-invert refusal is a first-class, discoverable contract rather than a silent absence.
|
|
@@ -364,7 +364,7 @@ declare const FATAL_CODES: {
|
|
|
364
364
|
readonly TERM_MAP_NOT_INVERTIBLE: "TERM_MAP_NOT_INVERTIBLE";
|
|
365
365
|
};
|
|
366
366
|
/**
|
|
367
|
-
* A value from {@link FATAL_CODES}
|
|
367
|
+
* A value from {@link FATAL_CODES}: the type carried by a thrown {@link TerminologyError}.
|
|
368
368
|
*/
|
|
369
369
|
type FatalCode = (typeof FATAL_CODES)[keyof typeof FATAL_CODES];
|
|
370
370
|
/**
|
|
@@ -372,7 +372,7 @@ type FatalCode = (typeof FATAL_CODES)[keyof typeof FATAL_CODES];
|
|
|
372
372
|
* without string-matching the message. Thrown only for {@link FATAL_CODES} conditions.
|
|
373
373
|
*
|
|
374
374
|
* The `message` is **value-free**: it names the structural fault (a resource path, a missing field,
|
|
375
|
-
* the *role* of a configured column) and never echoes an input value
|
|
375
|
+
* the *role* of a configured column) and never echoes an input value, so it is safe to log, and
|
|
376
376
|
* safe in an `err.stack` that reaches an error reporter. The rule the strings are built by is in
|
|
377
377
|
* this module's docblock above.
|
|
378
378
|
*
|
|
@@ -393,7 +393,7 @@ declare class TerminologyError extends Error {
|
|
|
393
393
|
/**
|
|
394
394
|
* @param code - The stable {@link FatalCode} describing the fault.
|
|
395
395
|
* @param message - A **value-free** structural description (path + fault; never an input value).
|
|
396
|
-
* Every piece of it must be engine-owned
|
|
396
|
+
* Every piece of it must be engine-owned: a literal, a frozen-table entry, or a locus this
|
|
397
397
|
* package built. This string reaches `err.stack`, so interpolating a caller-supplied or
|
|
398
398
|
* document-derived value into it is how a diagnostic becomes a leak.
|
|
399
399
|
*/
|
|
@@ -407,7 +407,7 @@ declare class TerminologyError extends Error {
|
|
|
407
407
|
* The engine never trusts the shape of its inputs: every accessor here narrows an `unknown`
|
|
408
408
|
* to a concrete type or returns `undefined`, so a malformed resource degrades to a typed
|
|
409
409
|
* diagnostic (see {@link ../conceptmap/load}) rather than a `TypeError` deep in a getter. This
|
|
410
|
-
* is the terminology-engine analogue of a parser's lenient tokenizer
|
|
410
|
+
* is the terminology-engine analogue of a parser's lenient tokenizer: liberal on load.
|
|
411
411
|
*
|
|
412
412
|
* These helpers are **value-free**: they read structure, never log or echo field *values*, so a
|
|
413
413
|
* code-in-context (which can be PHI) never flows into a message.
|
|
@@ -444,7 +444,7 @@ declare function getString(obj: unknown, key: string): string | undefined;
|
|
|
444
444
|
/**
|
|
445
445
|
* Read an **array** property from an untrusted object as a `readonly unknown[]`, or `undefined`.
|
|
446
446
|
*
|
|
447
|
-
* The elements are left as `unknown
|
|
447
|
+
* The elements are left as `unknown`: callers narrow each one. A non-array (including a missing
|
|
448
448
|
* key) yields `undefined`, which callers treat as "no entries" rather than an error.
|
|
449
449
|
*
|
|
450
450
|
* @param obj - The source object (may be any `unknown`).
|
|
@@ -461,7 +461,7 @@ declare function getArray(obj: unknown, key: string): readonly unknown[] | undef
|
|
|
461
461
|
/**
|
|
462
462
|
* Read a **boolean** property from an untrusted object, or `undefined` if absent/not a boolean.
|
|
463
463
|
*
|
|
464
|
-
* A non-boolean (including a missing key, or the strings `"true"`/`"false"`) yields `undefined
|
|
464
|
+
* A non-boolean (including a missing key, or the strings `"true"`/`"false"`) yields `undefined`:
|
|
465
465
|
* the accessor never coerces, so a caller can distinguish "explicitly `false`" from "absent".
|
|
466
466
|
*
|
|
467
467
|
* @param obj - The source object (may be any `unknown`).
|
|
@@ -491,41 +491,41 @@ declare function getBoolean(obj: unknown, key: string): boolean | undefined;
|
|
|
491
491
|
declare function getNumber(obj: unknown, key: string): number | undefined;
|
|
492
492
|
|
|
493
493
|
/**
|
|
494
|
-
* The **code-system identity registry
|
|
494
|
+
* The **code-system identity registry**: the grounded OID ↔ canonical-URI ↔ mnemonic facts the
|
|
495
495
|
* ecosystem uses.
|
|
496
496
|
*
|
|
497
497
|
* A code-system *identity* (the triple of canonical URI, OID, and HL7 v2 mnemonic that all name
|
|
498
|
-
* the same terminology) is a **published identifier** for the system, not the system's code list
|
|
498
|
+
* the same terminology) is a **published identifier** for the system, not the system's code list, so
|
|
499
499
|
* it is encoded here, cited firsthand. That is where the line falls: identities are encoded; the code
|
|
500
500
|
* *lists themselves* (SNOMED CT / CPT / LOINC content) are BYO and never bundled.
|
|
501
501
|
*
|
|
502
502
|
* **Every identity below is grounded firsthand against a primary source** (verified 2026-07-21):
|
|
503
503
|
*
|
|
504
|
-
* - The FHIR R4 terminology-systems registry
|
|
505
|
-
*
|
|
504
|
+
* - The FHIR R4 terminology-systems registry (`https://hl7.org/fhir/R4/terminologies-systems.html`)
|
|
505
|
+
* for LOINC, SNOMED CT, RxNorm, UCUM, CPT, NDC, CVX (canonical URI + OID), and for the HL7 v2
|
|
506
506
|
* table URI/OID patterns (`http://terminology.hl7.org/CodeSystem/v2-[X]` ↔
|
|
507
507
|
* `2.16.840.1.113883.12.[X]`).
|
|
508
|
-
* - The FHIR R4 ICD page
|
|
508
|
+
* - The FHIR R4 ICD page (`https://hl7.org/fhir/R4/icd.html`) for ICD-10-CM
|
|
509
509
|
* (`http://hl7.org/fhir/sid/icd-10-cm` ↔ `2.16.840.1.113883.6.90`).
|
|
510
|
-
* - HL7 Table 0396 (coding-system mnemonics)
|
|
510
|
+
* - HL7 Table 0396 (coding-system mnemonics), the THO `v2-0396` code system, for the mnemonics
|
|
511
511
|
* (`LN`, `SCT`, `I10C`, `RXNORM`, `UCUM`, `C4`, `NDC`, `CVX`).
|
|
512
512
|
*
|
|
513
513
|
* Identities that could not be pinned to a primary source firsthand are **omitted**, not
|
|
514
|
-
* guessed
|
|
514
|
+
* guessed: notably ICD-9-CM and ICD-10-PCS, whose OID
|
|
515
515
|
* assignments were ambiguous across sources.
|
|
516
516
|
*
|
|
517
517
|
* @packageDocumentation
|
|
518
518
|
*/
|
|
519
519
|
/**
|
|
520
|
-
* A resolved code-system identity
|
|
520
|
+
* A resolved code-system identity: the canonical URI plus the alternate identifiers that name the
|
|
521
521
|
* same system.
|
|
522
522
|
*/
|
|
523
523
|
interface SystemIdentity {
|
|
524
|
-
/** The canonical URI
|
|
524
|
+
/** The canonical URI: the single value the engine treats as the system's identity. */
|
|
525
525
|
readonly url: string;
|
|
526
526
|
/** The registered OID (bare, no `urn:oid:` prefix), when the system has one. */
|
|
527
527
|
readonly oid?: string;
|
|
528
|
-
/** A short human-readable name for diagnostics/logs (value-free
|
|
528
|
+
/** A short human-readable name for diagnostics/logs (value-free, a system name, never a value). */
|
|
529
529
|
readonly name: string;
|
|
530
530
|
/** HL7 v2 Table 0396 mnemonic(s) and other accepted short aliases for this system. */
|
|
531
531
|
readonly mnemonics: readonly string[];
|
|
@@ -537,33 +537,33 @@ interface SystemIdentity {
|
|
|
537
537
|
declare const SYSTEM_IDENTITIES: readonly SystemIdentity[];
|
|
538
538
|
/**
|
|
539
539
|
* The OID root under which every HL7 v2 table code system is registered:
|
|
540
|
-
* `2.16.840.1.113883.12.[table]
|
|
540
|
+
* `2.16.840.1.113883.12.[table]`: grounded against the FHIR R4 terminology-systems registry.
|
|
541
541
|
* The table number is appended with no leading zeros (e.g. table 0203 → `…12.203`).
|
|
542
542
|
*/
|
|
543
543
|
declare const HL7_V2_OID_ROOT = "2.16.840.1.113883.12";
|
|
544
544
|
/**
|
|
545
545
|
* The canonical URI prefix for HL7 v2 table code systems in HL7 Terminology (THO):
|
|
546
546
|
* `http://terminology.hl7.org/CodeSystem/v2-[XXXX]`, where `[XXXX]` is the zero-padded 4-digit
|
|
547
|
-
* table id
|
|
547
|
+
* table id: grounded against the FHIR R4 terminology-systems registry.
|
|
548
548
|
*/
|
|
549
549
|
declare const HL7_V2_URL_PREFIX = "http://terminology.hl7.org/CodeSystem/v2-";
|
|
550
550
|
|
|
551
551
|
/**
|
|
552
|
-
* The **code-system identity / canonical-URI resolver
|
|
552
|
+
* The **code-system identity / canonical-URI resolver**: `resolveSystem`.
|
|
553
553
|
*
|
|
554
|
-
* Given a code system named any of the ways the ecosystem names it
|
|
555
|
-
* or `urn:oid:`-prefixed), or an HL7 v2 mnemonic (`LN`, `SCT`, …)
|
|
554
|
+
* Given a code system named any of the ways the ecosystem names it, whether a canonical URI, an OID
|
|
555
|
+
* (bare or `urn:oid:`-prefixed), or an HL7 v2 mnemonic (`LN`, `SCT`, …), it returns the one canonical
|
|
556
556
|
* {@link SystemIdentity}. This is the piece `@cosyte/transform` pins so a `Coding` off any parser
|
|
557
557
|
* (HL7 v2 CE/CWE, C-CDA, FHIR) can be canonicalized to a single system URI before translation.
|
|
558
558
|
*
|
|
559
559
|
* **Never guesses.** An identifier that matches nothing known returns a typed
|
|
560
|
-
* `{ unknown: true, input }
|
|
560
|
+
* `{ unknown: true, input }`: never a fabricated URI (the never-fabricate invariant, applied to
|
|
561
561
|
* system identity).
|
|
562
562
|
*
|
|
563
563
|
* @packageDocumentation
|
|
564
564
|
*/
|
|
565
565
|
|
|
566
|
-
/** The typed "not recognized" outcome from {@link resolveSystem}
|
|
566
|
+
/** The typed "not recognized" outcome from {@link resolveSystem}: surfaced, never a guess. */
|
|
567
567
|
interface UnknownSystem {
|
|
568
568
|
/** Discriminant: the identifier was not recognized. */
|
|
569
569
|
readonly unknown: true;
|
|
@@ -578,7 +578,7 @@ type ResolveSystemResult = SystemIdentity | UnknownSystem;
|
|
|
578
578
|
* Accepts, in order of attempt: a canonical URI (case-insensitive), a `v2-XXXX` mnemonic or a
|
|
579
579
|
* v2 table URI/OID (resolved structurally), a bare or `urn:oid:`-prefixed OID, or an HL7 v2
|
|
580
580
|
* Table 0396 mnemonic. Whitespace is trimmed. An empty or unrecognized identifier yields a typed
|
|
581
|
-
* {@link UnknownSystem}
|
|
581
|
+
* {@link UnknownSystem}: the resolver **never** invents a URI.
|
|
582
582
|
*
|
|
583
583
|
* @param id - The identifier (canonical URI, OID, `urn:oid:` OID, or mnemonic).
|
|
584
584
|
* @returns The resolved {@link SystemIdentity}, or `{ unknown: true, input }`.
|
|
@@ -607,7 +607,7 @@ declare function resolveSystem(id: string): ResolveSystemResult;
|
|
|
607
607
|
declare function isUnknownSystem(result: ResolveSystemResult): result is UnknownSystem;
|
|
608
608
|
|
|
609
609
|
/**
|
|
610
|
-
* The types for the ConceptMap `$translate` engine
|
|
610
|
+
* The types for the ConceptMap `$translate` engine: the loaded {@link ConceptMap} model, the
|
|
611
611
|
* normalized {@link Relationship} enum, and the fail-safe {@link TranslateResult}.
|
|
612
612
|
*
|
|
613
613
|
* The engine targets **FHIR R4** ConceptMap input (`element.target.equivalence`), but carries an
|
|
@@ -627,7 +627,7 @@ declare function isUnknownSystem(result: ResolveSystemResult): result is Unknown
|
|
|
627
627
|
*/
|
|
628
628
|
type R4Equivalence = "relatedto" | "equivalent" | "equal" | "wider" | "subsumes" | "narrower" | "specializes" | "inexact" | "unmatched" | "disjoint";
|
|
629
629
|
/**
|
|
630
|
-
* The engine's **normalized, version-neutral relationship** between a source and a target concept
|
|
630
|
+
* The engine's **normalized, version-neutral relationship** between a source and a target concept:
|
|
631
631
|
* the FHIR **R5** vocabulary, which the R4 `equivalence` tokens fold into cleanly. Surfaced on every
|
|
632
632
|
* match alongside the verbatim R4 token.
|
|
633
633
|
*
|
|
@@ -640,7 +640,7 @@ type R4Equivalence = "relatedto" | "equivalent" | "equal" | "wider" | "subsumes"
|
|
|
640
640
|
type Relationship = "equivalent" | "source-is-narrower-than-target" | "source-is-broader-than-target" | "related-to" | "not-related-to";
|
|
641
641
|
/**
|
|
642
642
|
* One target concept a {@link translate} call produced, with its relationship to the source and
|
|
643
|
-
* the verbatim R4 equivalence token. Never fabricated
|
|
643
|
+
* the verbatim R4 equivalence token. Never fabricated: every field is drawn from the loaded map.
|
|
644
644
|
*/
|
|
645
645
|
interface TranslateMatch {
|
|
646
646
|
/** The target {@link Coding} exactly as declared in the map (frozen). */
|
|
@@ -653,17 +653,17 @@ interface TranslateMatch {
|
|
|
653
653
|
readonly comment?: string;
|
|
654
654
|
}
|
|
655
655
|
/**
|
|
656
|
-
* The FHIR R4 `group.unmapped.mode` an unmapped source fell through to
|
|
656
|
+
* The FHIR R4 `group.unmapped.mode` an unmapped source fell through to: the map author's declared
|
|
657
657
|
* fallback behavior. Surfaced (never silently acted on): the caller decides whether to trust a
|
|
658
658
|
* fallback.
|
|
659
659
|
*
|
|
660
|
-
* - `provided
|
|
661
|
-
* - `fixed
|
|
662
|
-
* - `other-map
|
|
663
|
-
* - `none
|
|
660
|
+
* - `provided`: echo the source code as the target (the map declares no real mapping).
|
|
661
|
+
* - `fixed`: a single fixed fallback code the map declares for *all* unmapped sources.
|
|
662
|
+
* - `other-map`: consult the referenced ConceptMap (which this engine does not auto-follow).
|
|
663
|
+
* - `none`: no `group.unmapped` directive applied (plain no-match, or an explicit `unmatched`).
|
|
664
664
|
*/
|
|
665
665
|
type UnmappedMode = "provided" | "fixed" | "other-map" | "none";
|
|
666
|
-
/** Provenance of a translation
|
|
666
|
+
/** Provenance of a translation, which map (and which group's systems) produced it. */
|
|
667
667
|
interface MapProvenance {
|
|
668
668
|
/** The ConceptMap's canonical `url`, when declared. */
|
|
669
669
|
readonly conceptMapUrl?: string;
|
|
@@ -690,9 +690,9 @@ interface TranslateMatched {
|
|
|
690
690
|
readonly provenance: MapProvenance;
|
|
691
691
|
}
|
|
692
692
|
/**
|
|
693
|
-
* A **fail-safe unmapped** translation
|
|
693
|
+
* A **fail-safe unmapped** translation: the never-fabricate outcome. The source is surfaced as-is;
|
|
694
694
|
* **no target is ever guessed**. Any `group.unmapped` fallback the author declared is reported via
|
|
695
|
-
* {@link UnmappedMode} (and `fixedTarget`/`otherMapUrl`) for the caller to accept or reject
|
|
695
|
+
* {@link UnmappedMode} (and `fixedTarget`/`otherMapUrl`) for the caller to accept or reject: the
|
|
696
696
|
* engine does not silently substitute it.
|
|
697
697
|
*/
|
|
698
698
|
interface TranslateUnmapped {
|
|
@@ -704,9 +704,9 @@ interface TranslateUnmapped {
|
|
|
704
704
|
readonly mode: UnmappedMode;
|
|
705
705
|
/** The original source {@link Coding}, surfaced untouched. */
|
|
706
706
|
readonly source: Coding;
|
|
707
|
-
/** For `mode: "fixed"`, the author's fixed fallback coding
|
|
707
|
+
/** For `mode: "fixed"`, the author's fixed fallback coding: reported, not auto-applied. */
|
|
708
708
|
readonly fixedTarget?: Coding;
|
|
709
|
-
/** For `mode: "other-map"`, the referenced map's URL
|
|
709
|
+
/** For `mode: "other-map"`, the referenced map's URL: reported, not auto-followed. */
|
|
710
710
|
readonly otherMapUrl?: string;
|
|
711
711
|
/** Where the (failed) translation was attempted. */
|
|
712
712
|
readonly provenance: MapProvenance;
|
|
@@ -726,7 +726,7 @@ interface ConceptMapUnmapped {
|
|
|
726
726
|
/** For `other-map`, the canonical URL of the map to consult. */
|
|
727
727
|
readonly url?: string;
|
|
728
728
|
}
|
|
729
|
-
/** One `group.element.target
|
|
729
|
+
/** One `group.element.target`: a candidate target for a source concept (FHIR R4). */
|
|
730
730
|
interface ConceptMapTarget {
|
|
731
731
|
/** The target code (absent for a pure `unmatched` assertion). */
|
|
732
732
|
readonly code?: string;
|
|
@@ -737,7 +737,7 @@ interface ConceptMapTarget {
|
|
|
737
737
|
/** Author's comment (e.g. steward map advice), carried verbatim. */
|
|
738
738
|
readonly comment?: string;
|
|
739
739
|
}
|
|
740
|
-
/** One `group.element
|
|
740
|
+
/** One `group.element`: a source concept and its candidate targets (FHIR R4). */
|
|
741
741
|
interface ConceptMapElement {
|
|
742
742
|
/** The source code. */
|
|
743
743
|
readonly code?: string;
|
|
@@ -746,7 +746,7 @@ interface ConceptMapElement {
|
|
|
746
746
|
/** The candidate targets. */
|
|
747
747
|
readonly target: readonly ConceptMapTarget[];
|
|
748
748
|
}
|
|
749
|
-
/** One `group
|
|
749
|
+
/** One `group`: a source-system/target-system pair with its element mappings (FHIR R4). */
|
|
750
750
|
interface ConceptMapGroup {
|
|
751
751
|
/** The group's source code system (canonical URI), when declared. */
|
|
752
752
|
readonly source?: string;
|
|
@@ -762,7 +762,7 @@ interface ConceptMapGroup {
|
|
|
762
762
|
readonly unmapped?: ConceptMapUnmapped;
|
|
763
763
|
}
|
|
764
764
|
/**
|
|
765
|
-
* A loaded, immutable ConceptMap
|
|
765
|
+
* A loaded, immutable ConceptMap: the subset of the FHIR R4 `ConceptMap` resource the
|
|
766
766
|
* `$translate` engine needs. Produced by {@link loadConceptMap}; every field frozen.
|
|
767
767
|
*/
|
|
768
768
|
interface ConceptMap {
|
|
@@ -779,13 +779,13 @@ interface ConceptMap {
|
|
|
779
779
|
}
|
|
780
780
|
|
|
781
781
|
/**
|
|
782
|
-
* {@link loadConceptMap}
|
|
782
|
+
* {@link loadConceptMap}: validate and normalize an untrusted FHIR R4 `ConceptMap` JSON resource
|
|
783
783
|
* into the immutable {@link ConceptMap} model the `$translate` engine runs over.
|
|
784
784
|
*
|
|
785
785
|
* **Conservative on load** (unlike a wire parser's lenient posture): a ConceptMap drives a clinical
|
|
786
786
|
* translation, so a structurally unusable map is a typed **fatal**
|
|
787
787
|
* ({@link FATAL_CODES.TERM_CONCEPTMAP_MALFORMED}), never a silently partial map that would translate
|
|
788
|
-
* *some* codes and quietly drop others. Fault messages are **value-free
|
|
788
|
+
* *some* codes and quietly drop others. Fault messages are **value-free**: they name the resource
|
|
789
789
|
* *path* and the fault, never echo a code or display *value*.
|
|
790
790
|
*
|
|
791
791
|
* @packageDocumentation
|
|
@@ -799,7 +799,7 @@ interface ConceptMap {
|
|
|
799
799
|
* variant. The result is deep-frozen. Anything structurally unusable throws a
|
|
800
800
|
* {@link TerminologyError} carrying {@link FATAL_CODES.TERM_CONCEPTMAP_MALFORMED}.
|
|
801
801
|
*
|
|
802
|
-
* @param json - The untrusted resource (typically `JSON.parse` output
|
|
802
|
+
* @param json - The untrusted resource (typically `JSON.parse` output, hence `unknown`).
|
|
803
803
|
* @returns The immutable, validated {@link ConceptMap}.
|
|
804
804
|
* @throws {TerminologyError} `TERM_CONCEPTMAP_MALFORMED` when the resource is not a usable ConceptMap.
|
|
805
805
|
* @example
|
|
@@ -823,18 +823,18 @@ interface ConceptMap {
|
|
|
823
823
|
declare function loadConceptMap(json: unknown): ConceptMap;
|
|
824
824
|
|
|
825
825
|
/**
|
|
826
|
-
* {@link translate}
|
|
826
|
+
* {@link translate}: the ConceptMap `$translate` engine, modeled on the FHIR
|
|
827
827
|
* `ConceptMap/$translate` operation.
|
|
828
828
|
*
|
|
829
829
|
* Given a source {@link Coding} and a loaded {@link ConceptMap}, it returns the declared target
|
|
830
|
-
* code(s) with their FHIR relationship and the map's provenance
|
|
830
|
+
* code(s) with their FHIR relationship and the map's provenance, or, when the source does not map,
|
|
831
831
|
* a **typed {@link TranslateUnmapped}**. Two invariants govern it:
|
|
832
832
|
*
|
|
833
|
-
* 1. **Never fabricate.** An unmapped source yields a surfaced `unmapped` result
|
|
833
|
+
* 1. **Never fabricate.** An unmapped source yields a surfaced `unmapped` result: never a guessed
|
|
834
834
|
* target. Every target returned is drawn verbatim from the map; the engine invents nothing.
|
|
835
835
|
* 2. **Never invert.** Translation reads the map in its authored direction only: a source coding is
|
|
836
836
|
* matched against `group.element.code` (the source side) and **never** against target codes. A
|
|
837
|
-
* directional map therefore cannot be run backwards
|
|
837
|
+
* directional map therefore cannot be run backwards: reverse translation requires an explicit
|
|
838
838
|
* inverse map; it is never synthesized here.
|
|
839
839
|
*
|
|
840
840
|
* @packageDocumentation
|
|
@@ -843,16 +843,16 @@ declare function loadConceptMap(json: unknown): ConceptMap;
|
|
|
843
843
|
/**
|
|
844
844
|
* Translate a source {@link Coding} through a loaded {@link ConceptMap}.
|
|
845
845
|
*
|
|
846
|
-
* Matches the coding's `code` against each applicable group's `element.code` (the **source** side
|
|
846
|
+
* Matches the coding's `code` against each applicable group's `element.code` (the **source** side,
|
|
847
847
|
* never targets, so the map is never inverted) and returns every declared target for it. A target
|
|
848
|
-
* with an `unmatched` equivalence, or with no `code`, is treated as "no target"
|
|
849
|
-
* asserting a non-mapping
|
|
848
|
+
* with an `unmatched` equivalence, or with no `code`, is treated as "no target" (the FHIR way of
|
|
849
|
+
* asserting a non-mapping), and does not count as a match. When nothing matches, the map author's
|
|
850
850
|
* `group.unmapped` directive (if any) is *reported* via the result's {@link UnmappedMode} but never
|
|
851
851
|
* silently applied.
|
|
852
852
|
*
|
|
853
853
|
* @param sourceCoding - The source concept to translate.
|
|
854
854
|
* @param map - A {@link ConceptMap} from {@link loadConceptMap}.
|
|
855
|
-
* @returns A {@link TranslateResult}
|
|
855
|
+
* @returns A {@link TranslateResult}: matched targets, or a typed unmapped outcome.
|
|
856
856
|
* @example
|
|
857
857
|
* ```ts
|
|
858
858
|
* import { loadConceptMap, translate } from "@cosyte/terminology";
|
|
@@ -883,7 +883,7 @@ declare function translate(sourceCoding: Coding, map: ConceptMap): TranslateResu
|
|
|
883
883
|
*
|
|
884
884
|
* The model is **content-agnostic**: it is fed a code system's *release* (a consumer-supplied RRF,
|
|
885
885
|
* CSV, fixed-width file, or FHIR `CodeSystem` JSON) and answers the two identity questions. It ships
|
|
886
|
-
* **no code-system release
|
|
886
|
+
* **no code-system release**: every concept comes from the caller's data (the BYO-data posture).
|
|
887
887
|
* The FHIR operation shapes are grounded firsthand on the FHIR R4 Terminology Module
|
|
888
888
|
* (`https://hl7.org/fhir/R4/codesystem-operation-lookup.html`,
|
|
889
889
|
* `https://hl7.org/fhir/R4/codesystem-operation-validate-code.html`).
|
|
@@ -892,20 +892,20 @@ declare function translate(sourceCoding: Coding, map: ConceptMap): TranslateResu
|
|
|
892
892
|
*/
|
|
893
893
|
|
|
894
894
|
/**
|
|
895
|
-
* A concept's normalized activity
|
|
895
|
+
* A concept's normalized activity: whether it is a clean, current, usable code, or carries a
|
|
896
896
|
* steward status that a caller must not ignore. `active` is the boolean convenience derived from it.
|
|
897
897
|
*
|
|
898
|
-
* - `active
|
|
899
|
-
* - `deprecated
|
|
900
|
-
* - `discouraged` / `trial
|
|
901
|
-
* - `obsolete
|
|
902
|
-
* - `suppressed
|
|
903
|
-
* - `header
|
|
904
|
-
* - `unknown
|
|
898
|
+
* - `active`: current and usable.
|
|
899
|
+
* - `deprecated`: no longer current (LOINC `DEPRECATED`; a FHIR `inactive`/`deprecated` concept).
|
|
900
|
+
* - `discouraged` / `trial`: LOINC lifecycle states (usable, but not settled).
|
|
901
|
+
* - `obsolete`: withdrawn (RxNorm `SUPPRESS = O`).
|
|
902
|
+
* - `suppressed`: editor-suppressed (RxNorm/UMLS `SUPPRESS = Y`/`E`).
|
|
903
|
+
* - `header`: a classification header, **not a billable/valid leaf** (ICD-10-CM flag `0`).
|
|
904
|
+
* - `unknown`: a status token the mapper did not recognize; carried verbatim, never guessed clean.
|
|
905
905
|
*/
|
|
906
906
|
type ConceptActivity = "active" | "deprecated" | "discouraged" | "trial" | "obsolete" | "suppressed" | "header" | "unknown";
|
|
907
907
|
/**
|
|
908
|
-
* The status flags a `$lookup`/`$validate-code` carries on a concept
|
|
908
|
+
* The status flags a `$lookup`/`$validate-code` carries on a concept: the safety surface that stops
|
|
909
909
|
* a non-current or non-billable code from being presented as clean. Present only when
|
|
910
910
|
* the loaded release supplied status information; the engine never fabricates a status.
|
|
911
911
|
*/
|
|
@@ -922,7 +922,7 @@ interface ConceptStatus {
|
|
|
922
922
|
readonly code?: DiagnosticCode;
|
|
923
923
|
}
|
|
924
924
|
/**
|
|
925
|
-
* One property value on a concept
|
|
925
|
+
* One property value on a concept: models FHIR R4 `$lookup` `property` ("one or more properties
|
|
926
926
|
* that contain additional information about the code, including status"). Carried verbatim from the
|
|
927
927
|
* release; never fabricated.
|
|
928
928
|
*/
|
|
@@ -935,7 +935,7 @@ interface Property {
|
|
|
935
935
|
readonly description?: string;
|
|
936
936
|
}
|
|
937
937
|
/**
|
|
938
|
-
* One loaded, immutable concept
|
|
938
|
+
* One loaded, immutable concept: the subset of a `CodeSystem.concept` the operations need.
|
|
939
939
|
*/
|
|
940
940
|
interface Concept {
|
|
941
941
|
/** The code, exactly as it appears in the release. */
|
|
@@ -950,7 +950,7 @@ interface Concept {
|
|
|
950
950
|
readonly properties: readonly Property[];
|
|
951
951
|
}
|
|
952
952
|
/**
|
|
953
|
-
* A surfaced, non-fatal load warning
|
|
953
|
+
* A surfaced, non-fatal load warning: a malformed row that was **skipped**, reported with its line
|
|
954
954
|
* number and a **value-free** structural reason (never the row's content). Liberal on load.
|
|
955
955
|
*/
|
|
956
956
|
interface LoadWarning {
|
|
@@ -962,14 +962,14 @@ interface LoadWarning {
|
|
|
962
962
|
readonly detail: string;
|
|
963
963
|
}
|
|
964
964
|
/**
|
|
965
|
-
* A loaded, immutable code-system release
|
|
965
|
+
* A loaded, immutable code-system release: the queryable model {@link loadCodeSystem} produces and
|
|
966
966
|
* {@link lookup} / {@link validateCode} run over. Concepts are keyed by code for O(1) identity, and
|
|
967
967
|
* every concept is frozen.
|
|
968
968
|
*/
|
|
969
969
|
interface CodeSystem {
|
|
970
970
|
/** The code system's canonical URI, when supplied by the source. */
|
|
971
971
|
readonly url?: string;
|
|
972
|
-
/** The release version, when supplied
|
|
972
|
+
/** The release version, when supplied: mappings and displays are release-scoped. */
|
|
973
973
|
readonly version?: string;
|
|
974
974
|
/** A short human-readable name, when supplied. */
|
|
975
975
|
readonly name?: string;
|
|
@@ -980,7 +980,7 @@ interface CodeSystem {
|
|
|
980
980
|
* iteration behave as a `Map`'s do, adding / deleting / clearing is refused however it is
|
|
981
981
|
* attempted, and every value is frozen.
|
|
982
982
|
*
|
|
983
|
-
* A view is not a `Map` instance
|
|
983
|
+
* A view is not a `Map` instance: `instanceof Map` is `false` and this model cannot be
|
|
984
984
|
* `structuredClone`d or posted to a worker; copy out what you need (`new Map(…)`).
|
|
985
985
|
*/
|
|
986
986
|
readonly concepts: ReadonlyMap<string, Concept>;
|
|
@@ -1006,7 +1006,7 @@ interface LookupResult {
|
|
|
1006
1006
|
/** The release version, when known. */
|
|
1007
1007
|
readonly version?: string;
|
|
1008
1008
|
}
|
|
1009
|
-
/** A **fail-safe unknown** {@link lookup}
|
|
1009
|
+
/** A **fail-safe unknown** {@link lookup}: the never-fabricate outcome; no display is ever guessed. */
|
|
1010
1010
|
interface LookupUnknown {
|
|
1011
1011
|
/** Discriminant: the code was not found. */
|
|
1012
1012
|
readonly found: false;
|
|
@@ -1018,7 +1018,7 @@ interface LookupUnknown {
|
|
|
1018
1018
|
/** The result of {@link lookup}: a found concept or a typed {@link LookupUnknown}. */
|
|
1019
1019
|
type LookupOutcome = LookupResult | LookupUnknown;
|
|
1020
1020
|
/**
|
|
1021
|
-
* The result of {@link validateCode}
|
|
1021
|
+
* The result of {@link validateCode}: models FHIR R4 `$validate-code`'s `result` boolean. A found
|
|
1022
1022
|
* concept is `valid: true` **carrying its status** (a deprecated or header code validates as present
|
|
1023
1023
|
* but is flagged, never presented clean); an absent code is `valid: false`, never a guessed `true`.
|
|
1024
1024
|
*/
|
|
@@ -1058,9 +1058,9 @@ interface RrfColumnMap {
|
|
|
1058
1058
|
readonly properties?: readonly RrfPropertyColumn[];
|
|
1059
1059
|
}
|
|
1060
1060
|
/**
|
|
1061
|
-
* An **RRF** (Rich Release Format
|
|
1061
|
+
* An **RRF** (Rich Release Format, pipe-delimited RxNorm/UMLS release) source. One parameterized
|
|
1062
1062
|
* reader serves both: RxNorm `RXNCONSO`/`RXNSAT` and UMLS `MRCONSO`/`MRSAT` share the RRF shape
|
|
1063
|
-
* (pipe-delimited, one trailing pipe per line). BYO
|
|
1063
|
+
* (pipe-delimited, one trailing pipe per line). BYO: the consumer supplies the file.
|
|
1064
1064
|
*/
|
|
1065
1065
|
interface RrfSource {
|
|
1066
1066
|
/** Discriminant. */
|
|
@@ -1073,7 +1073,7 @@ interface RrfSource {
|
|
|
1073
1073
|
readonly url?: string;
|
|
1074
1074
|
/** A human-readable name. */
|
|
1075
1075
|
readonly name?: string;
|
|
1076
|
-
/** The release version (RRF carries none inline
|
|
1076
|
+
/** The release version (RRF carries none inline, supply it so displays stay release-scoped). */
|
|
1077
1077
|
readonly version?: string;
|
|
1078
1078
|
/** Override the default status interpretation of the `status` column's raw token. */
|
|
1079
1079
|
readonly statusMap?: StatusMapper;
|
|
@@ -1090,7 +1090,7 @@ interface CsvColumnMap {
|
|
|
1090
1090
|
readonly properties?: readonly string[];
|
|
1091
1091
|
}
|
|
1092
1092
|
/**
|
|
1093
|
-
* An **RFC-4180 CSV** source (quoted fields, embedded commas/quotes/newlines)
|
|
1093
|
+
* An **RFC-4180 CSV** source (quoted fields, embedded commas/quotes/newlines): e.g. LOINC's
|
|
1094
1094
|
* `Loinc.csv`. The one release format that needs real quote handling; hand-rolled, zero-dep. BYO.
|
|
1095
1095
|
*/
|
|
1096
1096
|
interface CsvSource {
|
|
@@ -1137,7 +1137,7 @@ interface FixedWidthFieldMap {
|
|
|
1137
1137
|
readonly properties?: readonly FixedWidthPropertyField[];
|
|
1138
1138
|
}
|
|
1139
1139
|
/**
|
|
1140
|
-
* A **fixed-width** source (slice by column)
|
|
1140
|
+
* A **fixed-width** source (slice by column): e.g. the ICD-10-CM order file. Fully parameterized:
|
|
1141
1141
|
* the consumer supplies the field slices (see {@link ICD10CM_ORDER_FILE_FIELDS} for the documented
|
|
1142
1142
|
* ICD-10-CM preset, which they confirm against their release's README, since the byte offsets are
|
|
1143
1143
|
* not confirmed against an authoritative machine-readable source). BYO.
|
|
@@ -1166,14 +1166,14 @@ interface FixedWidthSource {
|
|
|
1166
1166
|
interface FhirCodeSystemSource {
|
|
1167
1167
|
/** Discriminant. */
|
|
1168
1168
|
readonly format: "fhir";
|
|
1169
|
-
/** The untrusted FHIR `CodeSystem` resource (typically `JSON.parse` output
|
|
1169
|
+
/** The untrusted FHIR `CodeSystem` resource (typically `JSON.parse` output, hence `unknown`). */
|
|
1170
1170
|
readonly resource: unknown;
|
|
1171
1171
|
}
|
|
1172
1172
|
/** The discriminated union {@link loadCodeSystem} accepts. */
|
|
1173
1173
|
type CodeSystemSource = RrfSource | CsvSource | FixedWidthSource | FhirCodeSystemSource;
|
|
1174
1174
|
|
|
1175
1175
|
/**
|
|
1176
|
-
* {@link loadCodeSystem}
|
|
1176
|
+
* {@link loadCodeSystem}: the single entry point that dispatches a {@link CodeSystemSource} to the
|
|
1177
1177
|
* right reader (RRF / CSV / fixed-width / FHIR) and assembles the immutable {@link CodeSystem}.
|
|
1178
1178
|
*
|
|
1179
1179
|
* The engine is **content-agnostic**: it loads a *consumer-supplied* release and ships
|
|
@@ -1187,10 +1187,10 @@ type CodeSystemSource = RrfSource | CsvSource | FixedWidthSource | FhirCodeSyste
|
|
|
1187
1187
|
* Load a consumer-supplied code-system release into an immutable, queryable {@link CodeSystem}.
|
|
1188
1188
|
*
|
|
1189
1189
|
* Dispatches on `source.format`:
|
|
1190
|
-
* - `"rrf"
|
|
1191
|
-
* - `"csv"
|
|
1192
|
-
* - `"fixed-width"
|
|
1193
|
-
* - `"fhir"
|
|
1190
|
+
* - `"rrf"`: pipe-delimited RxNorm/UMLS release (one parameterized reader for both).
|
|
1191
|
+
* - `"csv"`: RFC-4180 CSV (e.g. LOINC `Loinc.csv`), with real quote handling.
|
|
1192
|
+
* - `"fixed-width"`: slice-by-column order files (e.g. ICD-10-CM; see `ICD10CM_ORDER_FILE_FIELDS`).
|
|
1193
|
+
* - `"fhir"`: a native FHIR R4 `CodeSystem` JSON resource.
|
|
1194
1194
|
*
|
|
1195
1195
|
* **Liberal on load:** a malformed *row* is skipped and surfaced in `warnings` (never a crash, never a
|
|
1196
1196
|
* partial concept). **Conservative on structure:** an unusable *source* (wrong FHIR `resourceType`, or
|
|
@@ -1218,7 +1218,7 @@ type CodeSystemSource = RrfSource | CsvSource | FixedWidthSource | FhirCodeSyste
|
|
|
1218
1218
|
declare function loadCodeSystem(source: CodeSystemSource): CodeSystem;
|
|
1219
1219
|
|
|
1220
1220
|
/**
|
|
1221
|
-
* {@link lookup} and {@link validateCode}
|
|
1221
|
+
* {@link lookup} and {@link validateCode}: the FHIR R4 CodeSystem `$lookup` and `$validate-code`
|
|
1222
1222
|
* operations over a loaded {@link CodeSystem}.
|
|
1223
1223
|
*
|
|
1224
1224
|
* Grounded firsthand on FHIR R4 (`https://hl7.org/fhir/R4/codesystem-operation-lookup.html`,
|
|
@@ -1229,7 +1229,7 @@ declare function loadCodeSystem(source: CodeSystemSource): CodeSystem;
|
|
|
1229
1229
|
* - `$validate-code` returns `result` (*"True if the concept details supplied are valid"*).
|
|
1230
1230
|
*
|
|
1231
1231
|
* Both honor the **never-fabricate invariant**, applied here to code identity: an
|
|
1232
|
-
* unknown code yields a typed `unknown` / `valid: false
|
|
1232
|
+
* unknown code yields a typed `unknown` / `valid: false`: **never** a fabricated display and
|
|
1233
1233
|
* **never** a guessed `valid: true`. A found-but-non-current concept (deprecated, or an ICD-10-CM
|
|
1234
1234
|
* header) validates as present **but carries its status flag**, so a caller never treats it as clean.
|
|
1235
1235
|
*
|
|
@@ -1241,7 +1241,7 @@ declare function loadCodeSystem(source: CodeSystemSource): CodeSystem;
|
|
|
1241
1241
|
*
|
|
1242
1242
|
* @param cs - The loaded {@link CodeSystem}.
|
|
1243
1243
|
* @param code - The code to look up.
|
|
1244
|
-
* @returns A {@link LookupResult} when found, or a typed {@link LookupUnknown}
|
|
1244
|
+
* @returns A {@link LookupResult} when found, or a typed {@link LookupUnknown}: never a guess.
|
|
1245
1245
|
* @example
|
|
1246
1246
|
* ```ts
|
|
1247
1247
|
* import { loadCodeSystem, lookup } from "@cosyte/terminology";
|
|
@@ -1259,7 +1259,7 @@ declare function lookup(cs: CodeSystem, code: string): LookupOutcome;
|
|
|
1259
1259
|
* `$validate-code`: is `code` a valid member of the loaded code system?
|
|
1260
1260
|
*
|
|
1261
1261
|
* A found code is `valid: true`, **carrying its status** (a deprecated or header code is present but
|
|
1262
|
-
* flagged
|
|
1262
|
+
* flagged: never silently clean). An absent code is `valid: false` with `TERM_CODE_UNKNOWN`, never a
|
|
1263
1263
|
* guessed `true`.
|
|
1264
1264
|
*
|
|
1265
1265
|
* @param cs - The loaded {@link CodeSystem}.
|
|
@@ -1280,14 +1280,14 @@ declare function lookup(cs: CodeSystem, code: string): LookupOutcome;
|
|
|
1280
1280
|
declare function validateCode(cs: CodeSystem, code: string): ValidateCodeResult;
|
|
1281
1281
|
|
|
1282
1282
|
/**
|
|
1283
|
-
* The **RRF** (Rich Release Format) reader
|
|
1283
|
+
* The **RRF** (Rich Release Format) reader: the pipe-delimited layer shared by RxNorm (`RXNCONSO`/
|
|
1284
1284
|
* `RXNSAT`) and UMLS (`MRCONSO`/`MRSAT`). One parameterized reader serves both: they share the RRF
|
|
1285
|
-
* shape
|
|
1285
|
+
* shape: fields separated by `|`, with **one trailing pipe per line** (grounded firsthand on the
|
|
1286
1286
|
* UMLS Reference Manual, `https://www.ncbi.nlm.nih.gov/books/NBK9685/`: *"values … are separated by
|
|
1287
1287
|
* vertical bars (|)"* and each row ends with *"a vertical bar and line termination"*).
|
|
1288
1288
|
*
|
|
1289
1289
|
* **Liberal on load**: a row too short to reach a configured column, or with an empty
|
|
1290
|
-
* code, is **skipped and surfaced** as a `TERM_RRF_MALFORMED_ROW` warning
|
|
1290
|
+
* code, is **skipped and surfaced** as a `TERM_RRF_MALFORMED_ROW` warning: never kept as a partial
|
|
1291
1291
|
* concept, never a crash. RRF reserves `|` as the delimiter (fields never contain a literal pipe), so
|
|
1292
1292
|
* a plain split is exact.
|
|
1293
1293
|
*
|
|
@@ -1311,7 +1311,7 @@ declare function parseRrfLine(line: string): readonly string[];
|
|
|
1311
1311
|
* Parse an {@link RrfSource} into concepts (first row per code wins) and skipped-row warnings.
|
|
1312
1312
|
*
|
|
1313
1313
|
* A code that recurs across rows (RRF repeats a code once per atom/attribute) keeps its **first**
|
|
1314
|
-
* occurrence
|
|
1314
|
+
* occurrence, a documented v1 limitation: preferred-atom selection (`TS`/`STT`/`ISPREF`) and
|
|
1315
1315
|
* attribute merging are later work. The result is data only; {@link loadCodeSystem} freezes it.
|
|
1316
1316
|
*
|
|
1317
1317
|
* @param source - The RRF source.
|
|
@@ -1334,17 +1334,17 @@ declare function parseRrf(source: RrfSource): {
|
|
|
1334
1334
|
};
|
|
1335
1335
|
|
|
1336
1336
|
/**
|
|
1337
|
-
* The **RFC-4180 CSV** reader
|
|
1337
|
+
* The **RFC-4180 CSV** reader: the one release format that needs real quote handling (LOINC's
|
|
1338
1338
|
* `Loinc.csv`). Fields may be quoted with `"`; inside a quoted field a literal quote is escaped as
|
|
1339
1339
|
* `""`, and commas and newlines are data. Hand-rolled, zero-dep (the CSV surface is small and
|
|
1340
1340
|
* well-specified enough to hand-roll rather than pull a dependency).
|
|
1341
1341
|
*
|
|
1342
1342
|
* **Liberal on load:** a data row with too few fields to reach a configured column is **skipped and
|
|
1343
|
-
* surfaced** as a `TERM_CSV_MALFORMED` warning; an unterminated final quote is surfaced too
|
|
1343
|
+
* surfaced** as a `TERM_CSV_MALFORMED` warning; an unterminated final quote is surfaced too: never a
|
|
1344
1344
|
* crash. A configured code/display header that is **absent from the header row** is a *fatal*
|
|
1345
1345
|
* (`TERM_CODESYSTEM_MALFORMED`): the source config does not match the file, so nothing loads cleanly.
|
|
1346
1346
|
* That fatal names the missing column's **role** (`code`, `display`, `status`, a property column)
|
|
1347
|
-
* from a frozen table, never the column name you configured
|
|
1347
|
+
* from a frozen table, never the column name you configured: the message reaches `err.stack`, and a
|
|
1348
1348
|
* column name is consumer-supplied text of unbounded length.
|
|
1349
1349
|
*
|
|
1350
1350
|
* @packageDocumentation
|
|
@@ -1390,14 +1390,14 @@ declare function parseCsvSource(source: CsvSource): {
|
|
|
1390
1390
|
};
|
|
1391
1391
|
|
|
1392
1392
|
/**
|
|
1393
|
-
* The **fixed-width** reader
|
|
1393
|
+
* The **fixed-width** reader: slice a line by column, for order-file layouts like the ICD-10-CM
|
|
1394
1394
|
* order file (`icd10cm_order_YYYY.txt`). Fully parameterized: the consumer supplies the field slices,
|
|
1395
1395
|
* so the *engine* is content-agnostic and the byte offsets live in the caller's config, not baked in.
|
|
1396
1396
|
*
|
|
1397
|
-
* The documented ICD-10-CM preset is {@link ICD10CM_ORDER_FILE_FIELDS}
|
|
1397
|
+
* The documented ICD-10-CM preset is {@link ICD10CM_ORDER_FILE_FIELDS}: the position-15 flag
|
|
1398
1398
|
* (0-based char index 14) is `1` for a **billable/valid** code and `0` for a **header** (grounded on
|
|
1399
1399
|
* the CMS/CDC order-file layout). Confirm the exact offsets against your release's README before
|
|
1400
|
-
* relying on the preset
|
|
1400
|
+
* relying on the preset, which is exactly why the reader takes the slices as a parameter.
|
|
1401
1401
|
*
|
|
1402
1402
|
* **Liberal on load:** a line too short to contain the code slice, or with an empty code, is skipped
|
|
1403
1403
|
* and surfaced as a `TERM_FIXED_WIDTH_MALFORMED` warning.
|
|
@@ -1422,10 +1422,10 @@ declare function sliceField(line: string, slice: FieldSlice): string;
|
|
|
1422
1422
|
/**
|
|
1423
1423
|
* The documented **ICD-10-CM order file** field layout (0-based char indices).
|
|
1424
1424
|
*
|
|
1425
|
-
* - `code
|
|
1426
|
-
* - `billable
|
|
1427
|
-
* - `display
|
|
1428
|
-
* - property `shortDescription
|
|
1425
|
+
* - `code`: the ICD-10-CM code (no decimal point).
|
|
1426
|
+
* - `billable`, position-15 flag at index 14: `"1"` = billable/valid leaf, `"0"` = header.
|
|
1427
|
+
* - `display`: the long description (to end of line).
|
|
1428
|
+
* - property `shortDescription`: the 60-char short description.
|
|
1429
1429
|
*
|
|
1430
1430
|
* Grounded on the CMS/CDC order-file layout; **verify against your release's README** before relying
|
|
1431
1431
|
* on the exact offsets, which are not confirmed against an authoritative machine-readable source.
|
|
@@ -1456,14 +1456,14 @@ declare function parseFixedWidth(source: FixedWidthSource): {
|
|
|
1456
1456
|
};
|
|
1457
1457
|
|
|
1458
1458
|
/**
|
|
1459
|
-
* The **FHIR R4 `CodeSystem`** JSON loader
|
|
1459
|
+
* The **FHIR R4 `CodeSystem`** JSON loader: the native, consumer-supplied model. Reads the untrusted
|
|
1460
1460
|
* resource into the engine's {@link Concept} map, flattening nested `concept` hierarchies and mapping
|
|
1461
1461
|
* the standard concept properties to {@link ConceptStatus}.
|
|
1462
1462
|
*
|
|
1463
1463
|
* Grounded firsthand on FHIR R4 (`https://hl7.org/fhir/R4/codesystem.html` and the concept-properties
|
|
1464
1464
|
* code system, `https://hl7.org/fhir/R4/codesystem-concept-properties.html`): a concept has
|
|
1465
1465
|
* `code`/`display`/`definition`/`designation`/`property`/nested `concept`; the base property
|
|
1466
|
-
* **`inactive`** (boolean) is *"True if the concept is not considered active
|
|
1466
|
+
* **`inactive`** (boolean) is *"True if the concept is not considered active: e.g. not a valid
|
|
1467
1467
|
* concept any more"*, **`deprecated`** (dateTime) marks a deprecation, and a `status` string property
|
|
1468
1468
|
* is common in real systems.
|
|
1469
1469
|
*
|
|
@@ -1500,14 +1500,14 @@ declare function parseFhirCodeSystem(source: FhirCodeSystemSource): {
|
|
|
1500
1500
|
};
|
|
1501
1501
|
|
|
1502
1502
|
/**
|
|
1503
|
-
* Status interpretation shared by the loaders
|
|
1503
|
+
* Status interpretation shared by the loaders: the {@link defaultStatusMapper} that turns a raw
|
|
1504
1504
|
* steward status token into a normalized {@link ConceptActivity}, and {@link makeStatus} which
|
|
1505
1505
|
* assembles the frozen {@link ConceptStatus} (attaching the stable diagnostic code for the two
|
|
1506
1506
|
* concerns it distinguishes: deprecated and header-not-billable).
|
|
1507
1507
|
*
|
|
1508
1508
|
* The mapper is deliberately **conservative**: it recognizes only the tokens grounded in the format
|
|
1509
1509
|
* docs (LOINC `STATUS` lifecycle values and RxNorm/UMLS `SUPPRESS` values), and maps
|
|
1510
|
-
* everything else to `unknown
|
|
1510
|
+
* everything else to `unknown`: a non-active state carrying the raw token, **never** a guessed
|
|
1511
1511
|
* clean-active. Every loader lets the consumer override it for a release with bespoke semantics.
|
|
1512
1512
|
*
|
|
1513
1513
|
* @packageDocumentation
|
|
@@ -1534,7 +1534,7 @@ declare const defaultStatusMapper: StatusMapper;
|
|
|
1534
1534
|
/**
|
|
1535
1535
|
* Assemble a frozen {@link ConceptStatus} from a normalized activity, carrying the raw token and (for
|
|
1536
1536
|
* classification systems) the billable flag, and attaching the stable diagnostic code for the two
|
|
1537
|
-
* concerns it distinguishes
|
|
1537
|
+
* concerns it distinguishes: `TERM_CONCEPT_DEPRECATED` and `TERM_CONCEPT_HEADER_NOT_BILLABLE`.
|
|
1538
1538
|
*
|
|
1539
1539
|
* @param activity - The normalized activity.
|
|
1540
1540
|
* @param raw - The verbatim steward token, if any (omitted from the result when empty).
|
|
@@ -1556,7 +1556,7 @@ declare function makeStatus(activity: ConceptActivity, raw?: string, billable?:
|
|
|
1556
1556
|
* {@link ValueSetMembership} outcomes.
|
|
1557
1557
|
*
|
|
1558
1558
|
* The model is **content-agnostic**: a `ValueSet` names codes by system URI and is expanded over
|
|
1559
|
-
* **consumer-supplied** {@link CodeSystem} releases
|
|
1559
|
+
* **consumer-supplied** {@link CodeSystem} releases: the engine ships **zero** encoded value-set
|
|
1560
1560
|
* content (SNOMED CT / CPT / LOINC / UMLS / VSAC value sets are strictly BYO). The FHIR
|
|
1561
1561
|
* operation shapes are grounded firsthand on the FHIR R4 Terminology Module
|
|
1562
1562
|
* (`https://hl7.org/fhir/R4/valueset.html`, `https://hl7.org/fhir/R4/valueset-operation-expand.html`,
|
|
@@ -1566,17 +1566,17 @@ declare function makeStatus(activity: ConceptActivity, raw?: string, billable?:
|
|
|
1566
1566
|
*/
|
|
1567
1567
|
|
|
1568
1568
|
/**
|
|
1569
|
-
* A FHIR R4 `ValueSet.compose.include.filter` operator
|
|
1569
|
+
* A FHIR R4 `ValueSet.compose.include.filter` operator: the subset the engine implements plus the
|
|
1570
1570
|
* ones it explicitly does not. Grounded on the FHIR `filter-operator` code system
|
|
1571
1571
|
* (`https://hl7.org/fhir/R4/valueset-filter-operator.html`).
|
|
1572
1572
|
*
|
|
1573
1573
|
* **Implemented:** `is-a` / `descendent-of` / `is-not-a` (subsumption over the loaded release's
|
|
1574
1574
|
* hierarchy), `=` / `in` / `not-in` / `exists` (property predicates). **Not implemented** (surfaced as
|
|
1575
1575
|
* a typed {@link DiagnosticCode.TERM_VALUESET_CANNOT_EXPAND}, never silently mis-expanded): `regex`,
|
|
1576
|
-
* `generalizes`. Anything unrecognized is treated as not-implemented
|
|
1576
|
+
* `generalizes`. Anything unrecognized is treated as not-implemented: never as "matches nothing".
|
|
1577
1577
|
*/
|
|
1578
1578
|
type FilterOperator = "=" | "is-a" | "descendent-of" | "is-not-a" | "regex" | "in" | "not-in" | "generalizes" | "exists";
|
|
1579
|
-
/** One `ValueSet.compose.include.filter
|
|
1579
|
+
/** One `ValueSet.compose.include.filter`: a `property op value` predicate over a code system. */
|
|
1580
1580
|
interface ConceptSetFilter {
|
|
1581
1581
|
/** The concept property the predicate is on (e.g. `"concept"` for the code hierarchy, or a code). */
|
|
1582
1582
|
readonly property: string;
|
|
@@ -1585,7 +1585,7 @@ interface ConceptSetFilter {
|
|
|
1585
1585
|
/** The comparison value (for `in`/`not-in`, a comma-separated list; for `is-a`, an anchor code). */
|
|
1586
1586
|
readonly value: string;
|
|
1587
1587
|
}
|
|
1588
|
-
/** One explicit `ValueSet.compose.include.concept
|
|
1588
|
+
/** One explicit `ValueSet.compose.include.concept`: an enumerated code (extensional). */
|
|
1589
1589
|
interface ConceptRef {
|
|
1590
1590
|
/** The code, drawn verbatim from the value set. */
|
|
1591
1591
|
readonly code: string;
|
|
@@ -1593,7 +1593,7 @@ interface ConceptRef {
|
|
|
1593
1593
|
readonly display?: string;
|
|
1594
1594
|
}
|
|
1595
1595
|
/**
|
|
1596
|
-
* One `ValueSet.compose.include` / `.exclude` component
|
|
1596
|
+
* One `ValueSet.compose.include` / `.exclude` component: a `ConceptSet`. Selects codes by an explicit
|
|
1597
1597
|
* `concept` list, by `filter`s over a `system`, by referencing other value sets (`valueSet`), or a
|
|
1598
1598
|
* combination (the combination is an **intersection**, per FHIR).
|
|
1599
1599
|
*/
|
|
@@ -1609,18 +1609,18 @@ interface ConceptSetComponent {
|
|
|
1609
1609
|
/** Canonical URLs of other value sets; a code must be a member of **every** one (intersection). */
|
|
1610
1610
|
readonly valueSet?: readonly string[];
|
|
1611
1611
|
}
|
|
1612
|
-
/** A `ValueSet.compose
|
|
1612
|
+
/** A `ValueSet.compose`: the intensional/extensional definition of membership. */
|
|
1613
1613
|
interface ValueSetCompose {
|
|
1614
1614
|
/** The `include` components (their union, minus every {@link exclude}, is the membership). */
|
|
1615
1615
|
readonly include: readonly ConceptSetComponent[];
|
|
1616
|
-
/** The `exclude` components
|
|
1616
|
+
/** The `exclude` components: codes removed from the include union. */
|
|
1617
1617
|
readonly exclude: readonly ConceptSetComponent[];
|
|
1618
1618
|
}
|
|
1619
1619
|
/** One `ValueSet.expansion.contains` entry from a **pre-computed** expansion. */
|
|
1620
1620
|
interface ExpansionContains {
|
|
1621
1621
|
/** The code system URI, when the entry names one. */
|
|
1622
1622
|
readonly system?: string;
|
|
1623
|
-
/** The code. Required
|
|
1623
|
+
/** The code. Required: a `contains` entry without a code is a malformed expansion. */
|
|
1624
1624
|
readonly code: string;
|
|
1625
1625
|
/** The display, carried verbatim when present. */
|
|
1626
1626
|
readonly display?: string;
|
|
@@ -1628,7 +1628,7 @@ interface ExpansionContains {
|
|
|
1628
1628
|
readonly version?: string;
|
|
1629
1629
|
}
|
|
1630
1630
|
/**
|
|
1631
|
-
* A **pre-computed** `ValueSet.expansion
|
|
1631
|
+
* A **pre-computed** `ValueSet.expansion`: a cached membership snapshot, used as-is (extensional).
|
|
1632
1632
|
* The engine never re-derives it; it only checks whether it is **complete** (a truncated
|
|
1633
1633
|
* expansion must never read as full membership).
|
|
1634
1634
|
*/
|
|
@@ -1645,7 +1645,7 @@ interface ValueSetExpansion {
|
|
|
1645
1645
|
readonly truncated: boolean;
|
|
1646
1646
|
}
|
|
1647
1647
|
/**
|
|
1648
|
-
* A loaded, immutable `ValueSet
|
|
1648
|
+
* A loaded, immutable `ValueSet`: the subset of the FHIR R4 `ValueSet` resource the binding layer
|
|
1649
1649
|
* needs. Produced by {@link loadValueSet}; every field deep-frozen.
|
|
1650
1650
|
*/
|
|
1651
1651
|
interface ValueSet {
|
|
@@ -1676,14 +1676,14 @@ interface ExpansionContext {
|
|
|
1676
1676
|
/** Referenced value sets, keyed by canonical URL, for `compose.include.valueSet`. */
|
|
1677
1677
|
readonly valueSets?: ReadonlyMap<string, ValueSet>;
|
|
1678
1678
|
}
|
|
1679
|
-
/** A surfaced expansion concern
|
|
1679
|
+
/** A surfaced expansion concern: a part that could not be expanded, or a truncated snapshot. */
|
|
1680
1680
|
interface ExpansionDiagnostic {
|
|
1681
1681
|
/** The stable code (`TERM_VALUESET_CANNOT_EXPAND` / `TERM_VALUESET_EXPANSION_TRUNCATED`). */
|
|
1682
1682
|
readonly code: DiagnosticCode;
|
|
1683
1683
|
/** A **value-free** structural description of the concern (never echoes a patient value). */
|
|
1684
1684
|
readonly detail: string;
|
|
1685
1685
|
/**
|
|
1686
|
-
* A **value-free structural locus** into the caller's own resource
|
|
1686
|
+
* A **value-free structural locus** into the caller's own resource: `"expansion"`, or a
|
|
1687
1687
|
* `compose`-relative index path such as `"compose.include[2]"` or
|
|
1688
1688
|
* `"compose.include[0].valueSet[1]"`. A diagnostic raised while expanding a *referenced* value set
|
|
1689
1689
|
* is prefixed with the reference that reached it (`"compose.include[0].valueSet[1]/compose.include[3]"`).
|
|
@@ -1713,7 +1713,7 @@ interface ExpandResult {
|
|
|
1713
1713
|
/** The surfaced concerns, in encounter order (frozen; may be empty). */
|
|
1714
1714
|
readonly diagnostics: readonly ExpansionDiagnostic[];
|
|
1715
1715
|
}
|
|
1716
|
-
/** A definitive membership answer
|
|
1716
|
+
/** A definitive membership answer: the code is (or is not) a member of the value set. */
|
|
1717
1717
|
interface ValueSetMemberDecided {
|
|
1718
1718
|
/** Discriminant: membership was decided. */
|
|
1719
1719
|
readonly undetermined: false;
|
|
@@ -1723,7 +1723,7 @@ interface ValueSetMemberDecided {
|
|
|
1723
1723
|
readonly coding: Coding;
|
|
1724
1724
|
}
|
|
1725
1725
|
/**
|
|
1726
|
-
* A **fail-safe undetermined** membership
|
|
1726
|
+
* A **fail-safe undetermined** membership: the never-fabricate outcome for a value set that could
|
|
1727
1727
|
* not be fully evaluated (a missing code system, a truncated expansion). The engine refuses to guess:
|
|
1728
1728
|
* it returns neither `true` nor `false`, so a caller can never mistake "we could not check" for "not a
|
|
1729
1729
|
* member" (a false "not a member" is a clinical error).
|
|
@@ -1742,14 +1742,14 @@ interface ValueSetMemberUndetermined {
|
|
|
1742
1742
|
type ValueSetMembership = ValueSetMemberDecided | ValueSetMemberUndetermined;
|
|
1743
1743
|
|
|
1744
1744
|
/**
|
|
1745
|
-
* {@link loadValueSet}
|
|
1745
|
+
* {@link loadValueSet}: validate and normalize an untrusted FHIR R4 `ValueSet` JSON resource into
|
|
1746
1746
|
* the immutable {@link ValueSet} model the `$expand` / `$validate-code` binding operations run over.
|
|
1747
1747
|
*
|
|
1748
1748
|
* **Conservative on load** (like {@link ../conceptmap/load.loadConceptMap}, unlike a lenient wire
|
|
1749
1749
|
* parser): a value set *binds* whether a code is allowed in a clinical slot, so a structurally
|
|
1750
1750
|
* unusable resource is a typed **fatal** ({@link FATAL_CODES.TERM_VALUESET_MALFORMED}) rather than a
|
|
1751
1751
|
* silently partial value set that would admit *some* codes and quietly drop others. A `filter`
|
|
1752
|
-
* operator the engine does not implement is **not** fatal
|
|
1752
|
+
* operator the engine does not implement is **not** fatal: the value set loads, and the gap surfaces
|
|
1753
1753
|
* at expansion time as a {@link DIAGNOSTIC_CODES.TERM_VALUESET_CANNOT_EXPAND} diagnostic. Fault
|
|
1754
1754
|
* messages are **value-free**: they name the resource *path* and the fault, never echo a code value.
|
|
1755
1755
|
*
|
|
@@ -1765,7 +1765,7 @@ type ValueSetMembership = ValueSetMemberDecided | ValueSetMemberUndetermined;
|
|
|
1765
1765
|
* `truncated` flag). The result is deep-frozen. Anything structurally unusable throws a
|
|
1766
1766
|
* {@link TerminologyError} carrying {@link FATAL_CODES.TERM_VALUESET_MALFORMED}.
|
|
1767
1767
|
*
|
|
1768
|
-
* @param json - The untrusted resource (typically `JSON.parse` output
|
|
1768
|
+
* @param json - The untrusted resource (typically `JSON.parse` output, hence `unknown`).
|
|
1769
1769
|
* @returns The immutable, validated {@link ValueSet}.
|
|
1770
1770
|
* @throws {TerminologyError} `TERM_VALUESET_MALFORMED` when the resource is not a usable ValueSet.
|
|
1771
1771
|
* @example
|
|
@@ -1785,20 +1785,20 @@ type ValueSetMembership = ValueSetMemberDecided | ValueSetMemberUndetermined;
|
|
|
1785
1785
|
declare function loadValueSet(json: unknown): ValueSet;
|
|
1786
1786
|
|
|
1787
1787
|
/**
|
|
1788
|
-
* {@link expand}
|
|
1788
|
+
* {@link expand}: the FHIR R4 ValueSet `$expand` operation over a loaded {@link ValueSet}.
|
|
1789
1789
|
*
|
|
1790
1790
|
* Grounded firsthand on FHIR R4 (`https://hl7.org/fhir/R4/valueset-operation-expand.html`,
|
|
1791
1791
|
* `https://hl7.org/fhir/R4/valueset.html#compose`):
|
|
1792
1792
|
*
|
|
1793
|
-
* - A **pre-computed** `expansion` is used as-is (extensional), and its completeness is checked
|
|
1793
|
+
* - A **pre-computed** `expansion` is used as-is (extensional), and its completeness is checked: a
|
|
1794
1794
|
* truncated snapshot is flagged, never treated as full membership.
|
|
1795
1795
|
* - An intensional `compose` is expanded over **consumer-supplied** {@link ../codesystem/types.CodeSystem}
|
|
1796
1796
|
* releases: the union of `include` components minus the union of `exclude` components. Each component
|
|
1797
1797
|
* selects by explicit `concept`, by `filter` (subsumption + property predicates), by the whole
|
|
1798
1798
|
* `system`, and/or by intersecting referenced value sets.
|
|
1799
1799
|
*
|
|
1800
|
-
* **Never fabricate.** A part that cannot be computed
|
|
1801
|
-
* referenced value set, an unimplemented `filter` operator
|
|
1800
|
+
* **Never fabricate.** A part that cannot be computed (a missing code system, an unresolved
|
|
1801
|
+
* referenced value set, an unimplemented `filter` operator) yields a typed
|
|
1802
1802
|
* {@link ../common/diagnostics.DIAGNOSTIC_CODES.TERM_VALUESET_CANNOT_EXPAND} and marks the result
|
|
1803
1803
|
* `complete: false`, so the `contains` set is an explicit **lower bound**, never a silently-empty or
|
|
1804
1804
|
* fabricated membership.
|
|
@@ -1811,7 +1811,7 @@ declare function loadValueSet(json: unknown): ValueSet;
|
|
|
1811
1811
|
*
|
|
1812
1812
|
* @param vs - The loaded value set.
|
|
1813
1813
|
* @param ctx - The loaded code systems / referenced value sets the intensional parts resolve against.
|
|
1814
|
-
* @returns An {@link ExpandResult}
|
|
1814
|
+
* @returns An {@link ExpandResult}: the `contains` members plus an honest `complete` flag. When
|
|
1815
1815
|
* `complete` is `false`, `contains` is a lower bound (never treat it as exhaustive membership).
|
|
1816
1816
|
* @example
|
|
1817
1817
|
* ```ts
|
|
@@ -1837,16 +1837,16 @@ declare function loadValueSet(json: unknown): ValueSet;
|
|
|
1837
1837
|
declare function expand(vs: ValueSet, ctx?: ExpansionContext): ExpandResult;
|
|
1838
1838
|
|
|
1839
1839
|
/**
|
|
1840
|
-
* {@link validateCodeInValueSet}
|
|
1840
|
+
* {@link validateCodeInValueSet}: the FHIR R4 ValueSet `$validate-code` operation (value-set
|
|
1841
1841
|
* binding): is a {@link Coding} a member of a {@link ValueSet}?
|
|
1842
1842
|
*
|
|
1843
1843
|
* Grounded firsthand on FHIR R4 (`https://hl7.org/fhir/R4/valueset-operation-validate-code.html`): a
|
|
1844
1844
|
* binding decides whether a code is *allowed* in a slot. The engine returns a **decided** membership
|
|
1845
|
-
* (`result: true`/`false`) **only when it can prove it
|
|
1845
|
+
* (`result: true`/`false`) **only when it can prove it**: a code found in a computable `include` and
|
|
1846
1846
|
* not removed by any computable `exclude` is a definite member; a code absent from a fully-evaluated
|
|
1847
1847
|
* value set is a definite non-member. When any relevant part cannot be evaluated (a missing code
|
|
1848
1848
|
* system, a truncated pre-computed expansion, an unimplemented `filter`), the answer is a typed
|
|
1849
|
-
* {@link ValueSetMemberUndetermined}
|
|
1849
|
+
* {@link ValueSetMemberUndetermined}: **never** a fabricated `false` (a false "not a member" is a
|
|
1850
1850
|
* clinical error).
|
|
1851
1851
|
*
|
|
1852
1852
|
* @packageDocumentation
|
|
@@ -1859,7 +1859,7 @@ declare function expand(vs: ValueSet, ctx?: ExpansionContext): ExpandResult;
|
|
|
1859
1859
|
* @param valueSet - The loaded value set.
|
|
1860
1860
|
* @param ctx - The loaded code systems / referenced value sets the intensional parts resolve against.
|
|
1861
1861
|
* @returns A decided {@link ValueSetMembership} (`result: true`/`false`), or a typed
|
|
1862
|
-
* {@link ValueSetMemberUndetermined} when membership could not be proven
|
|
1862
|
+
* {@link ValueSetMemberUndetermined} when membership could not be proven: never a fabricated `false`.
|
|
1863
1863
|
* @example
|
|
1864
1864
|
* ```ts
|
|
1865
1865
|
* import { loadValueSet, validateCodeInValueSet } from "@cosyte/terminology";
|
|
@@ -1875,15 +1875,15 @@ declare function expand(vs: ValueSet, ctx?: ExpansionContext): ExpandResult;
|
|
|
1875
1875
|
declare function validateCodeInValueSet(coding: Coding, valueSet: ValueSet, ctx?: ExpansionContext): ValueSetMembership;
|
|
1876
1876
|
|
|
1877
1877
|
/**
|
|
1878
|
-
* Subsumption + `compose.include.filter` evaluation
|
|
1878
|
+
* Subsumption + `compose.include.filter` evaluation: the shared machinery {@link ./expand.expand}
|
|
1879
1879
|
* and {@link ./validate.validateCodeInValueSet} both draw on.
|
|
1880
1880
|
*
|
|
1881
1881
|
* **Subsumption** is read from the loaded {@link CodeSystem}'s **`parent`** concept-properties
|
|
1882
|
-
* (`http://hl7.org/fhir/concept-properties#parent`)
|
|
1882
|
+
* (`http://hl7.org/fhir/concept-properties#parent`), which the FHIR loader synthesizes from a nested
|
|
1883
1883
|
* `concept` hierarchy and carries verbatim from an explicit `parent` property. This is deliberately
|
|
1884
1884
|
* the release's **own** hierarchy: subsumption across two separate releases is not computed, and a
|
|
1885
1885
|
* code system that encodes no parent edges has no descendants beyond identity, which is treated as
|
|
1886
|
-
* complete
|
|
1886
|
+
* complete: not guessed deeper.
|
|
1887
1887
|
*
|
|
1888
1888
|
* **Filter support is explicit.** `is-a` / `descendent-of` / `is-not-a` / `=` / `in` / `not-in` /
|
|
1889
1889
|
* `exists` are implemented; `regex` / `generalizes` / anything unrecognized report `supported: false`
|
|
@@ -1894,7 +1894,7 @@ declare function validateCodeInValueSet(coding: Coding, valueSet: ValueSet, ctx?
|
|
|
1894
1894
|
*/
|
|
1895
1895
|
|
|
1896
1896
|
/**
|
|
1897
|
-
* The filters whose operator the engine does **not** implement (`regex` / `generalizes` / unknown)
|
|
1897
|
+
* The filters whose operator the engine does **not** implement (`regex` / `generalizes` / unknown):
|
|
1898
1898
|
* a non-empty result means the caller must surface a typed cannot-expand, never mis-expand.
|
|
1899
1899
|
*
|
|
1900
1900
|
* @param filters - The component's filters.
|
|
@@ -1930,7 +1930,7 @@ interface Subsumption {
|
|
|
1930
1930
|
*/
|
|
1931
1931
|
declare function buildSubsumption(cs: CodeSystem): Subsumption;
|
|
1932
1932
|
/**
|
|
1933
|
-
* True when `code` is-a `anchor
|
|
1933
|
+
* True when `code` is-a `anchor`: the same code, or a (transitive) descendant of it.
|
|
1934
1934
|
*
|
|
1935
1935
|
* @param sub - The subsumption index (from {@link buildSubsumption}).
|
|
1936
1936
|
* @param code - The candidate code.
|
|
@@ -1960,7 +1960,7 @@ interface FilterMatch {
|
|
|
1960
1960
|
*
|
|
1961
1961
|
* The `concept` filter property (and the hierarchy operators regardless of property) reads the code
|
|
1962
1962
|
* itself / its subsumption; other properties read the concept's `property` values. An unimplemented
|
|
1963
|
-
* operator returns `{ supported: false }
|
|
1963
|
+
* operator returns `{ supported: false }`: never a coerced `matched`.
|
|
1964
1964
|
*
|
|
1965
1965
|
* @param concept - The concept under test.
|
|
1966
1966
|
* @param filter - The filter predicate.
|
|
@@ -1984,12 +1984,12 @@ declare function matchesFilter(concept: Concept, filter: ConceptSetFilter, sub:
|
|
|
1984
1984
|
* Types for the **UCUM unit layer**: the parsed unit AST, the reduced
|
|
1985
1985
|
* (canonical) dimensional form, and the public {@link UcumValidation} result.
|
|
1986
1986
|
*
|
|
1987
|
-
* The layer is **recognition + validation + representation canonicalization only
|
|
1987
|
+
* The layer is **recognition + validation + representation canonicalization only**: it answers
|
|
1988
1988
|
* "is this a valid UCUM expression" and "are these two expressions the same unit", and it
|
|
1989
1989
|
* canonicalizes a unit's *representation*. It performs **no magnitude conversion** (`mg/dL` →
|
|
1990
|
-
* `mmol/L` needs an analyte's molar mass
|
|
1990
|
+
* `mmol/L` needs an analyte's molar mass: a clinical computation the engine refuses). The tables
|
|
1991
1991
|
* are the UCUM `ucum-essence.xml`, **bundled verbatim** in this package (copyright © Regenstrief
|
|
1992
|
-
* Institute, Inc
|
|
1992
|
+
* Institute, Inc.: see `vendor/ucum/NOTICE.md`) and transformed to an in-memory model at runtime;
|
|
1993
1993
|
* the engine ships **no derivative** of the UCUM table.
|
|
1994
1994
|
*
|
|
1995
1995
|
* @packageDocumentation
|
|
@@ -2010,18 +2010,18 @@ interface UcumAtom {
|
|
|
2010
2010
|
readonly code: string;
|
|
2011
2011
|
/** Whether a metric prefix may attach to this atom (essence `isMetric`). Only metric atoms prefix. */
|
|
2012
2012
|
readonly metric: boolean;
|
|
2013
|
-
/** A **base** unit (one of the 7: `m s g rad K C cd`)
|
|
2013
|
+
/** A **base** unit (one of the 7: `m s g rad K C cd`), its own dimension, factor 1. */
|
|
2014
2014
|
readonly base: boolean;
|
|
2015
2015
|
/** A base unit's dimension key (its own `code`), or `undefined` for derived atoms. */
|
|
2016
2016
|
readonly dim?: string;
|
|
2017
2017
|
/**
|
|
2018
|
-
* A **special** unit (essence `isSpecial`, e.g. `Cel`, `B`, `[pH]`)
|
|
2018
|
+
* A **special** unit (essence `isSpecial`, e.g. `Cel`, `B`, `[pH]`): defined by a non-linear
|
|
2019
2019
|
* function, so it has **no** linear factor/dimension and is never reduced to one. Compared only by
|
|
2020
2020
|
* identity of its normalized representation (never claimed equal to a linear unit).
|
|
2021
2021
|
*/
|
|
2022
2022
|
readonly special: boolean;
|
|
2023
2023
|
/**
|
|
2024
|
-
* An **arbitrary** unit (essence `isArbitrary`, e.g. `[IU]`, `[arb'U]`)
|
|
2024
|
+
* An **arbitrary** unit (essence `isArbitrary`, e.g. `[IU]`, `[arb'U]`): not commensurable with
|
|
2025
2025
|
* any other unit. Modeled as its own dimension axis keyed by the atom `code`, so `[IU]/[IU]`
|
|
2026
2026
|
* reduces to unity but `[IU]` is never equated with a mass or another arbitrary unit.
|
|
2027
2027
|
*/
|
|
@@ -2035,7 +2035,7 @@ interface UcumAtom {
|
|
|
2035
2035
|
readonly unit: string;
|
|
2036
2036
|
};
|
|
2037
2037
|
}
|
|
2038
|
-
/** The parsed UCUM essence table
|
|
2038
|
+
/** The parsed UCUM essence table: the engine's in-memory unit model, built lazily and cached. */
|
|
2039
2039
|
interface UcumEssence {
|
|
2040
2040
|
/** Prefix symbols → prefix, longest symbols first (for greedy matching). */
|
|
2041
2041
|
readonly prefixes: readonly UcumPrefix[];
|
|
@@ -2072,7 +2072,7 @@ interface GroupNode {
|
|
|
2072
2072
|
interface AnnotationNode {
|
|
2073
2073
|
readonly kind: "annotation";
|
|
2074
2074
|
}
|
|
2075
|
-
/** A component: a simple unit, a factor, a group, or an annotation
|
|
2075
|
+
/** A component: a simple unit, a factor, a group, or an annotation, each optionally exponentiated. */
|
|
2076
2076
|
type ComponentNode = SimpleUnitNode | FactorNode | GroupNode | AnnotationNode;
|
|
2077
2077
|
/**
|
|
2078
2078
|
* A parsed UCUM term: an ordered list of components, each combined into the product with the given
|
|
@@ -2099,10 +2099,10 @@ interface LinearReduction {
|
|
|
2099
2099
|
readonly dims: Readonly<Record<string, number>>;
|
|
2100
2100
|
}
|
|
2101
2101
|
/**
|
|
2102
|
-
* A **non-linear** (special) reduction
|
|
2102
|
+
* A **non-linear** (special) reduction: the expression involves a special unit (`Cel`, `B`, …) and
|
|
2103
2103
|
* cannot be reduced to a scalar×dimension form. Carried by its normalized representation `form`;
|
|
2104
2104
|
* two special reductions are the same unit iff their `form`s are identical (never equated with a
|
|
2105
|
-
* linear unit
|
|
2105
|
+
* linear unit: the never-fabricate posture applied to units).
|
|
2106
2106
|
*/
|
|
2107
2107
|
interface SpecialReduction {
|
|
2108
2108
|
readonly kind: "special";
|
|
@@ -2119,7 +2119,7 @@ type UcumValidation = {
|
|
|
2119
2119
|
/** The expression is a well-formed UCUM unit over known atoms. */
|
|
2120
2120
|
readonly valid: true;
|
|
2121
2121
|
/**
|
|
2122
|
-
* A stable, normalized **descriptor** of the unit's canonical form
|
|
2122
|
+
* A stable, normalized **descriptor** of the unit's canonical form: equal iff the units are
|
|
2123
2123
|
* the same (see {@link ucumEqual}). Note: this is a comparison/debug descriptor, **not**
|
|
2124
2124
|
* guaranteed to be a re-parseable UCUM expression (UCUM cannot express arbitrary numeric
|
|
2125
2125
|
* factors as literals).
|
|
@@ -2128,7 +2128,7 @@ type UcumValidation = {
|
|
|
2128
2128
|
} | {
|
|
2129
2129
|
/** The expression is not a valid UCUM unit. */
|
|
2130
2130
|
readonly valid: false;
|
|
2131
|
-
/** The stable diagnostic code
|
|
2131
|
+
/** The stable diagnostic code: never a guessed "nearest" unit (the never-fabricate rule). */
|
|
2132
2132
|
readonly code: "TERM_UCUM_INVALID";
|
|
2133
2133
|
/** A **value-free** structural reason (a grammar fault or an unknown atom; never PHI). */
|
|
2134
2134
|
readonly reason: string;
|
|
@@ -2138,7 +2138,7 @@ type UcumValidation = {
|
|
|
2138
2138
|
* The public **UCUM** surface: {@link validateUcum} (recognition + a canonical
|
|
2139
2139
|
* descriptor) and {@link ucumEqual} (are two expressions the *same unit*).
|
|
2140
2140
|
*
|
|
2141
|
-
* Both are **recognition / validation / representation-canonicalization only
|
|
2141
|
+
* Both are **recognition / validation / representation-canonicalization only**: never magnitude
|
|
2142
2142
|
* conversion. The never-fabricate posture holds: an unparseable or unknown unit is
|
|
2143
2143
|
* a typed {@link TERM_UCUM_INVALID} outcome carrying a value-free reason, **never** a guessed
|
|
2144
2144
|
* "nearest" unit; and a special (non-linear) unit is never claimed equal to a linear one.
|
|
@@ -2151,7 +2151,7 @@ type UcumValidation = {
|
|
|
2151
2151
|
*
|
|
2152
2152
|
* Validation **is** parsing against the UCUM grammar over the known atom table: an expression is
|
|
2153
2153
|
* valid iff it parses completely. An invalid expression returns a typed {@link TERM_UCUM_INVALID}
|
|
2154
|
-
* with a value-free reason
|
|
2154
|
+
* with a value-free reason: never a coerced or guessed unit.
|
|
2155
2155
|
*
|
|
2156
2156
|
* @param unit - The UCUM unit expression (e.g. `"mmol/L"`, `"kg.m/s2"`, `"Cel"`).
|
|
2157
2157
|
* @returns `{ valid: true, canonical }` or `{ valid: false, code: "TERM_UCUM_INVALID", reason }`.
|
|
@@ -2166,13 +2166,13 @@ type UcumValidation = {
|
|
|
2166
2166
|
*/
|
|
2167
2167
|
declare function validateUcum(unit: string): UcumValidation;
|
|
2168
2168
|
/**
|
|
2169
|
-
* Whether two UCUM expressions denote the **same unit
|
|
2169
|
+
* Whether two UCUM expressions denote the **same unit**: i.e. they reduce to the same canonical
|
|
2170
2170
|
* form (equal base dimensions *and* equal scale). This recognizes representational equivalences
|
|
2171
2171
|
* (`N` ≡ `kg.m/s2`, `mmol/L` ≡ `mmol.L-1`, annotations inert) but is **not** magnitude conversion:
|
|
2172
2172
|
* `mg` and `g` are different units and compare unequal.
|
|
2173
2173
|
*
|
|
2174
2174
|
* A unit is never equal to an invalid expression, and a special (non-linear) unit (`Cel`, `[pH]`) is
|
|
2175
|
-
* equal only to a structurally identical special unit
|
|
2175
|
+
* equal only to a structurally identical special unit: never to a linear unit (the never-fabricate
|
|
2176
2176
|
* posture: the engine will not assert an equivalence it cannot prove).
|
|
2177
2177
|
*
|
|
2178
2178
|
* @param a - The first UCUM unit expression.
|
|
@@ -2195,7 +2195,7 @@ declare function ucumEqual(a: string, b: string): boolean;
|
|
|
2195
2195
|
* specification's syntax (base units, metric prefixes attached with no delimiter and resolved by
|
|
2196
2196
|
* longest-match, `.` multiply / `/` divide, signed integer exponents, `{…}` inert annotations, and
|
|
2197
2197
|
* the `10*` / `10^` powers-of-ten). Validation **is** parsing: an expression is valid iff it parses
|
|
2198
|
-
* completely over **known** atoms
|
|
2198
|
+
* completely over **known** atoms: an unknown atom yields no match and fails, never a guessed unit.
|
|
2199
2199
|
*
|
|
2200
2200
|
* @packageDocumentation
|
|
2201
2201
|
*/
|
|
@@ -2228,13 +2228,13 @@ declare function parseUcum(unit: string): ParseResult;
|
|
|
2228
2228
|
|
|
2229
2229
|
/**
|
|
2230
2230
|
* **Dimensional reduction** of a parsed UCUM unit: reduce an expression to its
|
|
2231
|
-
* canonical base-unit form
|
|
2231
|
+
* canonical base-unit form: a scalar factor times a map of the seven UCUM base dimensions
|
|
2232
2232
|
* (`m s g rad K C cd`), recursively substituting each atom's essence definition down to base units.
|
|
2233
2233
|
*
|
|
2234
2234
|
* This is **representation** canonicalization, not magnitude *conversion*: it answers "are these two
|
|
2235
2235
|
* expressions the same unit" (`N` ≡ `kg.m/s2`, `mmol/L` ≡ `mmol.L-1`), never "what is 5 mg/dL in
|
|
2236
2236
|
* mmol/L" (that needs an analyte's molar mass, which the engine refuses). **Special** units (`Cel`,
|
|
2237
|
-
* `B`, `[pH]`) are non-linear and carry no factor/dimension
|
|
2237
|
+
* `B`, `[pH]`) are non-linear and carry no factor/dimension: they reduce to an opaque normalized
|
|
2238
2238
|
* form and are never equated with a linear unit. **Arbitrary** units (`[IU]`, `[arb'U]`) are modeled
|
|
2239
2239
|
* as their own dimension axis, so they cancel with themselves but convert to nothing else.
|
|
2240
2240
|
*
|
|
@@ -2242,7 +2242,7 @@ declare function parseUcum(unit: string): ParseResult;
|
|
|
2242
2242
|
*/
|
|
2243
2243
|
|
|
2244
2244
|
/**
|
|
2245
|
-
* Reduce a parsed UCUM unit to its canonical {@link Reduction}
|
|
2245
|
+
* Reduce a parsed UCUM unit to its canonical {@link Reduction}: a linear scalar×dimension form, or
|
|
2246
2246
|
* an opaque `special` form for expressions involving a non-linear special unit.
|
|
2247
2247
|
*
|
|
2248
2248
|
* The reduction of one atom is cached against **that atom object**, so a `UnitNode` you assembled
|
|
@@ -2255,8 +2255,8 @@ declare function parseUcum(unit: string): ParseResult;
|
|
|
2255
2255
|
* definition does not parse. **No expression {@link parseUcum} accepts reaches either**; a node
|
|
2256
2256
|
* you assemble yourself can, including by defining an atom in terms of a special unit such as
|
|
2257
2257
|
* `Cel`, which lands on the table's own `Cel`. A third guard catches a definition that leads back
|
|
2258
|
-
* to itself. Naming a table atom does not reach it
|
|
2259
|
-
* table, so your atom can name one but never be one
|
|
2258
|
+
* to itself. Naming a table atom does not reach it (a definition is resolved against the loaded
|
|
2259
|
+
* table, so your atom can name one but never be one), and neither does the table itself, which is
|
|
2260
2260
|
* frozen; what reaches it is a `value` accessor that re-enters `reduce` for the same atom while
|
|
2261
2261
|
* that atom is still being reduced. The message names the fault, never the atom.
|
|
2262
2262
|
* @example
|
|
@@ -2274,13 +2274,13 @@ declare function reduce(node: UnitNode): Reduction;
|
|
|
2274
2274
|
|
|
2275
2275
|
/**
|
|
2276
2276
|
* Parse the vendored, verbatim UCUM `ucum-essence.xml` (embedded as {@link UCUM_ESSENCE_XML}) into
|
|
2277
|
-
* the engine's in-memory unit model
|
|
2277
|
+
* the engine's in-memory unit model: the {@link UcumEssence} table of prefixes and atoms.
|
|
2278
2278
|
*
|
|
2279
2279
|
* Hand-rolled, **zero-dependency** scanning of a known-well-formed document (not a general XML
|
|
2280
2280
|
* parser): the essence file is a flat, regular list of `<prefix>` / `<base-unit>` / `<unit>`
|
|
2281
|
-
* elements. Parsed **once**, lazily, and cached
|
|
2281
|
+
* elements. Parsed **once**, lazily, and cached: the engine reads no file at runtime; the table is
|
|
2282
2282
|
* a pure in-process transform of the embedded verbatim content, never serialized or distributed. The
|
|
2283
|
-
* UCUM table is copyright © Regenstrief Institute, Inc. and is bundled verbatim
|
|
2283
|
+
* UCUM table is copyright © Regenstrief Institute, Inc. and is bundled verbatim: see
|
|
2284
2284
|
* `vendor/ucum/NOTICE.md`, which ships with this package.
|
|
2285
2285
|
*
|
|
2286
2286
|
* @packageDocumentation
|
|
@@ -2292,7 +2292,7 @@ declare function reduce(node: UnitNode): Reduction;
|
|
|
2292
2292
|
* One table is shared by every caller and by the engine itself, so it is handed out **frozen**: an
|
|
2293
2293
|
* atom's definition cannot be rewritten in place, and neither can the `atoms` array the parser
|
|
2294
2294
|
* scans. It used to be, and doing so before that atom's first reduction poisoned the
|
|
2295
|
-
* reduction memo for the life of the process
|
|
2295
|
+
* reduction memo for the life of the process: a fabricated unit equivalence that survived putting
|
|
2296
2296
|
* the table back. A write is refused, which in strict mode means a `TypeError`.
|
|
2297
2297
|
*
|
|
2298
2298
|
* @returns The shared, frozen in-memory {@link UcumEssence} model.
|
|
@@ -2307,19 +2307,19 @@ declare function reduce(node: UnitNode): Reduction;
|
|
|
2307
2307
|
declare function loadUcumEssence(): UcumEssence;
|
|
2308
2308
|
|
|
2309
2309
|
/**
|
|
2310
|
-
* The types for the **crosswalk resolvers
|
|
2310
|
+
* The types for the **crosswalk resolvers**: the CMS ICD-9↔ICD-10 **GEMs**
|
|
2311
2311
|
* (General Equivalence Mappings) and the NLM **SNOMED CT → ICD-10-CM complex map**.
|
|
2312
2312
|
*
|
|
2313
2313
|
* Both are the library's highest-risk surface, and their types are built around the stewards' own
|
|
2314
|
-
* warnings: these maps are **approximate, 1:many, context-dependent, and non-invertible
|
|
2314
|
+
* warnings: these maps are **approximate, 1:many, context-dependent, and non-invertible**, *"not
|
|
2315
2315
|
* crosswalks… reference mappings"* (CMS on the GEMs), *"semi-automated"* (NLM on the SNOMED map). So
|
|
2316
2316
|
* every result type here is a **discriminated, fail-safe outcome** carrying the steward's flags,
|
|
2317
2317
|
* never a single collapsed target:
|
|
2318
2318
|
*
|
|
2319
|
-
* - a No-Map is a typed {@link CrosswalkNoMap}
|
|
2319
|
+
* - a No-Map is a typed {@link CrosswalkNoMap}: the steward said "cannot be classified", surfaced,
|
|
2320
2320
|
* never a guessed code;
|
|
2321
2321
|
* - a 1:many source yields the **whole** ordered candidate set, never one confident pick;
|
|
2322
|
-
* - a context-dependent rule with no runtime context is a typed {@link ComplexMapContextRequired}
|
|
2322
|
+
* - a context-dependent rule with no runtime context is a typed {@link ComplexMapContextRequired}:
|
|
2323
2323
|
* the rule + advice ride through, the engine never picks a branch it wasn't given the data for;
|
|
2324
2324
|
* - all Map Advice / GEM flags ride through **verbatim** (advice flags must not be swallowed);
|
|
2325
2325
|
* - a directional map is **never inverted** (see {@link ../crosswalk/gems.invertGem}).
|
|
@@ -2329,7 +2329,7 @@ declare function loadUcumEssence(): UcumEssence;
|
|
|
2329
2329
|
|
|
2330
2330
|
/**
|
|
2331
2331
|
* The **direction** of a loaded GEM file. CMS ships the forward (ICD-9→ICD-10, `…_I9gem.txt`) and
|
|
2332
|
-
* backward (ICD-10→ICD-9, `…_I10gem.txt`) maps as **separate, non-inverse artifacts
|
|
2332
|
+
* backward (ICD-10→ICD-9, `…_I10gem.txt`) maps as **separate, non-inverse artifacts**: a forward map
|
|
2333
2333
|
* composed with a backward map is *"not a mirror image"*. A `GemMap` therefore records
|
|
2334
2334
|
* which direction it is and is only ever applied in that direction.
|
|
2335
2335
|
*/
|
|
@@ -2342,31 +2342,31 @@ type GemDirection = "9-to-10" | "10-to-9";
|
|
|
2342
2342
|
*/
|
|
2343
2343
|
interface GemFlags {
|
|
2344
2344
|
/**
|
|
2345
|
-
* Position 1
|
|
2345
|
+
* Position 1: **approximate** flag. `true` when the mapping is approximate (the common case: the
|
|
2346
2346
|
* source and target are not identical in meaning); `false` when the entry is an exact identity. A
|
|
2347
|
-
* GEM entry is a *reference* mapping either way
|
|
2347
|
+
* GEM entry is a *reference* mapping either way: never an assertion of clinical equivalence.
|
|
2348
2348
|
*/
|
|
2349
2349
|
readonly approximate: boolean;
|
|
2350
2350
|
/**
|
|
2351
|
-
* Position 2
|
|
2352
|
-
* classification (the target field is the `NoDx`/`NoPCS` sentinel). A first-class typed outcome
|
|
2351
|
+
* Position 2: **no-map** flag. `true` when the source code has **no valid target** in the other
|
|
2352
|
+
* classification (the target field is the `NoDx`/`NoPCS` sentinel). A first-class typed outcome:
|
|
2353
2353
|
* surfaced as a {@link CrosswalkNoMap}, never a fabricated target.
|
|
2354
2354
|
*/
|
|
2355
2355
|
readonly noMap: boolean;
|
|
2356
2356
|
/**
|
|
2357
|
-
* Position 3
|
|
2357
|
+
* Position 3: **combination** flag. `true` when the source requires a **combination** of target
|
|
2358
2358
|
* codes to be fully represented; the entry is one candidate within a scenario/choice-list cluster
|
|
2359
2359
|
* (see {@link scenario} / {@link choiceList}), never a standalone 1:1 target.
|
|
2360
2360
|
*/
|
|
2361
2361
|
readonly combination: boolean;
|
|
2362
2362
|
/**
|
|
2363
|
-
* Position 4
|
|
2363
|
+
* Position 4: **scenario** number (`0` for a non-combination entry). Within a combination, all
|
|
2364
2364
|
* entries sharing a scenario describe **one** valid way to represent the source; distinct scenarios
|
|
2365
2365
|
* are alternative representations.
|
|
2366
2366
|
*/
|
|
2367
2367
|
readonly scenario: number;
|
|
2368
2368
|
/**
|
|
2369
|
-
* Position 5
|
|
2369
|
+
* Position 5: **choice-list** number (`0` for a non-combination entry). Within a scenario, a valid
|
|
2370
2370
|
* cluster is built by taking **one** target from each distinct choice list.
|
|
2371
2371
|
*/
|
|
2372
2372
|
readonly choiceList: number;
|
|
@@ -2374,33 +2374,33 @@ interface GemFlags {
|
|
|
2374
2374
|
readonly raw: string;
|
|
2375
2375
|
}
|
|
2376
2376
|
/**
|
|
2377
|
-
* One loaded GEM entry
|
|
2377
|
+
* One loaded GEM entry: a source code, its (optional) target, and the decoded {@link GemFlags}. A
|
|
2378
2378
|
* No-Map entry ({@link GemFlags.noMap}) carries **no** {@link target}: the source has no equivalent,
|
|
2379
2379
|
* and the engine never invents one.
|
|
2380
2380
|
*/
|
|
2381
2381
|
interface GemEntry {
|
|
2382
2382
|
/** The source code (in the map's source classification), verbatim. */
|
|
2383
2383
|
readonly source: string;
|
|
2384
|
-
/** The target code (in the map's target classification), verbatim
|
|
2384
|
+
/** The target code (in the map's target classification), verbatim: **absent** for a No-Map entry. */
|
|
2385
2385
|
readonly target?: string;
|
|
2386
2386
|
/** The decoded steward flags. */
|
|
2387
2387
|
readonly flags: GemFlags;
|
|
2388
2388
|
}
|
|
2389
2389
|
/**
|
|
2390
|
-
* A loaded, immutable GEM map. Entries are keyed by source code (a source may have many entries
|
|
2390
|
+
* A loaded, immutable GEM map. Entries are keyed by source code (a source may have many entries, the
|
|
2391
2391
|
* maps are 1:many). Applied **only** in its {@link direction}; never inverted.
|
|
2392
2392
|
*
|
|
2393
2393
|
* {@link entries} is a **read-only view**, not a `Map` you were handed, and each source's candidate
|
|
2394
2394
|
* list is frozen: nothing that holds a loaded map can delete a source's mapping, or add a target the
|
|
2395
2395
|
* steward's file never authored, and have {@link applyGem} answer from it.
|
|
2396
2396
|
*
|
|
2397
|
-
* A view is not a `Map` instance
|
|
2397
|
+
* A view is not a `Map` instance: `instanceof Map` is `false` and this model cannot be
|
|
2398
2398
|
* `structuredClone`d or posted to a worker; copy out what you need (`new Map(…)`).
|
|
2399
2399
|
*/
|
|
2400
2400
|
interface GemMap {
|
|
2401
2401
|
/** Which direction this file maps. Applied only this way. */
|
|
2402
2402
|
readonly direction: GemDirection;
|
|
2403
|
-
/** The GEM version/release (e.g. `"2018"`), when supplied
|
|
2403
|
+
/** The GEM version/release (e.g. `"2018"`), when supplied: mappings are release-scoped. */
|
|
2404
2404
|
readonly version?: string;
|
|
2405
2405
|
/** The number of loaded entries. */
|
|
2406
2406
|
readonly count: number;
|
|
@@ -2410,7 +2410,7 @@ interface GemMap {
|
|
|
2410
2410
|
readonly warnings: readonly GemLoadWarning[];
|
|
2411
2411
|
}
|
|
2412
2412
|
/**
|
|
2413
|
-
* A surfaced, non-fatal GEM load warning
|
|
2413
|
+
* A surfaced, non-fatal GEM load warning: a malformed line that was **skipped**, reported with its
|
|
2414
2414
|
* line number and a value-free structural reason. Liberal on load (the parsers' posture).
|
|
2415
2415
|
*/
|
|
2416
2416
|
interface GemLoadWarning {
|
|
@@ -2421,7 +2421,7 @@ interface GemLoadWarning {
|
|
|
2421
2421
|
/** A value-free description of the structural fault (never echoes a field value). */
|
|
2422
2422
|
readonly detail: string;
|
|
2423
2423
|
}
|
|
2424
|
-
/** One choice list within a combination scenario
|
|
2424
|
+
/** One choice list within a combination scenario: pick **one** of its targets to build a cluster. */
|
|
2425
2425
|
interface GemChoiceList {
|
|
2426
2426
|
/** The choice-list number ({@link GemFlags.choiceList}). */
|
|
2427
2427
|
readonly choiceList: number;
|
|
@@ -2429,7 +2429,7 @@ interface GemChoiceList {
|
|
|
2429
2429
|
readonly targets: readonly string[];
|
|
2430
2430
|
}
|
|
2431
2431
|
/**
|
|
2432
|
-
* One combination **scenario
|
|
2432
|
+
* One combination **scenario**: a single valid way to represent the source as a combination of
|
|
2433
2433
|
* target codes. A valid **cluster** is one target taken from each of its {@link choiceLists}.
|
|
2434
2434
|
*/
|
|
2435
2435
|
interface GemScenario {
|
|
@@ -2439,7 +2439,7 @@ interface GemScenario {
|
|
|
2439
2439
|
readonly choiceLists: readonly GemChoiceList[];
|
|
2440
2440
|
}
|
|
2441
2441
|
/**
|
|
2442
|
-
* A successful GEM application
|
|
2442
|
+
* A successful GEM application: one or more candidate targets for the source. The **full** candidate
|
|
2443
2443
|
* set is surfaced (never collapsed to one); when the source is a combination, {@link combinations}
|
|
2444
2444
|
* carries the scenario/choice-list structure needed to build valid clusters.
|
|
2445
2445
|
*/
|
|
@@ -2456,7 +2456,7 @@ interface GemMatched {
|
|
|
2456
2456
|
readonly combinations?: readonly GemScenario[];
|
|
2457
2457
|
}
|
|
2458
2458
|
/**
|
|
2459
|
-
* One row of the SNOMED CT → ICD-10-CM **complex/extended map** refset
|
|
2459
|
+
* One row of the SNOMED CT → ICD-10-CM **complex/extended map** refset: the caller-supplied,
|
|
2460
2460
|
* SNOMED-licensed content the resolver runs over (**no SNOMED CT refset is bundled**). The field
|
|
2461
2461
|
* names paraphrase the SNOMED RF2 extended-map refset columns.
|
|
2462
2462
|
*/
|
|
@@ -2464,7 +2464,7 @@ interface ComplexMapEntry {
|
|
|
2464
2464
|
/** The SNOMED CT source concept id (`referencedComponentId`), verbatim. */
|
|
2465
2465
|
readonly source: string;
|
|
2466
2466
|
/**
|
|
2467
|
-
* The **map group** (1-based). Distinct groups on one source are an **AND
|
|
2467
|
+
* The **map group** (1-based). Distinct groups on one source are an **AND**: the source needs a
|
|
2468
2468
|
* target from *each* group (e.g. a manifestation code plus an etiology code). Every group resolves
|
|
2469
2469
|
* independently.
|
|
2470
2470
|
*/
|
|
@@ -2475,17 +2475,17 @@ interface ComplexMapEntry {
|
|
|
2475
2475
|
*/
|
|
2476
2476
|
readonly priority: number;
|
|
2477
2477
|
/**
|
|
2478
|
-
* The **map rule**, verbatim
|
|
2478
|
+
* The **map rule**, verbatim: `"TRUE"` / `"OTHERWISE TRUE"` (unconditional fall-through), or an
|
|
2479
2479
|
* `IFA` predicate (e.g. an age-band or gender test) evaluated against caller-supplied context.
|
|
2480
2480
|
*/
|
|
2481
2481
|
readonly rule: string;
|
|
2482
2482
|
/**
|
|
2483
|
-
* The **map advice**, verbatim (pipe-delimited in the source)
|
|
2483
|
+
* The **map advice**, verbatim (pipe-delimited in the source): steward instructions to a human
|
|
2484
2484
|
* (`CONSIDER LATERALITY`, `EPISODE OF CARE INFORMATION NEEDED`, `THIS IS A MANIFESTATION CODE…`).
|
|
2485
2485
|
* Carried through untouched: advice flags must **never** be swallowed.
|
|
2486
2486
|
*/
|
|
2487
2487
|
readonly advice: string;
|
|
2488
|
-
/** The ICD-10-CM **map target** code, verbatim
|
|
2488
|
+
/** The ICD-10-CM **map target** code, verbatim: **absent** for a No-Map / empty-target row. */
|
|
2489
2489
|
readonly target?: string;
|
|
2490
2490
|
/** The steward **map category** id (a `MAP_CATEGORIES` value, e.g. `447638001`), when supplied. */
|
|
2491
2491
|
readonly category?: string;
|
|
@@ -2500,11 +2500,11 @@ interface ComplexMapEntry {
|
|
|
2500
2500
|
* is frozen: nothing that holds a loaded map can delete a source concept's rules, or add one your
|
|
2501
2501
|
* refset never carried, and have {@link applyComplexMap} resolve from it.
|
|
2502
2502
|
*
|
|
2503
|
-
* A view is not a `Map` instance
|
|
2503
|
+
* A view is not a `Map` instance: `instanceof Map` is `false` and this model cannot be
|
|
2504
2504
|
* `structuredClone`d or posted to a worker; copy out what you need (`new Map(…)`).
|
|
2505
2505
|
*/
|
|
2506
2506
|
interface ComplexMap {
|
|
2507
|
-
/** The map version/release, when supplied
|
|
2507
|
+
/** The map version/release, when supplied: mappings are release-scoped. */
|
|
2508
2508
|
readonly version?: string;
|
|
2509
2509
|
/** The number of loaded rows. */
|
|
2510
2510
|
readonly count: number;
|
|
@@ -2513,7 +2513,7 @@ interface ComplexMap {
|
|
|
2513
2513
|
/** The skipped-row warnings surfaced during load, in line order. Frozen; may be empty. */
|
|
2514
2514
|
readonly warnings: readonly ComplexMapLoadWarning[];
|
|
2515
2515
|
}
|
|
2516
|
-
/** A surfaced, non-fatal complex-map load warning
|
|
2516
|
+
/** A surfaced, non-fatal complex-map load warning: a malformed refset row that was skipped. */
|
|
2517
2517
|
interface ComplexMapLoadWarning {
|
|
2518
2518
|
/** The stable diagnostic code for a skipped complex-map row. */
|
|
2519
2519
|
readonly code: "TERM_COMPLEX_MAP_MALFORMED_ROW";
|
|
@@ -2534,7 +2534,7 @@ interface PatientContext {
|
|
|
2534
2534
|
readonly gender?: "male" | "female";
|
|
2535
2535
|
}
|
|
2536
2536
|
/**
|
|
2537
|
-
* One map group's resolution
|
|
2537
|
+
* One map group's resolution: a discriminated outcome. A group resolves to a target, a No-Map, an
|
|
2538
2538
|
* ambiguity (candidates surfaced), or a context-required stall; it is **never** a silently-picked
|
|
2539
2539
|
* single target when the steward flagged otherwise.
|
|
2540
2540
|
*/
|
|
@@ -2555,7 +2555,7 @@ interface ComplexMapGroupResolved {
|
|
|
2555
2555
|
readonly rule: string;
|
|
2556
2556
|
}
|
|
2557
2557
|
/**
|
|
2558
|
-
* A group the steward marked **No-Map** (`447638001` "cannot be classified", or an empty target)
|
|
2558
|
+
* A group the steward marked **No-Map** (`447638001` "cannot be classified", or an empty target): a
|
|
2559
2559
|
* typed, surfaced outcome, never a fabricated target.
|
|
2560
2560
|
*/
|
|
2561
2561
|
interface ComplexMapGroupNoMap {
|
|
@@ -2573,7 +2573,7 @@ interface ComplexMapGroupNoMap {
|
|
|
2573
2573
|
/**
|
|
2574
2574
|
* A group whose winning path is a **context-dependent** `IFA` rule (or `447639009`/`447640006`
|
|
2575
2575
|
* category) for which the caller supplied **no** matching context. The engine surfaces the rules +
|
|
2576
|
-
* advice and refuses to pick a branch
|
|
2576
|
+
* advice and refuses to pick a branch: the never-fabricate rule for runtime context.
|
|
2577
2577
|
*/
|
|
2578
2578
|
interface ComplexMapContextRequired {
|
|
2579
2579
|
/** Discriminant. */
|
|
@@ -2585,7 +2585,7 @@ interface ComplexMapContextRequired {
|
|
|
2585
2585
|
/** The unresolved candidate rules in this group (priority order), each with its target + advice. */
|
|
2586
2586
|
readonly rules: readonly ComplexMapEntry[];
|
|
2587
2587
|
}
|
|
2588
|
-
/** A successful complex-map application
|
|
2588
|
+
/** A successful complex-map application: one resolution **per map group**, in group order. */
|
|
2589
2589
|
interface ComplexMapMatched {
|
|
2590
2590
|
/** Discriminant: the source concept is present in the map. */
|
|
2591
2591
|
readonly mapped: true;
|
|
@@ -2595,7 +2595,7 @@ interface ComplexMapMatched {
|
|
|
2595
2595
|
readonly groups: readonly ComplexMapGroupResult[];
|
|
2596
2596
|
}
|
|
2597
2597
|
/**
|
|
2598
|
-
* A **No-Map** outcome
|
|
2598
|
+
* A **No-Map** outcome: the source is present in the map but the steward declares it has no valid
|
|
2599
2599
|
* target ("cannot be classified with available data"). A first-class typed result, **never** a
|
|
2600
2600
|
* fabricated target. Distinct from {@link CrosswalkUnmapped} (source absent entirely).
|
|
2601
2601
|
*/
|
|
@@ -2612,7 +2612,7 @@ interface CrosswalkNoMap {
|
|
|
2612
2612
|
readonly entries: readonly GemEntry[];
|
|
2613
2613
|
}
|
|
2614
2614
|
/**
|
|
2615
|
-
* An **unmapped** outcome
|
|
2615
|
+
* An **unmapped** outcome: the source code is **not present in the map at all** (distinct from an
|
|
2616
2616
|
* authored No-Map). Surfaced as a typed result, never a guessed target and never a silent success.
|
|
2617
2617
|
*/
|
|
2618
2618
|
interface CrosswalkUnmapped {
|
|
@@ -2637,9 +2637,9 @@ type ComplexMapApplyResult = ComplexMapMatched | CrosswalkUnmapped;
|
|
|
2637
2637
|
* The CMS **ICD-9 ↔ ICD-10 GEMs** (General Equivalence Mappings) loader + applier.
|
|
2638
2638
|
*
|
|
2639
2639
|
* The GEMs are **CMS/NCHS public-domain** (US-government work) reference mappings between the ICD-9-CM
|
|
2640
|
-
* and ICD-10-CM diagnosis classifications. CMS is emphatic about what they are
|
|
2640
|
+
* and ICD-10-CM diagnosis classifications. CMS is emphatic about what they are: *"GEMs are not
|
|
2641
2641
|
* crosswalks. They are reference mappings… the raw material from which providers… derive specific
|
|
2642
|
-
* applied mappings"
|
|
2642
|
+
* applied mappings"*, so this resolver treats a GEM hit as a **candidate**, never an equivalence:
|
|
2643
2643
|
*
|
|
2644
2644
|
* - **Approximate by default.** Position-1 flag: most entries are approximate (source and target are
|
|
2645
2645
|
* not identical in meaning). The flag rides through; the engine asserts nothing beyond it.
|
|
@@ -2658,7 +2658,7 @@ type ComplexMapApplyResult = ComplexMapMatched | CrosswalkUnmapped;
|
|
|
2658
2658
|
*/
|
|
2659
2659
|
|
|
2660
2660
|
/**
|
|
2661
|
-
* A raw GEM source file, plus the direction it maps and its release version. BYO
|
|
2661
|
+
* A raw GEM source file, plus the direction it maps and its release version. BYO: the caller
|
|
2662
2662
|
* supplies the public-domain CMS GEM file content.
|
|
2663
2663
|
*/
|
|
2664
2664
|
interface GemSource {
|
|
@@ -2666,7 +2666,7 @@ interface GemSource {
|
|
|
2666
2666
|
readonly content: string;
|
|
2667
2667
|
/** Which direction this file maps (`"9-to-10"` for `…_I9gem.txt`, `"10-to-9"` for `…_I10gem.txt`). */
|
|
2668
2668
|
readonly direction: GemDirection;
|
|
2669
|
-
/** The GEM release/version (e.g. `"2018"`), when known
|
|
2669
|
+
/** The GEM release/version (e.g. `"2018"`), when known: mappings are release-scoped. */
|
|
2670
2670
|
readonly version?: string;
|
|
2671
2671
|
}
|
|
2672
2672
|
/**
|
|
@@ -2675,7 +2675,7 @@ interface GemSource {
|
|
|
2675
2675
|
* Liberal on load: a structurally unusable *line* (not three whitespace-delimited fields, or a
|
|
2676
2676
|
* malformed 5-digit flag) is **skipped and surfaced** as a {@link GemLoadWarning}, never a
|
|
2677
2677
|
* partially-parsed entry. An unusable *source* is not possible here (an all-malformed file loads to an
|
|
2678
|
-
* empty map with warnings)
|
|
2678
|
+
* empty map with warnings): there is no fatal for GEM load. Ships **no** GEM content: the entries are
|
|
2679
2679
|
* the caller's public-domain file.
|
|
2680
2680
|
*
|
|
2681
2681
|
* @param source - The {@link GemSource} (raw content + direction + version).
|
|
@@ -2700,7 +2700,7 @@ declare function loadGems(source: GemSource): GemMap;
|
|
|
2700
2700
|
* Returns the **full** candidate set (never collapsed to one), with each entry's steward flags; a
|
|
2701
2701
|
* combination source additionally surfaces its scenario/choice-list structure. A source the steward
|
|
2702
2702
|
* marked No-Map (`NoDx` sentinel) is a typed {@link CrosswalkNoMap}; a source **absent** from the map
|
|
2703
|
-
* is a typed {@link CrosswalkUnmapped}
|
|
2703
|
+
* is a typed {@link CrosswalkUnmapped}: the two are distinct, and neither is ever a fabricated code.
|
|
2704
2704
|
*
|
|
2705
2705
|
* @param map - A {@link GemMap} from {@link loadGems}.
|
|
2706
2706
|
* @param source - The source code (in the map's source classification).
|
|
@@ -2719,12 +2719,12 @@ declare function applyGem(map: GemMap, source: string): GemApplyResult;
|
|
|
2719
2719
|
* Refuse to invert a directional GEM map. **Always throws** {@link FATAL_CODES.TERM_MAP_NOT_INVERTIBLE}.
|
|
2720
2720
|
*
|
|
2721
2721
|
* The never-invert invariant made explicit and discoverable: a forward GEM (9→10) is **not** the
|
|
2722
|
-
* inverse of the backward GEM (10→9)
|
|
2722
|
+
* inverse of the backward GEM (10→9): CMS ships them as separate artifacts and *"forward and
|
|
2723
2723
|
* backward mappings are not simply the reverse"*. To resolve the other direction, load
|
|
2724
2724
|
* the other file with {@link loadGems}; the engine never synthesizes an inverse.
|
|
2725
2725
|
*
|
|
2726
2726
|
* @param map - The map an inversion was (incorrectly) requested for.
|
|
2727
|
-
* @returns Never
|
|
2727
|
+
* @returns Never: always throws.
|
|
2728
2728
|
* @throws {TerminologyError} `TERM_MAP_NOT_INVERTIBLE`, always.
|
|
2729
2729
|
* @example
|
|
2730
2730
|
* ```ts runnable throws
|
|
@@ -2737,15 +2737,15 @@ declare function applyGem(map: GemMap, source: string): GemApplyResult;
|
|
|
2737
2737
|
declare function invertGem(map: GemMap): never;
|
|
2738
2738
|
|
|
2739
2739
|
/**
|
|
2740
|
-
* The **SNOMED CT → ICD-10-CM complex-map** resolver
|
|
2740
|
+
* The **SNOMED CT → ICD-10-CM complex-map** resolver: a rule-based, **BYO**
|
|
2741
2741
|
* resolver over the caller-supplied complex/extended-map refset. **No SNOMED CT refset or release is
|
|
2742
2742
|
* bundled**: the engine ships the rule machinery; the caller supplies the map rows from their own
|
|
2743
2743
|
* SNOMED CT release. (Individual SNOMED CT concepts this resolver *names* are bundled: the
|
|
2744
|
-
* map-category concepts a row's `mapCategoryId` refers to
|
|
2745
|
-
* {@link ../crosswalk/categories.MAP_CATEGORIES}
|
|
2744
|
+
* map-category concepts a row's `mapCategoryId` refers to (see
|
|
2745
|
+
* {@link ../crosswalk/categories.MAP_CATEGORIES}), and the two gender findings a gender `IFA` rule
|
|
2746
2746
|
* is written against.)
|
|
2747
2747
|
*
|
|
2748
|
-
* The map is *"semi-automated"* by the steward's own statement
|
|
2748
|
+
* The map is *"semi-automated"* by the steward's own statement, 1:many, context-dependent, with
|
|
2749
2749
|
* first-class No-Map states. The resolver honours that:
|
|
2750
2750
|
*
|
|
2751
2751
|
* - **Map groups are an AND.** A source needing a manifestation *and* an etiology code has two groups;
|
|
@@ -2754,19 +2754,19 @@ declare function invertGem(map: GemMap): never;
|
|
|
2754
2754
|
* whose `IFA` predicate the caller's context satisfies wins.
|
|
2755
2755
|
* - **Context it wasn't given, it never guesses.** If deciding a group requires an `IFA` predicate
|
|
2756
2756
|
* (an age band, a gender) the caller left unspecified, the group is a typed
|
|
2757
|
-
* {@link ComplexMapContextRequired} carrying the candidate rules + advice
|
|
2757
|
+
* {@link ComplexMapContextRequired} carrying the candidate rules + advice: never a silently-picked
|
|
2758
2758
|
* branch.
|
|
2759
2759
|
* - **No-Map is typed.** A `447638001` "cannot be classified" row (or an empty target) is a typed
|
|
2760
2760
|
* No-Map, never a fabricated code.
|
|
2761
2761
|
* - **Advice rides through verbatim.** `CONSIDER LATERALITY`, `EPISODE OF CARE INFORMATION NEEDED`,
|
|
2762
|
-
* manifestation-code advice
|
|
2762
|
+
* manifestation-code advice: carried untouched to the caller.
|
|
2763
2763
|
* - **Never inverted.** The map is applied SNOMED→ICD-10-CM only; the reverse is a separate artifact.
|
|
2764
2764
|
*
|
|
2765
2765
|
* @packageDocumentation
|
|
2766
2766
|
*/
|
|
2767
2767
|
|
|
2768
2768
|
/**
|
|
2769
|
-
* The discriminated input {@link loadComplexMap} accepts
|
|
2769
|
+
* The discriminated input {@link loadComplexMap} accepts: already-structured refset rows, or a raw
|
|
2770
2770
|
* RF2 tab-delimited extended-map refset the caller exported from their SNOMED release.
|
|
2771
2771
|
*/
|
|
2772
2772
|
type ComplexMapInput = {
|
|
@@ -2784,7 +2784,7 @@ type ComplexMapInput = {
|
|
|
2784
2784
|
*
|
|
2785
2785
|
* Liberal on load: a structurally unusable RF2 *row* is skipped and surfaced as a warning; only an
|
|
2786
2786
|
* unusable *source* (empty content, header missing required columns) is a fatal
|
|
2787
|
-
* {@link FATAL_CODES.TERM_CROSSWALK_MALFORMED}. Ships **no** SNOMED CT release or refset
|
|
2787
|
+
* {@link FATAL_CODES.TERM_CROSSWALK_MALFORMED}. Ships **no** SNOMED CT release or refset: the rows
|
|
2788
2788
|
* are the caller's, under their own licence.
|
|
2789
2789
|
*
|
|
2790
2790
|
* @param input - Structured `rows`, or a raw RF2 extended-map refset `content`.
|
|
@@ -2807,7 +2807,7 @@ declare function loadComplexMap(input: ComplexMapInput): ComplexMap;
|
|
|
2807
2807
|
/**
|
|
2808
2808
|
* Apply a loaded SNOMED→ICD-10-CM complex map to a source concept and patient context.
|
|
2809
2809
|
*
|
|
2810
|
-
* Resolves **each map group** independently (groups are an AND
|
|
2810
|
+
* Resolves **each map group** independently (groups are an AND, a source needing multiple ICD-10-CM
|
|
2811
2811
|
* codes has multiple groups) by running its rules in priority order against `context`. A group whose
|
|
2812
2812
|
* decision needs `IFA` context the caller did not supply is a typed
|
|
2813
2813
|
* {@link ComplexMapContextRequired}; a `447638001` row is a typed No-Map; every result carries the
|
|
@@ -2817,7 +2817,7 @@ declare function loadComplexMap(input: ComplexMapInput): ComplexMap;
|
|
|
2817
2817
|
* @param source - The SNOMED CT source concept id.
|
|
2818
2818
|
* @param context - The caller-supplied {@link PatientContext} (age / gender). Optional; a missing
|
|
2819
2819
|
* field that a rule needs yields a `context-required` group, never a guessed branch.
|
|
2820
|
-
* @returns A {@link ComplexMapApplyResult}
|
|
2820
|
+
* @returns A {@link ComplexMapApplyResult}: per-group resolutions, or a typed absence.
|
|
2821
2821
|
* @example
|
|
2822
2822
|
* ```ts
|
|
2823
2823
|
* import { loadComplexMap, applyComplexMap } from "@cosyte/terminology";
|
|
@@ -2839,10 +2839,10 @@ declare const COMPLEX_MAP_SOURCE_SYSTEM = "http://snomed.info/sct";
|
|
|
2839
2839
|
|
|
2840
2840
|
/**
|
|
2841
2841
|
* Steward-defined **map category** and **map-relationship** identifiers the crosswalk resolvers carry
|
|
2842
|
-
* through verbatim
|
|
2842
|
+
* through verbatim: the SNOMED CT complex-map `mapCategoryId` concepts and the map-correlation
|
|
2843
2843
|
* concepts. These are SNOMED CT metadata concepts, and **they are bundled**: the four ids below and
|
|
2844
2844
|
* their steward descriptions ship inside this package. SNOMED CT is copyright © International Health
|
|
2845
|
-
* Terminology Standards Development Organisation. **No SNOMED CT refset or release is bundled
|
|
2845
|
+
* Terminology Standards Development Organisation. **No SNOMED CT refset or release is bundled**: a
|
|
2846
2846
|
* caller still supplies the map refset itself under their own SNOMED CT licence (the BYO posture).
|
|
2847
2847
|
*
|
|
2848
2848
|
* The category on a resolved SNOMED→ICD-10-CM map row is the steward telling the caller *how much to
|
|
@@ -2854,8 +2854,8 @@ declare const COMPLEX_MAP_SOURCE_SYSTEM = "http://snomed.info/sct";
|
|
|
2854
2854
|
* @packageDocumentation
|
|
2855
2855
|
*/
|
|
2856
2856
|
/**
|
|
2857
|
-
* The SNOMED CT complex-map **map category** concept ids
|
|
2858
|
-
* SNOMED→ICD-10-CM extended-map refset. These four SNOMED CT concepts
|
|
2857
|
+
* The SNOMED CT complex-map **map category** concept ids: the `mapCategoryId` column of the
|
|
2858
|
+
* SNOMED→ICD-10-CM extended-map refset. These four SNOMED CT concepts (id and steward description)
|
|
2859
2859
|
* are **bundled** in this package (SNOMED CT is copyright © International Health Terminology
|
|
2860
2860
|
* Standards Development Organisation); carried through a resolution verbatim so a caller sees the
|
|
2861
2861
|
* steward's own trust signal.
|
|
@@ -2868,16 +2868,16 @@ declare const COMPLEX_MAP_SOURCE_SYSTEM = "http://snomed.info/sct";
|
|
|
2868
2868
|
* ```
|
|
2869
2869
|
*/
|
|
2870
2870
|
declare const MAP_CATEGORIES: {
|
|
2871
|
-
/** `447637006
|
|
2871
|
+
/** `447637006`: "Map source concept is properly classified" (a normal, usable target). */
|
|
2872
2872
|
readonly PROPERLY_CLASSIFIED: "447637006";
|
|
2873
|
-
/** `447638001
|
|
2873
|
+
/** `447638001`: "Map source concept cannot be classified with available data" (a **No-Map**). */
|
|
2874
2874
|
readonly NO_MAP: "447638001";
|
|
2875
|
-
/** `447639009
|
|
2875
|
+
/** `447639009`: "Map of source concept is context dependent" (needs runtime patient context). */
|
|
2876
2876
|
readonly CONTEXT_DEPENDENT: "447639009";
|
|
2877
|
-
/** `447640006
|
|
2877
|
+
/** `447640006`: "Source concept is ambiguous" (surface candidates, never pick one). */
|
|
2878
2878
|
readonly AMBIGUOUS: "447640006";
|
|
2879
2879
|
};
|
|
2880
|
-
/** A value from {@link MAP_CATEGORIES}
|
|
2880
|
+
/** A value from {@link MAP_CATEGORIES}: the SNOMED map-category id carried on a resolution. */
|
|
2881
2881
|
type MapCategoryId = (typeof MAP_CATEGORIES)[keyof typeof MAP_CATEGORIES];
|
|
2882
2882
|
/**
|
|
2883
2883
|
* The set of {@link MAP_CATEGORIES} ids the resolver treats as a **No-Map** (a typed, surfaced
|
|
@@ -2885,7 +2885,7 @@ type MapCategoryId = (typeof MAP_CATEGORIES)[keyof typeof MAP_CATEGORIES];
|
|
|
2885
2885
|
*/
|
|
2886
2886
|
declare const NO_MAP_CATEGORIES: ReadonlySet<string>;
|
|
2887
2887
|
/**
|
|
2888
|
-
* The canonical code-system URI for **ICD-10-CM
|
|
2888
|
+
* The canonical code-system URI for **ICD-10-CM**: the target system of both crosswalks. A published
|
|
2889
2889
|
* identity fact (mirrors {@link ../systems/registry.SYSTEM_IDENTITIES}); attached to a resolved
|
|
2890
2890
|
* target {@link ../common/coding.Coding} so a translation is self-describing.
|
|
2891
2891
|
*/
|
|
@@ -2896,13 +2896,13 @@ declare const ICD10CM_SYSTEM = "http://hl7.org/fhir/sid/icd-10-cm";
|
|
|
2896
2896
|
*/
|
|
2897
2897
|
declare const ICD9CM_SYSTEM = "http://hl7.org/fhir/sid/icd-9-cm";
|
|
2898
2898
|
/**
|
|
2899
|
-
* The canonical code-system URI for **SNOMED CT
|
|
2899
|
+
* The canonical code-system URI for **SNOMED CT**: the source system of the SNOMED→ICD-10-CM complex
|
|
2900
2900
|
* map. Recognised by URI only; **no SNOMED CT refset or release is bundled**.
|
|
2901
2901
|
*/
|
|
2902
2902
|
declare const SNOMEDCT_SYSTEM = "http://snomed.info/sct";
|
|
2903
2903
|
|
|
2904
2904
|
/**
|
|
2905
|
-
* The types for the **RxNorm drug relationship graph
|
|
2905
|
+
* The types for the **RxNorm drug relationship graph**: the ingredient / brand /
|
|
2906
2906
|
* clinical-drug / dose-form graph navigated over a **caller-supplied** RxNorm RRF release.
|
|
2907
2907
|
*
|
|
2908
2908
|
* RxNorm is the US NLM's normalized drug nomenclature. Its concepts (`RXCUI`s) are typed by **term
|
|
@@ -2916,13 +2916,13 @@ declare const SNOMEDCT_SYSTEM = "http://snomed.info/sct";
|
|
|
2916
2916
|
*
|
|
2917
2917
|
* **The direction convention is a documented medication-safety trap**, and it
|
|
2918
2918
|
* is grounded here firsthand on the NLM RxNorm Technical Documentation (§12.7) and the UMLS Reference
|
|
2919
|
-
* Manual: *"the direction of REL
|
|
2919
|
+
* Manual: *"the direction of REL, the relationship which the SECOND concept or atom (with … RXCUI2
|
|
2920
2920
|
* …) HAS TO the FIRST concept or atom (with … RXCUI1 …)."* So every `RXNREL` row `(RXCUI1, …, RELA,
|
|
2921
2921
|
* RXCUI2, …)` is read **`RXCUI2 ⟶RELA⟶ RXCUI1`** and normalized at load into a
|
|
2922
2922
|
* {@link RxNormEdge} with `subject = RXCUI2`, `predicate = RELA`, `object = RXCUI1`. Navigation only
|
|
2923
2923
|
* ever follows **authored** edges by their predicate; the engine **never synthesizes an inverse edge**
|
|
2924
2924
|
* (RxNorm already ships both directions of an asymmetric relationship as separate rows) and **never
|
|
2925
|
-
* fabricates** an `RXCUI` or a relationship absent from the loaded data
|
|
2925
|
+
* fabricates** an `RXCUI` or a relationship absent from the loaded data: an absent concept is a typed
|
|
2926
2926
|
* {@link RxNormUnknown}, an unresolvable NDC a typed {@link NdcUnmapped}, never a guess.
|
|
2927
2927
|
*
|
|
2928
2928
|
* **No RxNorm release is bundled**: the engine ships the graph *machinery*, and RxNorm's
|
|
@@ -2933,7 +2933,7 @@ declare const SNOMEDCT_SYSTEM = "http://snomed.info/sct";
|
|
|
2933
2933
|
* @packageDocumentation
|
|
2934
2934
|
*/
|
|
2935
2935
|
/**
|
|
2936
|
-
* A RxNorm **term type** (`TTY`)
|
|
2936
|
+
* A RxNorm **term type** (`TTY`): the kind of drug concept an `RXCUI` names. These are the
|
|
2937
2937
|
* `RXNCONSO.RRF` `TTY` values relevant to the drug graph, grounded on the NLM RxNorm Technical
|
|
2938
2938
|
* Documentation (Appendix 5). Carried verbatim on a {@link RxNormConcept}; the engine classifies but
|
|
2939
2939
|
* never re-labels a concept.
|
|
@@ -2945,7 +2945,7 @@ declare const SNOMEDCT_SYSTEM = "http://snomed.info/sct";
|
|
|
2945
2945
|
*/
|
|
2946
2946
|
type TermType = "IN" | "PIN" | "MIN" | "BN" | "SCDC" | "SBDC" | "SCDF" | "SBDF" | "SCDFP" | "SBDFP" | "SCD" | "SBD" | "SCDG" | "SBDG" | "SCDGP" | "GPCK" | "BPCK" | "DF" | "DFG" | "PSN" | "SY" | "TMSY" | "ET";
|
|
2947
2947
|
/**
|
|
2948
|
-
* One RxNorm concept (`RXCUI`) as loaded from `RXNCONSO.RRF
|
|
2948
|
+
* One RxNorm concept (`RXCUI`) as loaded from `RXNCONSO.RRF`: its normalized name and term type.
|
|
2949
2949
|
* Built from the concept's `SAB=RXNORM` atom (the normalized form); the verbatim `RXCUI`, `TTY`, and
|
|
2950
2950
|
* `STR` (name) ride through untouched.
|
|
2951
2951
|
*/
|
|
@@ -2959,26 +2959,26 @@ interface RxNormConcept {
|
|
|
2959
2959
|
readonly tty: TermType;
|
|
2960
2960
|
/** The concept's normalized name (`RXNCONSO.STR`), verbatim. */
|
|
2961
2961
|
readonly name: string;
|
|
2962
|
-
/** `true` when the source atom is suppressed (`RXNCONSO.SUPPRESS` ≠ `N`)
|
|
2962
|
+
/** `true` when the source atom is suppressed (`RXNCONSO.SUPPRESS` ≠ `N`): surfaced, never hidden. */
|
|
2963
2963
|
readonly suppressed: boolean;
|
|
2964
2964
|
}
|
|
2965
2965
|
/**
|
|
2966
2966
|
* One directed relationship edge, normalized from an `RXNREL.RRF` row under the documented direction
|
|
2967
2967
|
* convention (see the module doc): the row `(RXCUI1, …, RELA, RXCUI2, …)` becomes
|
|
2968
|
-
* `subject = RXCUI2`, `predicate = RELA`, `object = RXCUI1
|
|
2968
|
+
* `subject = RXCUI2`, `predicate = RELA`, `object = RXCUI1`: read **`subject ⟶predicate⟶ object`**.
|
|
2969
2969
|
*/
|
|
2970
2970
|
interface RxNormEdge {
|
|
2971
|
-
/** The subject `RXCUI
|
|
2971
|
+
/** The subject `RXCUI`: `RXCUI2` in the source row. The concept the relationship is *from*. */
|
|
2972
2972
|
readonly subject: string;
|
|
2973
2973
|
/** The relationship label (`RXNREL.RELA`, e.g. `has_ingredient`), verbatim. */
|
|
2974
2974
|
readonly predicate: string;
|
|
2975
|
-
/** The object `RXCUI
|
|
2975
|
+
/** The object `RXCUI`: `RXCUI1` in the source row. The concept the relationship is *to*. */
|
|
2976
2976
|
readonly object: string;
|
|
2977
2977
|
}
|
|
2978
2978
|
/**
|
|
2979
2979
|
* A resolved **NDC → RXCUI** mapping (from an `RXNSAT.RRF` `ATN=NDC` attribute), carrying the
|
|
2980
2980
|
* temporal {@link NdcStatus} and the **as-of release** it is valid for. NDC↔RXCUI is many:1 and
|
|
2981
|
-
* changes across releases, so a resolution is never timeless
|
|
2981
|
+
* changes across releases, so a resolution is never timeless: the release rides
|
|
2982
2982
|
* through on {@link asOf}.
|
|
2983
2983
|
*/
|
|
2984
2984
|
interface NdcResolution {
|
|
@@ -2997,11 +2997,11 @@ interface NdcResolution {
|
|
|
2997
2997
|
* The temporal status of an NDC↔RXCUI mapping (RxNav `getNDCStatus`: `ACTIVE` / `OBSOLETE` / `ALIEN`
|
|
2998
2998
|
* / `UNKNOWN`). An NDC found in the loaded release's `RXNSAT` attributes is `active` **as of that
|
|
2999
2999
|
* release**; `obsolete` / `alien` come from the RxNav NDC-history data (a differential / BYO source,
|
|
3000
|
-
* not the base RRF concept files) and are surfaced only when the caller supplies them
|
|
3000
|
+
* not the base RRF concept files) and are surfaced only when the caller supplies them: the engine
|
|
3001
3001
|
* **never fabricates** a non-current status.
|
|
3002
3002
|
*/
|
|
3003
3003
|
type NdcStatus = "active" | "obsolete" | "alien" | "unknown";
|
|
3004
|
-
/** An NDC that could not be resolved to any `RXCUI` in the loaded release
|
|
3004
|
+
/** An NDC that could not be resolved to any `RXCUI` in the loaded release: a typed absence. */
|
|
3005
3005
|
interface NdcUnmapped {
|
|
3006
3006
|
/** Discriminant: the NDC is not present in the loaded release. */
|
|
3007
3007
|
readonly resolved: false;
|
|
@@ -3013,7 +3013,7 @@ interface NdcUnmapped {
|
|
|
3013
3013
|
/** The result of {@link ../rxnorm/navigate.resolveNdc}: a resolution or a typed absence. */
|
|
3014
3014
|
type NdcResult = NdcResolution | NdcUnmapped;
|
|
3015
3015
|
/**
|
|
3016
|
-
* A successful graph-navigation result
|
|
3016
|
+
* A successful graph-navigation result: the concept, the predicate followed, and the **full** set of
|
|
3017
3017
|
* related concepts drawn verbatim from the loaded edges. `targets` may be **empty**: that is an
|
|
3018
3018
|
* honest, data-grounded "the release has no such edge for this concept", never a fabricated relation.
|
|
3019
3019
|
*/
|
|
@@ -3028,7 +3028,7 @@ interface RxNormRelated {
|
|
|
3028
3028
|
readonly targets: readonly RxNormConcept[];
|
|
3029
3029
|
}
|
|
3030
3030
|
/**
|
|
3031
|
-
* A typed **unknown** navigation result
|
|
3031
|
+
* A typed **unknown** navigation result: the queried `RXCUI` is **absent from the loaded graph**. A
|
|
3032
3032
|
* first-class outcome, never a fabricated concept or an empty success (the never-fabricate
|
|
3033
3033
|
* invariant, applied to the drug graph). Distinct from a {@link RxNormRelated} with empty
|
|
3034
3034
|
* `targets`, which means "present, but no such relationship".
|
|
@@ -3050,7 +3050,7 @@ type RxNormNavResult = RxNormRelated | RxNormUnknown;
|
|
|
3050
3050
|
* loaded release.
|
|
3051
3051
|
*/
|
|
3052
3052
|
interface RxNormApproximateMatch {
|
|
3053
|
-
/** Always `true
|
|
3053
|
+
/** Always `true`: this is a similarity match, never an exact code resolution. */
|
|
3054
3054
|
readonly approximate: true;
|
|
3055
3055
|
/** The matched concept, verbatim from the loaded release. */
|
|
3056
3056
|
readonly concept: RxNormConcept;
|
|
@@ -3082,15 +3082,15 @@ interface RxNormLoadWarning {
|
|
|
3082
3082
|
*
|
|
3083
3083
|
* Its three indexes are **read-only views**, not `Map`s you were handed: reads and iteration behave
|
|
3084
3084
|
* as a `Map`'s do, and adding / deleting / clearing is refused however it is attempted. What that
|
|
3085
|
-
* buys is the never-fabricate invariant surviving the handover
|
|
3085
|
+
* buys is the never-fabricate invariant surviving the handover: nothing that holds a loaded graph
|
|
3086
3086
|
* can empty a medication's ingredient edges, or add an edge or concept the release never authored,
|
|
3087
3087
|
* and leave {@link conceptCount} / {@link edgeCount} still reporting the loaded figures.
|
|
3088
3088
|
*
|
|
3089
|
-
* A view is not a `Map` instance
|
|
3089
|
+
* A view is not a `Map` instance: `instanceof Map` is `false` and this model cannot be
|
|
3090
3090
|
* `structuredClone`d or posted to a worker; copy out what you need (`new Map(…)`).
|
|
3091
3091
|
*/
|
|
3092
3092
|
interface RxNormGraph {
|
|
3093
|
-
/** The release version (e.g. `"RXNORM_2026AA"`), when supplied
|
|
3093
|
+
/** The release version (e.g. `"RXNORM_2026AA"`), when supplied: mappings are release-scoped. */
|
|
3094
3094
|
readonly version?: string;
|
|
3095
3095
|
/** Concepts keyed by `RXCUI` (first `SAB=RXNORM` atom per `RXCUI` wins). Each frozen. */
|
|
3096
3096
|
readonly concepts: ReadonlyMap<string, RxNormConcept>;
|
|
@@ -3110,10 +3110,10 @@ interface RxNormGraph {
|
|
|
3110
3110
|
}
|
|
3111
3111
|
|
|
3112
3112
|
/**
|
|
3113
|
-
* The **RxNorm drug graph loader
|
|
3113
|
+
* The **RxNorm drug graph loader**: build an immutable {@link RxNormGraph} from a
|
|
3114
3114
|
* **caller-supplied** RxNorm RRF release (`RXNCONSO.RRF` + `RXNREL.RRF`, and optionally `RXNSAT.RRF`
|
|
3115
3115
|
* for NDC attributes). Reuses the shared, zero-dep {@link ../codesystem/rrf.parseRrfLine} (pipe split,
|
|
3116
|
-
* reserved trailing pipe)
|
|
3116
|
+
* reserved trailing pipe): the same RRF reader the CodeSystem layer uses.
|
|
3117
3117
|
*
|
|
3118
3118
|
* **Column layouts, grounded firsthand** on the NLM RxNorm Technical Documentation (§ file
|
|
3119
3119
|
* descriptions):
|
|
@@ -3124,7 +3124,7 @@ interface RxNormGraph {
|
|
|
3124
3124
|
* - `RXNREL.RRF` (16 cols): `RXCUI1`(0) `RXAUI1`(1) `STYPE1`(2) `REL`(3) `RXCUI2`(4) `RXAUI2`(5)
|
|
3125
3125
|
* `STYPE2`(6) `RELA`(7) `RUI`(8) `SRUI`(9) `SAB`(10) `SL`(11) `RG`(12) `DIR`(13) `SUPPRESS`(14)
|
|
3126
3126
|
* `CVF`(15). Read `subject = RXCUI2`, `predicate = RELA`, `object = RXCUI1` (the direction
|
|
3127
|
-
* convention
|
|
3127
|
+
* convention: see {@link ../rxnorm/rela}). Only concept-level rows (both `RXCUI`s present) with a
|
|
3128
3128
|
* non-empty `RELA` become edges; atom-level (`RXAUI`) rows are not part of the concept graph.
|
|
3129
3129
|
* - `RXNSAT.RRF` (13 cols): `RXCUI`(0) … `ATN`(8) `SAB`(9) `ATV`(10) `SUPPRESS`(11) `CVF`(12). Rows
|
|
3130
3130
|
* with `ATN=NDC` index `ATV`(the NDC) → `RXCUI`, marked `active` **as of** the loaded release.
|
|
@@ -3144,7 +3144,7 @@ interface RxNormGraph {
|
|
|
3144
3144
|
* **Liberal on load**: a structurally unusable *row* (too few columns, missing a required
|
|
3145
3145
|
* value) is **skipped and surfaced** as a `TERM_RXNORM_MALFORMED_ROW` warning, never a partial
|
|
3146
3146
|
* concept/edge, never a crash. Rows that are simply *not of interest* (a non-`RXNORM` atom, an
|
|
3147
|
-
* atom-level relationship, a non-`NDC` attribute) are skipped **silently
|
|
3147
|
+
* atom-level relationship, a non-`NDC` attribute) are skipped **silently**: they are expected, not
|
|
3148
3148
|
* faults. Ships **no** RxNorm release: every concept/edge is the caller's.
|
|
3149
3149
|
*
|
|
3150
3150
|
* @packageDocumentation
|
|
@@ -3159,17 +3159,17 @@ interface RxNormGraphSource {
|
|
|
3159
3159
|
readonly conso: string;
|
|
3160
3160
|
/** The raw `RXNREL.RRF` content (pipe-delimited relationships). */
|
|
3161
3161
|
readonly rel: string;
|
|
3162
|
-
/** The raw `RXNSAT.RRF` content (pipe-delimited attributes)
|
|
3162
|
+
/** The raw `RXNSAT.RRF` content (pipe-delimited attributes): supply to resolve NDCs. Optional. */
|
|
3163
3163
|
readonly sat?: string;
|
|
3164
|
-
/** The release version (e.g. `"RXNORM_2026AA"`), when known
|
|
3164
|
+
/** The release version (e.g. `"RXNORM_2026AA"`), when known: mappings are release-scoped. */
|
|
3165
3165
|
readonly version?: string;
|
|
3166
3166
|
}
|
|
3167
3167
|
/**
|
|
3168
3168
|
* Load a **caller-supplied** RxNorm RRF release into an immutable {@link RxNormGraph}.
|
|
3169
3169
|
*
|
|
3170
3170
|
* Parses `RXNCONSO` (concepts), `RXNREL` (directed edges, normalized to the documented direction), and
|
|
3171
|
-
*
|
|
3172
|
-
* skipped, surfaced {@link RxNormLoadWarning}, never partial. Ships **no** RxNorm release
|
|
3171
|
+
* (when supplied) `RXNSAT` (NDC attributes). Liberal on load: a structurally unusable row is a
|
|
3172
|
+
* skipped, surfaced {@link RxNormLoadWarning}, never partial. Ships **no** RxNorm release: the graph
|
|
3173
3173
|
* is entirely the caller's release.
|
|
3174
3174
|
*
|
|
3175
3175
|
* A concept is typed only by a **defining** atom, never by a synonym-class one and never by file
|
|
@@ -3199,7 +3199,7 @@ declare function loadRxNormGraph(source: RxNormGraphSource): RxNormGraph;
|
|
|
3199
3199
|
* a loaded {@link RxNormGraph}. Every query is **fail-safe and never-fabricate**:
|
|
3200
3200
|
*
|
|
3201
3201
|
* - a queried `RXCUI` absent from the graph is a typed {@link RxNormUnknown}, never a guessed concept;
|
|
3202
|
-
* - a present concept with no such relationship is a {@link RxNormRelated} with **empty** `targets
|
|
3202
|
+
* - a present concept with no such relationship is a {@link RxNormRelated} with **empty** `targets`:
|
|
3203
3203
|
* an honest, data-grounded "no such edge", distinct from "unknown concept";
|
|
3204
3204
|
* - navigation follows only **authored** edges by their predicate; the engine **never synthesizes an
|
|
3205
3205
|
* inverse** (RxNorm ships both directions as separate rows, so brand→generic follows the authored
|
|
@@ -3250,7 +3250,7 @@ declare function getConcept(graph: RxNormGraph, rxcui: string): RxNormConcept |
|
|
|
3250
3250
|
*/
|
|
3251
3251
|
declare function relatedByRela(graph: RxNormGraph, rxcui: string, predicate: string | readonly string[]): RxNormNavResult;
|
|
3252
3252
|
/**
|
|
3253
|
-
* The **ingredients** of a concept
|
|
3253
|
+
* The **ingredients** of a concept: the concepts it links to by a **direct** `has_ingredient` /
|
|
3254
3254
|
* `has_precise_ingredient` edge in the loaded release.
|
|
3255
3255
|
*
|
|
3256
3256
|
* This follows the *authored, direct* edge only (never-fabricate, never a synthesized path), and
|
|
@@ -3300,7 +3300,7 @@ declare function relatedByRela(graph: RxNormGraph, rxcui: string, predicate: str
|
|
|
3300
3300
|
*/
|
|
3301
3301
|
declare function ingredientsOf(graph: RxNormGraph, rxcui: string): RxNormNavResult;
|
|
3302
3302
|
/**
|
|
3303
|
-
* The **generic** form(s) of a branded concept
|
|
3303
|
+
* The **generic** form(s) of a branded concept: an `SBD`/`BN`/`BPCK` `tradename_of` its generic. The
|
|
3304
3304
|
* authored forward edge; the engine never inverts a `has_tradename` edge to synthesize this.
|
|
3305
3305
|
*
|
|
3306
3306
|
* @param graph - A loaded {@link RxNormGraph}.
|
|
@@ -3320,7 +3320,7 @@ declare function ingredientsOf(graph: RxNormGraph, rxcui: string): RxNormNavResu
|
|
|
3320
3320
|
*/
|
|
3321
3321
|
declare function genericFor(graph: RxNormGraph, rxcui: string): RxNormNavResult;
|
|
3322
3322
|
/**
|
|
3323
|
-
* The **branded** form(s) of a generic concept
|
|
3323
|
+
* The **branded** form(s) of a generic concept: an `SCD`/`IN`/`GPCK` that `has_tradename` a brand.
|
|
3324
3324
|
* The authored forward edge; not a synthesized inverse of `tradename_of`.
|
|
3325
3325
|
*
|
|
3326
3326
|
* @param graph - A loaded {@link RxNormGraph}.
|
|
@@ -3339,7 +3339,7 @@ declare function genericFor(graph: RxNormGraph, rxcui: string): RxNormNavResult;
|
|
|
3339
3339
|
*/
|
|
3340
3340
|
declare function brandsFor(graph: RxNormGraph, rxcui: string): RxNormNavResult;
|
|
3341
3341
|
/**
|
|
3342
|
-
* The **dose form(s)** of a drug
|
|
3342
|
+
* The **dose form(s)** of a drug: the `DF`/`DFG` concepts it `has_dose_form` / `has_doseformgroup`.
|
|
3343
3343
|
*
|
|
3344
3344
|
* @param graph - A loaded {@link RxNormGraph}.
|
|
3345
3345
|
* @param rxcui - The drug concept.
|
|
@@ -3357,7 +3357,7 @@ declare function brandsFor(graph: RxNormGraph, rxcui: string): RxNormNavResult;
|
|
|
3357
3357
|
*/
|
|
3358
3358
|
declare function doseFormsOf(graph: RxNormGraph, rxcui: string): RxNormNavResult;
|
|
3359
3359
|
/**
|
|
3360
|
-
* The **components** a drug `consists_of
|
|
3360
|
+
* The **components** a drug `consists_of`: an `SCD`/`SBD` → its `SCDC`/`SBDC` dose-form components.
|
|
3361
3361
|
*
|
|
3362
3362
|
* @param graph - A loaded {@link RxNormGraph}.
|
|
3363
3363
|
* @param rxcui - The drug concept.
|
|
@@ -3382,7 +3382,7 @@ declare function consistsOf(graph: RxNormGraph, rxcui: string): RxNormNavResult;
|
|
|
3382
3382
|
*
|
|
3383
3383
|
* @param graph - A loaded {@link RxNormGraph} (load with `sat` supplied to populate NDC attributes).
|
|
3384
3384
|
* @param ndc - The NDC (as it appears in the release, e.g. 11-digit).
|
|
3385
|
-
* @returns An {@link NdcResult}
|
|
3385
|
+
* @returns An {@link NdcResult}: a resolution with status + `asOf`, or a typed absence.
|
|
3386
3386
|
* @example
|
|
3387
3387
|
* ```ts
|
|
3388
3388
|
* import { loadRxNormGraph, resolveNdc } from "@cosyte/terminology";
|
|
@@ -3406,7 +3406,7 @@ interface ApproximateMatchOptions {
|
|
|
3406
3406
|
readonly limit?: number;
|
|
3407
3407
|
}
|
|
3408
3408
|
/**
|
|
3409
|
-
* **Opt-in, explicitly labeled** approximate name matching
|
|
3409
|
+
* **Opt-in, explicitly labeled** approximate name matching: find loaded concepts whose
|
|
3410
3410
|
* names are token-similar to `query`. This is **never** the default resolution path and its results
|
|
3411
3411
|
* are **never** an exact code assertion: every candidate is marked `approximate: true` with a derived
|
|
3412
3412
|
* {@link RxNormApproximateMatch.score}. A caller opts in by calling this function explicitly.
|
|
@@ -3434,16 +3434,16 @@ declare function approximateMatch(graph: RxNormGraph, query: string, options?: A
|
|
|
3434
3434
|
|
|
3435
3435
|
/**
|
|
3436
3436
|
* The RxNorm **relationship (`RELA`) vocabulary** and the **direction convention** the drug graph is
|
|
3437
|
-
* built on
|
|
3437
|
+
* built on: encoded here as published identity facts (like the code-system OID↔URI facts in
|
|
3438
3438
|
* {@link ../systems/registry}), grounded firsthand on the NLM RxNorm Technical Documentation and the
|
|
3439
|
-
* UMLS Reference Manual. **No RxNorm release is bundled
|
|
3439
|
+
* UMLS Reference Manual. **No RxNorm release is bundled**: what ships is the relationship *names*
|
|
3440
3440
|
* and the *rule* for reading a row's direction.
|
|
3441
3441
|
*
|
|
3442
3442
|
* **The direction rule (a documented medication-safety trap).** From the
|
|
3443
3443
|
* RxNorm Technical Documentation (§12.7) and the UMLS Reference Manual, verbatim: *"the direction of
|
|
3444
|
-
* REL
|
|
3445
|
-
* or atom (with … RXCUI1 …)."* The doc's worked example
|
|
3446
|
-
* `RXCUI2=197589`
|
|
3444
|
+
* REL: the relationship which the SECOND concept or atom (with … RXCUI2 …) HAS TO the FIRST concept
|
|
3445
|
+
* or atom (with … RXCUI1 …)."* The doc's worked example (a row with `RXCUI1=1155862`, `RELA=isa`,
|
|
3446
|
+
* `RXCUI2=197589`) reads *"197589 **isa** 1155862"* (the second concept is-a the first).
|
|
3447
3447
|
*
|
|
3448
3448
|
* So an `RXNREL.RRF` row is read **`RXCUI2 ⟶RELA⟶ RXCUI1`**, and {@link ../rxnorm/load.loadRxNormGraph}
|
|
3449
3449
|
* normalizes every row to `subject = RXCUI2`, `predicate = RELA`, `object = RXCUI1`. Concretely, a
|
|
@@ -3469,7 +3469,7 @@ declare function approximateMatch(graph: RxNormGraph, query: string, options?: A
|
|
|
3469
3469
|
* The drug-graph `RELA` relationship names, grounded on the NLM RxNorm Technical Documentation
|
|
3470
3470
|
* (Appendix 1). Each is directional and read `subject ⟶RELA⟶ object` after normalization (see the
|
|
3471
3471
|
* module doc). RxNorm ships both members of an inverse pair as **separate rows**, so the graph
|
|
3472
|
-
* traverses the authored predicate for the direction it wants
|
|
3472
|
+
* traverses the authored predicate for the direction it wants: it **never synthesizes an inverse**.
|
|
3473
3473
|
*
|
|
3474
3474
|
* @example
|
|
3475
3475
|
* ```ts
|
|
@@ -3491,43 +3491,43 @@ declare const RELA: {
|
|
|
3491
3491
|
* Neither reaches an `SCD`.
|
|
3492
3492
|
*/
|
|
3493
3493
|
readonly INGREDIENT_OF: "ingredient_of";
|
|
3494
|
-
/** `has_precise_ingredient
|
|
3494
|
+
/** `has_precise_ingredient`: subject *has precise ingredient* object (a `PIN`). */
|
|
3495
3495
|
readonly HAS_PRECISE_INGREDIENT: "has_precise_ingredient";
|
|
3496
|
-
/** `precise_ingredient_of
|
|
3496
|
+
/** `precise_ingredient_of`: inverse of `has_precise_ingredient`. */
|
|
3497
3497
|
readonly PRECISE_INGREDIENT_OF: "precise_ingredient_of";
|
|
3498
|
-
/** `tradename_of
|
|
3498
|
+
/** `tradename_of`: subject (a branded concept) *is a tradename of* object (its generic). */
|
|
3499
3499
|
readonly TRADENAME_OF: "tradename_of";
|
|
3500
|
-
/** `has_tradename
|
|
3500
|
+
/** `has_tradename`: subject (a generic concept) *has tradename* object (a branded concept). */
|
|
3501
3501
|
readonly HAS_TRADENAME: "has_tradename";
|
|
3502
|
-
/** `has_dose_form
|
|
3502
|
+
/** `has_dose_form`: subject (a drug) *has dose form* object (a `DF`). */
|
|
3503
3503
|
readonly HAS_DOSE_FORM: "has_dose_form";
|
|
3504
|
-
/** `dose_form_of
|
|
3504
|
+
/** `dose_form_of`: subject (a `DF`) *is the dose form of* object (a drug). */
|
|
3505
3505
|
readonly DOSE_FORM_OF: "dose_form_of";
|
|
3506
|
-
/** `has_doseformgroup
|
|
3506
|
+
/** `has_doseformgroup`: subject *has dose-form group* object (a `DFG`). */
|
|
3507
3507
|
readonly HAS_DOSE_FORM_GROUP: "has_doseformgroup";
|
|
3508
|
-
/** `doseformgroup_of
|
|
3508
|
+
/** `doseformgroup_of`: inverse of `has_doseformgroup`. */
|
|
3509
3509
|
readonly DOSE_FORM_GROUP_OF: "doseformgroup_of";
|
|
3510
|
-
/** `consists_of
|
|
3510
|
+
/** `consists_of`: subject (an `SCD`/`SBD`) *consists of* object (its `SCDC`/`SBDC` component(s)). */
|
|
3511
3511
|
readonly CONSISTS_OF: "consists_of";
|
|
3512
|
-
/** `constitutes
|
|
3512
|
+
/** `constitutes`: subject (a component) *constitutes* object (the drug). Inverse of `consists_of`. */
|
|
3513
3513
|
readonly CONSTITUTES: "constitutes";
|
|
3514
|
-
/** `contains
|
|
3514
|
+
/** `contains`: subject (a pack) *contains* object (a member drug). */
|
|
3515
3515
|
readonly CONTAINS: "contains";
|
|
3516
|
-
/** `contained_in
|
|
3516
|
+
/** `contained_in`: subject (a drug) *is contained in* object (a pack). Inverse of `contains`. */
|
|
3517
3517
|
readonly CONTAINED_IN: "contained_in";
|
|
3518
|
-
/** `has_quantified_form
|
|
3518
|
+
/** `has_quantified_form`: subject *has quantified form* object. */
|
|
3519
3519
|
readonly HAS_QUANTIFIED_FORM: "has_quantified_form";
|
|
3520
|
-
/** `quantified_form_of
|
|
3520
|
+
/** `quantified_form_of`: inverse of `has_quantified_form`. */
|
|
3521
3521
|
readonly QUANTIFIED_FORM_OF: "quantified_form_of";
|
|
3522
|
-
/** `isa
|
|
3522
|
+
/** `isa`: subject *is a* object (hierarchical, e.g. `SCD isa SCDG`). */
|
|
3523
3523
|
readonly ISA: "isa";
|
|
3524
|
-
/** `inverse_isa
|
|
3524
|
+
/** `inverse_isa`: subject *is a parent of* object. Inverse of `isa`. */
|
|
3525
3525
|
readonly INVERSE_ISA: "inverse_isa";
|
|
3526
3526
|
};
|
|
3527
|
-
/** A value from {@link RELA}
|
|
3527
|
+
/** A value from {@link RELA}: a drug-graph relationship name. */
|
|
3528
3528
|
type RelaName = (typeof RELA)[keyof typeof RELA];
|
|
3529
3529
|
/**
|
|
3530
|
-
* The authored **inverse pairs** of the drug-graph `RELA`s
|
|
3530
|
+
* The authored **inverse pairs** of the drug-graph `RELA`s: a published fact (RxNorm Appendix 1),
|
|
3531
3531
|
* used only to *document* and *validate* that a caller is traversing a real relationship. The graph
|
|
3532
3532
|
* **never** uses this to synthesize a missing edge: RxNorm ships both directions, so
|
|
3533
3533
|
* {@link ../rxnorm/navigate} follows whichever authored predicate points the way it wants to go.
|
|
@@ -3540,12 +3540,12 @@ type RelaName = (typeof RELA)[keyof typeof RELA];
|
|
|
3540
3540
|
* ```
|
|
3541
3541
|
*/
|
|
3542
3542
|
declare const RELA_INVERSE: Readonly<Record<string, string>>;
|
|
3543
|
-
/** The canonical code-system URI for **RxNorm
|
|
3543
|
+
/** The canonical code-system URI for **RxNorm**: a published identity fact, attached to graph codings. */
|
|
3544
3544
|
declare const RXNORM_SYSTEM = "http://www.nlm.nih.gov/research/umls/rxnorm";
|
|
3545
3545
|
|
|
3546
3546
|
/**
|
|
3547
|
-
* The RxNorm **term-type (`TTY`) vocabulary** relevant to the drug graph
|
|
3548
|
-
* the cross-link kinds
|
|
3547
|
+
* The RxNorm **term-type (`TTY`) vocabulary** relevant to the drug graph (the normal-form ladder and
|
|
3548
|
+
* the cross-link kinds), encoded as published identity facts (grounded firsthand on the NLM RxNorm
|
|
3549
3549
|
* Technical Documentation, Appendix 5). **No RxNorm release is bundled**: what ships is these
|
|
3550
3550
|
* *labels*, not the drug list.
|
|
3551
3551
|
*
|
|
@@ -3620,7 +3620,7 @@ declare function asTermType(tty: string): TermType | undefined;
|
|
|
3620
3620
|
declare function isSynonymTermType(tty: TermType): boolean;
|
|
3621
3621
|
|
|
3622
3622
|
/**
|
|
3623
|
-
* Public entry point for **`@cosyte/terminology
|
|
3623
|
+
* Public entry point for **`@cosyte/terminology`**: a zero-dependency, developer-focused
|
|
3624
3624
|
* **terminology engine** for US healthcare code systems.
|
|
3625
3625
|
*
|
|
3626
3626
|
* Unlike its sibling `@cosyte/*` packages, this is **not a wire-format parser**: it mirrors the
|
|
@@ -3633,78 +3633,78 @@ declare function isSynonymTermType(tty: TermType): boolean;
|
|
|
3633
3633
|
*
|
|
3634
3634
|
* **Code-system identity and ConceptMap translation:**
|
|
3635
3635
|
*
|
|
3636
|
-
* - {@link resolveSystem}
|
|
3637
|
-
* - {@link loadConceptMap} + {@link translate}
|
|
3636
|
+
* - {@link resolveSystem}: the code-system identity / canonical-URI resolver (mnemonic | OID → URI).
|
|
3637
|
+
* - {@link loadConceptMap} + {@link translate}: the ConceptMap `$translate` engine, with the
|
|
3638
3638
|
* **never-fabricate / never-invert** invariants: an unmapped source is a typed
|
|
3639
3639
|
* {@link TranslateUnmapped}, never a guessed target; a directional map is never run backwards.
|
|
3640
3640
|
*
|
|
3641
3641
|
* **The CodeSystem load layer**, with the FHIR `$lookup` / `$validate-code` operations:
|
|
3642
3642
|
*
|
|
3643
|
-
* - {@link loadCodeSystem}
|
|
3643
|
+
* - {@link loadCodeSystem}: load a **consumer-supplied** release (RRF / CSV / fixed-width / FHIR
|
|
3644
3644
|
* `CodeSystem` JSON) into an immutable model. Ships the loader; **no code-system release**.
|
|
3645
|
-
* - {@link lookup}
|
|
3646
|
-
* - {@link validateCode}
|
|
3645
|
+
* - {@link lookup}: code → display + properties, carrying status (deprecated / header-not-billable).
|
|
3646
|
+
* - {@link validateCode}: is a code a valid member of the system, with its status flags.
|
|
3647
3647
|
*
|
|
3648
3648
|
* The never-fabricate invariant holds here too: an unknown code is a typed `unknown` / `valid: false`,
|
|
3649
3649
|
* never a fabricated display or a guessed `valid: true`.
|
|
3650
3650
|
*
|
|
3651
|
-
* **The ValueSet binding layer
|
|
3651
|
+
* **The ValueSet binding layer**, FHIR `$expand` / `$validate-code` over a `compose`:
|
|
3652
3652
|
*
|
|
3653
|
-
* - {@link loadValueSet}
|
|
3653
|
+
* - {@link loadValueSet}: load a **consumer-supplied** FHIR `ValueSet` (intensional `compose` and/or
|
|
3654
3654
|
* a pre-computed `expansion`) into an immutable model.
|
|
3655
|
-
* - {@link expand}
|
|
3655
|
+
* - {@link expand}: flatten membership over the supplied {@link CodeSystem}s (`include`/`exclude`,
|
|
3656
3656
|
* explicit `concept` lists, `is-a`/property `filter`s, referenced value sets), with an honest
|
|
3657
3657
|
* `complete` flag: an unresolvable part is a typed `TERM_VALUESET_CANNOT_EXPAND`, never a guess.
|
|
3658
|
-
* - {@link validateCodeInValueSet}
|
|
3658
|
+
* - {@link validateCodeInValueSet}: binding membership, returning a **decided** `result` only when
|
|
3659
3659
|
* proven and a typed `undetermined` otherwise (a truncated expansion never reads as complete).
|
|
3660
3660
|
*
|
|
3661
|
-
* **The UCUM unit layer
|
|
3661
|
+
* **The UCUM unit layer**: a hand-rolled UCUM grammar parser + validation + representation
|
|
3662
3662
|
* canonicalization (recognition only, **no** magnitude conversion):
|
|
3663
3663
|
*
|
|
3664
|
-
* - {@link validateUcum}
|
|
3664
|
+
* - {@link validateUcum}: is a string a valid UCUM unit; if so, its canonical descriptor. An
|
|
3665
3665
|
* invalid unit is a typed `TERM_UCUM_INVALID`, never a guessed "nearest" unit.
|
|
3666
|
-
* - {@link ucumEqual}
|
|
3666
|
+
* - {@link ucumEqual}: do two expressions denote the *same unit* (`N` ≡ `kg.m/s2`), by reducing
|
|
3667
3667
|
* both to base dimensions. Not magnitude conversion (`mg/dL` → `mmol/L` is refused).
|
|
3668
|
-
* - {@link parseUcum} / {@link reduce} / {@link loadUcumEssence}
|
|
3668
|
+
* - {@link parseUcum} / {@link reduce} / {@link loadUcumEssence}: the underlying grammar parser,
|
|
3669
3669
|
* dimensional reducer, and the in-memory model of the vendored, verbatim UCUM table.
|
|
3670
3670
|
*
|
|
3671
|
-
* **The crosswalk resolvers
|
|
3671
|
+
* **The crosswalk resolvers**: the never-fabricate/never-invert invariant applied to the
|
|
3672
3672
|
* published, directional reference maps:
|
|
3673
3673
|
*
|
|
3674
|
-
* - {@link loadGems} + {@link applyGem}
|
|
3674
|
+
* - {@link loadGems} + {@link applyGem}: the CMS **ICD-9↔ICD-10 GEMs** (public-domain reference
|
|
3675
3675
|
* mappings), honoring the steward's Approximate / No-Map / Combination (scenario→choice-list) flags.
|
|
3676
3676
|
* A No-Map source is a typed {@link CrosswalkNoMap}; a 1:many source returns the full candidate set.
|
|
3677
|
-
* - {@link loadComplexMap} + {@link applyComplexMap}
|
|
3678
|
-
* (BYO
|
|
3677
|
+
* - {@link loadComplexMap} + {@link applyComplexMap}: the NLM **SNOMED CT → ICD-10-CM complex map**
|
|
3678
|
+
* (BYO, **no SNOMED CT refset bundled**), evaluating Map Group / Priority / `IFA` Rule /
|
|
3679
3679
|
* Advice / Category against caller-supplied {@link PatientContext}; a rule needing context the
|
|
3680
3680
|
* caller lacks is a typed {@link ComplexMapContextRequired}, never a guessed branch.
|
|
3681
|
-
* - {@link invertGem}
|
|
3681
|
+
* - {@link invertGem}: the never-invert refusal made a first-class, thrown contract
|
|
3682
3682
|
* ({@link FATAL_CODES.TERM_MAP_NOT_INVERTIBLE}).
|
|
3683
3683
|
*
|
|
3684
|
-
* **The RxNorm drug relationship graph
|
|
3684
|
+
* **The RxNorm drug relationship graph**: ingredient / brand / clinical-drug / dose-form
|
|
3685
3685
|
* navigation over a **caller-supplied** RxNorm RRF release:
|
|
3686
3686
|
*
|
|
3687
|
-
* - {@link loadRxNormGraph}
|
|
3687
|
+
* - {@link loadRxNormGraph}: load `RXNCONSO` (concepts, typed by `TTY`), `RXNREL` (directed `RELA`
|
|
3688
3688
|
* edges, normalized to the documented `RXCUI2 ⟶RELA⟶ RXCUI1` direction), and optionally `RXNSAT`
|
|
3689
|
-
* (NDC attributes) into an immutable graph. Ships **no** RxNorm release
|
|
3689
|
+
* (NDC attributes) into an immutable graph. Ships **no** RxNorm release: BYO.
|
|
3690
3690
|
* - {@link ingredientsOf} / {@link genericFor} / {@link brandsFor} / {@link doseFormsOf} /
|
|
3691
|
-
* {@link consistsOf} / {@link relatedByRela}
|
|
3691
|
+
* {@link consistsOf} / {@link relatedByRela}: graph navigation following **authored** edges only
|
|
3692
3692
|
* (the engine never synthesizes an inverse). An absent `RXCUI` is a typed {@link RxNormUnknown}.
|
|
3693
|
-
* - {@link resolveNdc}
|
|
3693
|
+
* - {@link resolveNdc}: NDC → `RXCUI` carrying the temporal status and the as-of release; an absent
|
|
3694
3694
|
* NDC is a typed {@link NdcUnmapped}, never a guess.
|
|
3695
|
-
* - {@link approximateMatch}
|
|
3695
|
+
* - {@link approximateMatch}: the **opt-in, explicitly labeled** similarity path (never the default,
|
|
3696
3696
|
* never an exact code assertion).
|
|
3697
3697
|
*
|
|
3698
3698
|
* **What is bundled.** No code-system release is. What is bundled includes the following, named with
|
|
3699
3699
|
* its copyright:
|
|
3700
3700
|
*
|
|
3701
|
-
* - the **UCUM unit table** (`ucum-essence.xml`, version 2.2, revision-date 2024-06-17)
|
|
3701
|
+
* - the **UCUM unit table** (`ucum-essence.xml`, version 2.2, revision-date 2024-06-17): copyright
|
|
3702
3702
|
* ©1999–2024 Regenstrief Institute, Inc., all rights reserved, reproduced **verbatim** under the
|
|
3703
3703
|
* UCUM Copyright Notice and License (https://ucum.org/license), embedded byte-for-byte in the
|
|
3704
3704
|
* published build and parsed at runtime; no modified or derivative copy is distributed. The UCUM
|
|
3705
|
-
* Specification is provided "as is" **without warranty of any kind
|
|
3705
|
+
* Specification is provided "as is" **without warranty of any kind**: see the License for the
|
|
3706
3706
|
* full disclaimer. The complete notice ships with this package at `vendor/ucum/NOTICE.md`.
|
|
3707
|
-
* - the **code-system identity facts** ({@link SYSTEM_IDENTITIES})
|
|
3707
|
+
* - the **code-system identity facts** ({@link SYSTEM_IDENTITIES}): OID ↔ canonical-URI pairings,
|
|
3708
3708
|
* which identify the systems rather than listing any system's codes.
|
|
3709
3709
|
* - the **SNOMED CT concepts the crosswalk resolver names**, each with its description: the four
|
|
3710
3710
|
* map-category concepts ({@link MAP_CATEGORIES}) a complex-map row's `mapCategoryId` refers to, and
|