@cosyte/astm 0.0.22 → 0.1.1
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 +346 -7
- package/README.md +559 -224
- package/dist/index.cjs +309 -64
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1061 -184
- package/dist/index.d.ts +1061 -184
- package/dist/index.mjs +301 -65
- package/dist/index.mjs.map +1 -1
- package/package.json +25 -8
package/dist/index.d.ts
CHANGED
|
@@ -858,7 +858,9 @@ declare function unpairedEscapeCharacter(position: AstmPosition): AstmRecordWarn
|
|
|
858
858
|
declare function ambiguousValueSplit(position: AstmPosition): AstmRecordWarning;
|
|
859
859
|
/**
|
|
860
860
|
* Build an `ASTM_RECORD_UNDEFINED_ABNORMAL_FLAG` warning. The flag is surfaced as
|
|
861
|
-
* `undefined` (never coerced to `normal`); the warning carries only the position
|
|
861
|
+
* `undefined` (never coerced to `normal`); the warning carries only the position
|
|
862
|
+
* and fixed prose naming the **same** vocabulary the interpreted flag reports,
|
|
863
|
+
* read from the one shared constant so the two cannot drift apart.
|
|
862
864
|
*
|
|
863
865
|
* @example
|
|
864
866
|
* ```ts
|
|
@@ -870,6 +872,8 @@ declare function undefinedAbnormalFlag(position: AstmPosition): AstmRecordWarnin
|
|
|
870
872
|
/**
|
|
871
873
|
* Build an `ASTM_RECORD_UNDEFINED_RESULT_STATUS` warning. The status is surfaced
|
|
872
874
|
* as `undefined` and, like every non-final status, never reads as active-final.
|
|
875
|
+
* The message carries the **same** attribution the interpreted status reports
|
|
876
|
+
* (there is no citable source for this letter set), from the one shared constant.
|
|
873
877
|
*
|
|
874
878
|
* @example
|
|
875
879
|
* ```ts
|
|
@@ -1254,22 +1258,30 @@ declare function astmDateToLocalISO(d: AstmDate): string;
|
|
|
1254
1258
|
* spec's component order is LOINC-slot / test-name / coding-scheme / local-code.
|
|
1255
1259
|
* In the field the way real analyzers emit it:
|
|
1256
1260
|
*
|
|
1257
|
-
* - **component 1** is a LOINC slot: *almost always empty
|
|
1258
|
-
*
|
|
1261
|
+
* - **component 1** is a LOINC slot: *almost always empty*, and the governing
|
|
1262
|
+
* mapping guide puts LOINC on the instrument wire explicitly out of scope, so
|
|
1263
|
+
* whatever arrives there is a wire value this library **does not vouch for**
|
|
1264
|
+
* and never treats as an identifier;
|
|
1259
1265
|
* - **component 4** is the vendor/local code: the identifier that is actually
|
|
1260
|
-
* present, and therefore the **
|
|
1266
|
+
* present, and therefore the **only** identifier a result is keyed on here.
|
|
1261
1267
|
*
|
|
1262
1268
|
* Following the sibling parsers' conservative posture, this module is a
|
|
1263
1269
|
* **structural recognizer, not a dictionary**: it tags where a code came from
|
|
1264
1270
|
* (its provenance) and surfaces every code verbatim. It does not look codes up,
|
|
1265
|
-
* does not validate them, and bundles no LOINC/SNOMED tables.
|
|
1271
|
+
* does not validate them, and bundles no LOINC/SNOMED tables. In particular it
|
|
1272
|
+
* performs **no LOINC validation of any kind** and never decides what a
|
|
1273
|
+
* first-component value "looks like": `2345-7` and `Glucose` in component 1 are
|
|
1274
|
+
* treated identically, and the routing is positional throughout.
|
|
1266
1275
|
*/
|
|
1267
1276
|
/** Where a Universal Test ID's usable identifier came from. */
|
|
1268
1277
|
type UniversalTestIdProvenance =
|
|
1269
|
-
/** Component 1 (the LOINC slot) is populated: a candidate LOINC, recognized not validated. */
|
|
1270
|
-
"inline-loinc-candidate"
|
|
1271
1278
|
/** Component 4 (the vendor/local code) carries the identifier. */
|
|
1272
|
-
|
|
1279
|
+
"local-code"
|
|
1280
|
+
/**
|
|
1281
|
+
* Component 1 is populated and there is no vendor/local code, so there is **no**
|
|
1282
|
+
* identifier: the value is surfaced unvalidated and is never keyed on.
|
|
1283
|
+
*/
|
|
1284
|
+
| "unvalidated-wire-value-only"
|
|
1273
1285
|
/** Only the test name (component 2) is present: no code. */
|
|
1274
1286
|
| "name-only"
|
|
1275
1287
|
/** Nothing usable in the field. */
|
|
@@ -1289,13 +1301,17 @@ type UniversalTestIdProvenance =
|
|
|
1289
1301
|
interface UniversalTestId {
|
|
1290
1302
|
/** The field's components, verbatim and in order. */
|
|
1291
1303
|
readonly components: readonly string[];
|
|
1292
|
-
/**
|
|
1293
|
-
|
|
1304
|
+
/**
|
|
1305
|
+
* Component 1 when populated, verbatim: a wire value this library **does not
|
|
1306
|
+
* vouch for**. It is not validated, is not reported as a LOINC or a LOINC
|
|
1307
|
+
* candidate, and is never the code a result is keyed on.
|
|
1308
|
+
*/
|
|
1309
|
+
readonly unvalidatedWireValue?: string;
|
|
1294
1310
|
/** Component 2: the test / battery name, when present. */
|
|
1295
1311
|
readonly testName?: string;
|
|
1296
1312
|
/** Component 3: the coding-scheme selector, when present. */
|
|
1297
1313
|
readonly codingScheme?: string;
|
|
1298
|
-
/** Component 4, the vendor/local code: the
|
|
1314
|
+
/** Component 4, the vendor/local code: the only identifier a result is keyed on. */
|
|
1299
1315
|
readonly localCode?: string;
|
|
1300
1316
|
/** Where the primary identifier came from. */
|
|
1301
1317
|
readonly provenance: UniversalTestIdProvenance;
|
|
@@ -1303,6 +1319,9 @@ interface UniversalTestId {
|
|
|
1303
1319
|
/**
|
|
1304
1320
|
* Recognize a Universal Test ID from a field's already-decoded components.
|
|
1305
1321
|
*
|
|
1322
|
+
* The provenance is decided **positionally**, by which components are populated,
|
|
1323
|
+
* and never by what a value looks like.
|
|
1324
|
+
*
|
|
1306
1325
|
* @param components - The component strings (escape-decoded), in order.
|
|
1307
1326
|
* @returns The recognized, provenance-tagged Universal Test ID.
|
|
1308
1327
|
* @example
|
|
@@ -1313,16 +1332,18 @@ interface UniversalTestId {
|
|
|
1313
1332
|
*/
|
|
1314
1333
|
declare function recognizeUniversalTestId(components: readonly string[]): UniversalTestId;
|
|
1315
1334
|
/**
|
|
1316
|
-
* The primary code to key a result on: the
|
|
1317
|
-
*
|
|
1318
|
-
*
|
|
1335
|
+
* The primary code to key a result on: the local (vendor) code, and nothing else.
|
|
1336
|
+
* Returns `undefined` when the field carries no vendor/local code, **including**
|
|
1337
|
+
* when component 1 is populated: never a guess, and never a value this library
|
|
1338
|
+
* does not vouch for. Read `unvalidatedWireValue` for that value.
|
|
1319
1339
|
*
|
|
1320
1340
|
* @param u - A recognized Universal Test ID.
|
|
1321
|
-
* @returns The
|
|
1341
|
+
* @returns The vendor/local code, or `undefined`.
|
|
1322
1342
|
* @example
|
|
1323
1343
|
* ```ts
|
|
1324
1344
|
* import { primaryCode, recognizeUniversalTestId } from "@cosyte/astm";
|
|
1325
|
-
* primaryCode(recognizeUniversalTestId(["2345-7", "Glucose", "LN", "687"])); // "
|
|
1345
|
+
* primaryCode(recognizeUniversalTestId(["2345-7", "Glucose", "LN", "687"])); // "687"
|
|
1346
|
+
* primaryCode(recognizeUniversalTestId(["Glucose", "", "", ""])); // undefined
|
|
1326
1347
|
* ```
|
|
1327
1348
|
*/
|
|
1328
1349
|
declare function primaryCode(u: UniversalTestId): string | undefined;
|
|
@@ -1348,7 +1369,7 @@ declare function primaryCode(u: UniversalTestId): string | undefined;
|
|
|
1348
1369
|
*/
|
|
1349
1370
|
interface AstmFramePosition {
|
|
1350
1371
|
/**
|
|
1351
|
-
* The frame's sequence number (`0
|
|
1372
|
+
* The frame's sequence number (`0` to `7`) when it could be read, or `undefined`
|
|
1352
1373
|
* when the frame was so truncated the number was not present.
|
|
1353
1374
|
*/
|
|
1354
1375
|
readonly frameNumber?: number;
|
|
@@ -1837,6 +1858,127 @@ interface DefineAstmProfileOptions {
|
|
|
1837
1858
|
readonly extends?: AstmProfile | readonly AstmProfile[];
|
|
1838
1859
|
}
|
|
1839
1860
|
|
|
1861
|
+
/**
|
|
1862
|
+
* Vocabulary attribution for the code sets this library grades wire letters
|
|
1863
|
+
* against.
|
|
1864
|
+
*
|
|
1865
|
+
* An `R` record carries single letters whose meaning comes from a published
|
|
1866
|
+
* vocabulary, and the ASTM record grammar itself is frozen while those
|
|
1867
|
+
* vocabularies keep moving. Reporting a letter as "unrecognized" without saying
|
|
1868
|
+
* what it was compared against therefore hides a staleness: a consumer cannot
|
|
1869
|
+
* tell a code no published vocabulary defines from a code this library has
|
|
1870
|
+
* simply not caught up to.
|
|
1871
|
+
*
|
|
1872
|
+
* So every interpreted value carries an attribution, and the attribution has
|
|
1873
|
+
* exactly two shapes:
|
|
1874
|
+
*
|
|
1875
|
+
* - {@link NamedVocabulary}: a published code system, named by identifier and
|
|
1876
|
+
* version. **The version says what this library compared against; it is not a
|
|
1877
|
+
* claim about which version the sender meant.**
|
|
1878
|
+
* - {@link UnattributedVocabulary}: no citable published source. This is a
|
|
1879
|
+
* positive statement, deliberately distinguishable from an attribution that is
|
|
1880
|
+
* simply absent, and it never carries a code-system identifier.
|
|
1881
|
+
*
|
|
1882
|
+
* These constants are the single source of truth: the interpreted value and the
|
|
1883
|
+
* warning raised beside it both read them, so the two can never drift apart.
|
|
1884
|
+
*/
|
|
1885
|
+
/**
|
|
1886
|
+
* A published code system this library graded a value against, named by
|
|
1887
|
+
* identifier and version.
|
|
1888
|
+
*
|
|
1889
|
+
* @example
|
|
1890
|
+
* ```ts
|
|
1891
|
+
* import { ABNORMAL_FLAG_VOCABULARY } from "@cosyte/astm";
|
|
1892
|
+
* ABNORMAL_FLAG_VOCABULARY.attributed; // true
|
|
1893
|
+
* ABNORMAL_FLAG_VOCABULARY.version; // the version compared against
|
|
1894
|
+
* ```
|
|
1895
|
+
*/
|
|
1896
|
+
interface NamedVocabulary {
|
|
1897
|
+
/** Always `true`: a published source is cited. */
|
|
1898
|
+
readonly attributed: true;
|
|
1899
|
+
/** The code system's canonical identifier, verbatim from the published source. */
|
|
1900
|
+
readonly system: string;
|
|
1901
|
+
/**
|
|
1902
|
+
* The code system version this library compared against, verbatim from the
|
|
1903
|
+
* published source. **Not** a claim about the version the sender used.
|
|
1904
|
+
*/
|
|
1905
|
+
readonly version: string;
|
|
1906
|
+
}
|
|
1907
|
+
/**
|
|
1908
|
+
* The explicit statement that a code set is bound by **no citable published
|
|
1909
|
+
* source**. It carries no identifier and no version, because inventing either
|
|
1910
|
+
* would be the guess this library exists to refuse.
|
|
1911
|
+
*
|
|
1912
|
+
* @example
|
|
1913
|
+
* ```ts
|
|
1914
|
+
* import { RESULT_STATUS_VOCABULARY } from "@cosyte/astm";
|
|
1915
|
+
* RESULT_STATUS_VOCABULARY.attributed; // false
|
|
1916
|
+
* RESULT_STATUS_VOCABULARY.reason; // fixed prose: why nothing is cited
|
|
1917
|
+
* ```
|
|
1918
|
+
*/
|
|
1919
|
+
interface UnattributedVocabulary {
|
|
1920
|
+
/** Always `false`: no published source can be cited for this code set. */
|
|
1921
|
+
readonly attributed: false;
|
|
1922
|
+
/** Fixed prose saying why nothing is cited. Never a code-system identifier. */
|
|
1923
|
+
readonly reason: string;
|
|
1924
|
+
}
|
|
1925
|
+
/**
|
|
1926
|
+
* What an interpreted wire letter was graded against: either a named published
|
|
1927
|
+
* code system or an explicit "no citable source". Discriminate on
|
|
1928
|
+
* {@link NamedVocabulary.attributed}.
|
|
1929
|
+
*/
|
|
1930
|
+
type VocabularyAttribution = NamedVocabulary | UnattributedVocabulary;
|
|
1931
|
+
/**
|
|
1932
|
+
* The vocabulary the `R` record's abnormal-flag letters (field 7) are graded
|
|
1933
|
+
* against: the HL7 v3 ObservationInterpretation code system, which carries the
|
|
1934
|
+
* concepts kept aligned with the HL7 v2 Table 0078 interpretation codes this
|
|
1935
|
+
* library has always recognized.
|
|
1936
|
+
*
|
|
1937
|
+
* The identifier and version are transcribed character for character from that
|
|
1938
|
+
* code system's published source of truth. **The version records what this
|
|
1939
|
+
* library compared against, not what the sender meant.**
|
|
1940
|
+
*
|
|
1941
|
+
* @example
|
|
1942
|
+
* ```ts
|
|
1943
|
+
* import { ABNORMAL_FLAG_VOCABULARY, interpretAbnormalFlag } from "@cosyte/astm";
|
|
1944
|
+
* interpretAbnormalFlag("HU").vocabulary === ABNORMAL_FLAG_VOCABULARY; // true
|
|
1945
|
+
* ```
|
|
1946
|
+
*/
|
|
1947
|
+
declare const ABNORMAL_FLAG_VOCABULARY: NamedVocabulary;
|
|
1948
|
+
/**
|
|
1949
|
+
* The attribution for the `R` record's result-status letters (field 9): **none**.
|
|
1950
|
+
*
|
|
1951
|
+
* The letters this library models are the ones real analyzers send, but the
|
|
1952
|
+
* normative text that would bind them to a published code set is purchase-gated
|
|
1953
|
+
* and has not been read here. A neighbouring HL7 table exists whose letters
|
|
1954
|
+
* partly agree, and adopting it would be an assertion nothing in the public
|
|
1955
|
+
* record supports. So this library says the set is unattributed rather than
|
|
1956
|
+
* citing a source it cannot stand behind.
|
|
1957
|
+
*
|
|
1958
|
+
* @example
|
|
1959
|
+
* ```ts
|
|
1960
|
+
* import { interpretResultStatus } from "@cosyte/astm";
|
|
1961
|
+
* interpretResultStatus("F").vocabulary.attributed; // false
|
|
1962
|
+
* ```
|
|
1963
|
+
*/
|
|
1964
|
+
declare const RESULT_STATUS_VOCABULARY: UnattributedVocabulary;
|
|
1965
|
+
/**
|
|
1966
|
+
* Render a vocabulary attribution as fixed prose for a warning message.
|
|
1967
|
+
*
|
|
1968
|
+
* The result is a function of the attribution constants alone: it embeds no
|
|
1969
|
+
* field text, no value, and no position, so a warning built with it stays
|
|
1970
|
+
* value-free.
|
|
1971
|
+
*
|
|
1972
|
+
* @param vocabulary - The attribution to describe.
|
|
1973
|
+
* @returns Fixed prose naming the code system and version, or the unattributed reason.
|
|
1974
|
+
* @example
|
|
1975
|
+
* ```ts
|
|
1976
|
+
* import { describeVocabulary, ABNORMAL_FLAG_VOCABULARY } from "@cosyte/astm";
|
|
1977
|
+
* describeVocabulary(ABNORMAL_FLAG_VOCABULARY); // "graded against <system> version <version>"
|
|
1978
|
+
* ```
|
|
1979
|
+
*/
|
|
1980
|
+
declare function describeVocabulary(vocabulary: VocabularyAttribution): string;
|
|
1981
|
+
|
|
1840
1982
|
/**
|
|
1841
1983
|
* Safety-critical result semantics for the ASTM `R` (result) record.
|
|
1842
1984
|
*
|
|
@@ -1844,9 +1986,9 @@ interface DefineAstmProfileOptions {
|
|
|
1844
1986
|
* fields **raw**. This module turns those raw letters into modeled, **fail-safe**
|
|
1845
1987
|
* semantics, under one rule: **never a confident wrong value.**
|
|
1846
1988
|
*
|
|
1847
|
-
* - An **abnormal flag** (field 7) is recognized against
|
|
1848
|
-
* unrecognized flag is surfaced as `undefined` (with a warning)
|
|
1849
|
-
* coerced to `normal`**.
|
|
1989
|
+
* - An **abnormal flag** (field 7) is recognized against a **named** published
|
|
1990
|
+
* vocabulary; an unrecognized flag is surfaced as `undefined` (with a warning)
|
|
1991
|
+
* and is **never coerced to `normal`**.
|
|
1850
1992
|
* - A **result status** (field 9) is modeled so a **correction (`C`)** or a
|
|
1851
1993
|
* **cancellation (`X`)** can never read as an active-final result, and an
|
|
1852
1994
|
* **absent** status is a typed `unspecified`: **never assumed `F` (final)**.
|
|
@@ -1854,54 +1996,91 @@ interface DefineAstmProfileOptions {
|
|
|
1854
1996
|
* pair; an unparseable range is surfaced **verbatim**, a bound is **never
|
|
1855
1997
|
* fabricated**.
|
|
1856
1998
|
*
|
|
1999
|
+
* Every interpreted flag and status also carries the **vocabulary it was graded
|
|
2000
|
+
* against**, recognized or not, so an unknown code is distinguishable from one
|
|
2001
|
+
* this library has not caught up to. The status set's attribution is the
|
|
2002
|
+
* explicit "no citable published source": see `../common/vocabulary.js`.
|
|
2003
|
+
*
|
|
1857
2004
|
* Every bound and code is surfaced verbatim; nothing is collapsed, reconciled,
|
|
1858
2005
|
* or converted. Units are handled at the record layer (a numeric value without
|
|
1859
2006
|
* units warns; units are never defaulted, guessed, or converted, see
|
|
1860
2007
|
* `./parse.ts`).
|
|
1861
2008
|
*/
|
|
2009
|
+
|
|
2010
|
+
/**
|
|
2011
|
+
* The recognized abnormal-flag letters, graded against
|
|
2012
|
+
* {@link ABNORMAL_FLAG_VOCABULARY} (the flag *value* set, a published fact set,
|
|
2013
|
+
* not CLSI prose). That code system carries the concepts kept aligned with the
|
|
2014
|
+
* HL7 v2 Table 0078 interpretation codes. Read in the context of an `R` record's
|
|
2015
|
+
* field 7: here `S`/`R`/`I` are the microbiology susceptibility codes and `R` is
|
|
2016
|
+
* **not** the repeat delimiter.
|
|
2017
|
+
*
|
|
2018
|
+
* Recognition is **exact match** after the surrounding whitespace is trimmed:
|
|
2019
|
+
* letter case is never folded, so `hu` is unrecognized and stays that way.
|
|
2020
|
+
*/
|
|
2021
|
+
type AbnormalFlagCode = "L" | "H" | "LL" | "HH" | "<" | ">" | "N" | "A" | "AA" | "U" | "D" | "B" | "W" | "S" | "R" | "I" | "HU" | "LU";
|
|
1862
2022
|
/**
|
|
1863
|
-
* The
|
|
1864
|
-
*
|
|
1865
|
-
*
|
|
1866
|
-
* codes and `R` is **not** the repeat delimiter.
|
|
2023
|
+
* The modeled meaning of a recognized {@link AbnormalFlagCode}, plus the
|
|
2024
|
+
* fail-safe sentinel `undefined` (a flag was present but is not in the graded
|
|
2025
|
+
* vocabulary), which is **never** collapsed to `normal`.
|
|
1867
2026
|
*/
|
|
1868
|
-
type
|
|
2027
|
+
type AbnormalFlagMeaning = "below-normal" | "above-normal" | "critically-below-normal" | "critically-above-normal" | "below-scale" | "above-scale" | "normal" | "abnormal" | "very-abnormal" | "significant-change-up" | "significant-change-down" | "better" | "worse" | "susceptible" | "resistant" | "intermediate" | "significantly-high" | "significantly-low" | "undefined";
|
|
1869
2028
|
/**
|
|
1870
|
-
*
|
|
1871
|
-
*
|
|
1872
|
-
*
|
|
2029
|
+
* Every abnormal-flag letter this library recognizes, in declaration order. A
|
|
2030
|
+
* letter outside this list is surfaced verbatim as unrecognized, never guessed
|
|
2031
|
+
* into a meaning.
|
|
2032
|
+
*
|
|
2033
|
+
* @example
|
|
2034
|
+
* ```ts
|
|
2035
|
+
* import { ABNORMAL_FLAG_CODES } from "@cosyte/astm";
|
|
2036
|
+
* ABNORMAL_FLAG_CODES.includes("HU"); // true
|
|
2037
|
+
* ```
|
|
1873
2038
|
*/
|
|
1874
|
-
|
|
2039
|
+
declare const ABNORMAL_FLAG_CODES: readonly AbnormalFlagCode[];
|
|
1875
2040
|
/**
|
|
1876
2041
|
* A recognized (or explicitly *un*recognized) abnormal flag. The raw field text
|
|
1877
2042
|
* is always preserved; `recognized` is `false` and `meaning` is `"undefined"`
|
|
1878
|
-
* for any letter outside
|
|
1879
|
-
* **never coerced to `normal`**.
|
|
2043
|
+
* for any letter outside the graded vocabulary, the flag is surfaced, never
|
|
2044
|
+
* dropped, and **never coerced to `normal`**.
|
|
2045
|
+
*
|
|
2046
|
+
* `vocabulary` is present either way, so a consumer holding an unrecognized flag
|
|
2047
|
+
* can tell a code no published vocabulary defines from one this library has not
|
|
2048
|
+
* caught up to.
|
|
1880
2049
|
*
|
|
1881
2050
|
* @example
|
|
1882
2051
|
* ```ts
|
|
1883
2052
|
* import { interpretAbnormalFlag } from "@cosyte/astm";
|
|
1884
2053
|
* const f = interpretAbnormalFlag("HH");
|
|
1885
|
-
* f.meaning;
|
|
1886
|
-
* f.recognized;
|
|
2054
|
+
* f.meaning; // "critically-above-normal"
|
|
2055
|
+
* f.recognized; // true
|
|
2056
|
+
* f.vocabulary.version; // the code system version compared against
|
|
1887
2057
|
* ```
|
|
1888
2058
|
*/
|
|
1889
2059
|
interface AbnormalFlag {
|
|
1890
2060
|
/** The verbatim field text, exactly as received. */
|
|
1891
2061
|
readonly raw: string;
|
|
1892
|
-
/** The
|
|
2062
|
+
/** The recognized code, present only when the raw text is a recognized flag. */
|
|
1893
2063
|
readonly code?: AbnormalFlagCode;
|
|
1894
2064
|
/** The modeled meaning; `"undefined"` (never `"normal"`) for an unrecognized flag. */
|
|
1895
2065
|
readonly meaning: AbnormalFlagMeaning;
|
|
1896
|
-
/** Whether the raw text matched a
|
|
2066
|
+
/** Whether the raw text matched a flag in the graded vocabulary. */
|
|
1897
2067
|
readonly recognized: boolean;
|
|
2068
|
+
/**
|
|
2069
|
+
* The published code system this flag was graded against, named by identifier
|
|
2070
|
+
* and version. Always present, recognized or not. The version says what this
|
|
2071
|
+
* library compared against, **not** what the sender meant.
|
|
2072
|
+
*/
|
|
2073
|
+
readonly vocabulary: NamedVocabulary;
|
|
1898
2074
|
}
|
|
1899
2075
|
/**
|
|
1900
|
-
* Interpret an `R`-record abnormal-flag field (field 7) against
|
|
2076
|
+
* Interpret an `R`-record abnormal-flag field (field 7) against
|
|
2077
|
+
* {@link ABNORMAL_FLAG_VOCABULARY}.
|
|
1901
2078
|
*
|
|
1902
2079
|
* Leading/trailing whitespace is ignored for the lookup but the `raw` text is
|
|
1903
|
-
* preserved verbatim.
|
|
1904
|
-
*
|
|
2080
|
+
* preserved verbatim. Matching is otherwise **exact**: letter case is never
|
|
2081
|
+
* folded. An unrecognized flag yields `{ recognized: false, meaning:
|
|
2082
|
+
* "undefined" }`, surfaced, never dropped, and **never `"normal"`**, and still
|
|
2083
|
+
* carries the vocabulary it was graded against.
|
|
1905
2084
|
*
|
|
1906
2085
|
* @param raw - The verbatim field-7 text.
|
|
1907
2086
|
* @returns The interpreted flag.
|
|
@@ -1909,6 +2088,7 @@ interface AbnormalFlag {
|
|
|
1909
2088
|
* ```ts
|
|
1910
2089
|
* import { interpretAbnormalFlag } from "@cosyte/astm";
|
|
1911
2090
|
* interpretAbnormalFlag("U").meaning; // "significant-change-up"
|
|
2091
|
+
* interpretAbnormalFlag("HU").meaning; // "significantly-high"
|
|
1912
2092
|
* interpretAbnormalFlag("ZZ").meaning; // "undefined" (never "normal")
|
|
1913
2093
|
* ```
|
|
1914
2094
|
*/
|
|
@@ -1917,6 +2097,10 @@ declare function interpretAbnormalFlag(raw: string): AbnormalFlag;
|
|
|
1917
2097
|
* The recognized result-status letters (`R`-record field 9). The clinically
|
|
1918
2098
|
* load-bearing members are **`C` (correction, supersedes a previously
|
|
1919
2099
|
* transmitted value)** and **`X` (cannot be done / cancelled)**.
|
|
2100
|
+
*
|
|
2101
|
+
* This set is bound by **no citable published source**: see
|
|
2102
|
+
* {@link RESULT_STATUS_VOCABULARY}, which every interpreted status carries. As
|
|
2103
|
+
* with the flags, matching is exact after trimming; letter case is never folded.
|
|
1920
2104
|
*/
|
|
1921
2105
|
type ResultStatusCode = "F" | "C" | "P" | "R" | "S" | "I" | "X";
|
|
1922
2106
|
/**
|
|
@@ -1937,12 +2121,17 @@ type ResultStatusMeaning = "final" | "correction" | "preliminary" | "previously-
|
|
|
1937
2121
|
* transmitted one.
|
|
1938
2122
|
* - **`cancelled`** is `true` for `X`: the result cannot be done / was cancelled.
|
|
1939
2123
|
*
|
|
2124
|
+
* `vocabulary` is always the explicit "no citable published source": this letter
|
|
2125
|
+
* set is modeled from what analyzers send, not from a vocabulary this library
|
|
2126
|
+
* can name.
|
|
2127
|
+
*
|
|
1940
2128
|
* @example
|
|
1941
2129
|
* ```ts
|
|
1942
2130
|
* import { interpretResultStatus } from "@cosyte/astm";
|
|
1943
|
-
* interpretResultStatus("C").isActiveFinal;
|
|
1944
|
-
* interpretResultStatus("X").cancelled;
|
|
1945
|
-
* interpretResultStatus(undefined).meaning;
|
|
2131
|
+
* interpretResultStatus("C").isActiveFinal; // false (a correction is not active-final)
|
|
2132
|
+
* interpretResultStatus("X").cancelled; // true
|
|
2133
|
+
* interpretResultStatus(undefined).meaning; // "unspecified" (never "final")
|
|
2134
|
+
* interpretResultStatus("F").vocabulary.attributed; // false: nothing is cited
|
|
1946
2135
|
* ```
|
|
1947
2136
|
*/
|
|
1948
2137
|
interface ResultStatus {
|
|
@@ -1960,6 +2149,12 @@ interface ResultStatus {
|
|
|
1960
2149
|
readonly supersedes: boolean;
|
|
1961
2150
|
/** `true` for `X`: the result cannot be done / was cancelled. */
|
|
1962
2151
|
readonly cancelled: boolean;
|
|
2152
|
+
/**
|
|
2153
|
+
* The explicit statement that this letter set is bound by **no citable
|
|
2154
|
+
* published source**. Always present and always unattributed, so an absent
|
|
2155
|
+
* attribution and an unattributable one never look alike.
|
|
2156
|
+
*/
|
|
2157
|
+
readonly vocabulary: UnattributedVocabulary;
|
|
1963
2158
|
}
|
|
1964
2159
|
/**
|
|
1965
2160
|
* Interpret an `R`-record result-status field (field 9).
|
|
@@ -1969,14 +2164,18 @@ interface ResultStatus {
|
|
|
1969
2164
|
* (recognized `false`). In every non-`F` case `isActiveFinal` is `false`, so a
|
|
1970
2165
|
* correction, a cancellation, or an unknown status can never read as current.
|
|
1971
2166
|
*
|
|
2167
|
+
* Every returned status carries {@link RESULT_STATUS_VOCABULARY}: the explicit
|
|
2168
|
+
* statement that no published source binding this letter set can be cited.
|
|
2169
|
+
*
|
|
1972
2170
|
* @param raw - The verbatim field-9 text, or `undefined`/empty when absent.
|
|
1973
2171
|
* @returns The modeled status.
|
|
1974
2172
|
* @example
|
|
1975
2173
|
* ```ts
|
|
1976
2174
|
* import { interpretResultStatus } from "@cosyte/astm";
|
|
1977
2175
|
* const s = interpretResultStatus("F");
|
|
1978
|
-
* s.isActiveFinal;
|
|
1979
|
-
* s.supersedes;
|
|
2176
|
+
* s.isActiveFinal; // true
|
|
2177
|
+
* s.supersedes; // false
|
|
2178
|
+
* s.vocabulary.attributed; // false: nothing is cited for this set
|
|
1980
2179
|
* ```
|
|
1981
2180
|
*/
|
|
1982
2181
|
declare function interpretResultStatus(raw: string | undefined): ResultStatus;
|
|
@@ -4285,6 +4484,183 @@ declare function decodeEscapes(leaf: string, d: Delimiters, onUnknown?: UnknownE
|
|
|
4285
4484
|
*/
|
|
4286
4485
|
declare function splitEscapeAware(text: string, delimiter: string, escape: string, onAmbiguousAlignment?: AmbiguousAlignmentSink, onShiftedFields?: ShiftedFieldsSink, onTruncatedField?: TruncatedFieldSink, onShiftedComponents?: ShiftedComponentsSink): string[];
|
|
4287
4486
|
|
|
4487
|
+
/**
|
|
4488
|
+
* The shared `@cosyte/*` date conversion surface, over {@link AstmDate}.
|
|
4489
|
+
*
|
|
4490
|
+
* `toObject`, `toISO` and `toDate` carry the same names, the same return shapes
|
|
4491
|
+
* and the same timezone rule in every `@cosyte` parser, so moving between two of
|
|
4492
|
+
* them costs nothing to relearn. They are **additive**: {@link astmDateToLocalISO}
|
|
4493
|
+
* and {@link parseAstmDate} are untouched, and `toISO` renders exactly the string
|
|
4494
|
+
* `astmDateToLocalISO` renders for every value `parseAstmDate` produces.
|
|
4495
|
+
*
|
|
4496
|
+
* **ASTM is the strictest case for the rule these functions exist for.** An ASTM
|
|
4497
|
+
* timestamp models **no timezone at all**: the value is local to the instrument
|
|
4498
|
+
* that wrote it. So an ASTM value is never an absolute instant on its own, and
|
|
4499
|
+
* {@link toDate} answers `undefined` until the caller says which zone the
|
|
4500
|
+
* instrument was in (`assumeOffsetMinutes`). The host machine's zone is never
|
|
4501
|
+
* read and UTC is never assumed: either guess shifts a date of birth by a day in
|
|
4502
|
+
* every negative-offset zone, silently, and nothing throws to say so.
|
|
4503
|
+
*
|
|
4504
|
+
* Nothing here fabricates a component either. A value stated to day precision
|
|
4505
|
+
* converts to a day, never to a fabricated midnight, and the components a value
|
|
4506
|
+
* did not state are **absent** from {@link DateParts} rather than zero-filled.
|
|
4507
|
+
*
|
|
4508
|
+
* **Nor does anything here normalise a component that is out of calendar range.**
|
|
4509
|
+
* `parseAstmDate` is lenient by design and reads `19881301` into month 13, so the
|
|
4510
|
+
* conversions are where that has to be answered. All three refuse such a value
|
|
4511
|
+
* (`undefined`, never a throw), because the alternative is what a JS `Date` does
|
|
4512
|
+
* with it: month 13 rolls into January of the following year and comes back as a
|
|
4513
|
+
* confident, wrong instant that no warning marks. A date of birth is the case
|
|
4514
|
+
* that decided it.
|
|
4515
|
+
*/
|
|
4516
|
+
|
|
4517
|
+
/**
|
|
4518
|
+
* The calendar components a parsed value actually stated: the shared return
|
|
4519
|
+
* shape of {@link toObject} across every `@cosyte` parser.
|
|
4520
|
+
*
|
|
4521
|
+
* Every value is a `number` and `month` is **spec-native 1 to 12**, never the JS
|
|
4522
|
+
* `Date` 0 to 11. A component the value did not state is **absent**: the key is
|
|
4523
|
+
* not present at all, rather than present and `undefined`, so `Object.keys()` of
|
|
4524
|
+
* the result is exactly the set of stated components and the value's precision is
|
|
4525
|
+
* recoverable from it. There is no `precision`, `raw`, `valid` or `truncated` key:
|
|
4526
|
+
* this is the calendar reading, not the parse record.
|
|
4527
|
+
*
|
|
4528
|
+
* Deleting `offsetMinutes` leaves an object `Temporal.PlainDateTime.from` and
|
|
4529
|
+
* luxon's `DateTime.fromObject` accept with no key rename and no value
|
|
4530
|
+
* adjustment, which is why the keys are singular and the month is 1-based.
|
|
4531
|
+
* Neither library is a dependency of this package: the shape is the interop, not
|
|
4532
|
+
* an import.
|
|
4533
|
+
*
|
|
4534
|
+
* `millisecond` and `offsetMinutes` belong to the shared shape and are **never
|
|
4535
|
+
* populated by this package**: an ASTM timestamp carries no timezone, and this
|
|
4536
|
+
* parser retains no fractional-second component (the digits stay in
|
|
4537
|
+
* {@link AstmDate.raw}). They are declared so that code written over two
|
|
4538
|
+
* `@cosyte` parsers reads one shape rather than two.
|
|
4539
|
+
*/
|
|
4540
|
+
interface DateParts {
|
|
4541
|
+
/** Four-digit calendar year, exactly as stated (`50` is the year 50, not 1950). */
|
|
4542
|
+
readonly year?: number;
|
|
4543
|
+
/** Calendar month, **1 to 12**, as the standard states it. */
|
|
4544
|
+
readonly month?: number;
|
|
4545
|
+
/** Day of month, 1 to 31. */
|
|
4546
|
+
readonly day?: number;
|
|
4547
|
+
/** Hour of day, 0 to 23. */
|
|
4548
|
+
readonly hour?: number;
|
|
4549
|
+
/** Minute of hour, 0 to 59. */
|
|
4550
|
+
readonly minute?: number;
|
|
4551
|
+
/** Second of minute, 0 to 59. */
|
|
4552
|
+
readonly second?: number;
|
|
4553
|
+
/** Millisecond. Never populated here: this parser retains no fractional second. */
|
|
4554
|
+
readonly millisecond?: number;
|
|
4555
|
+
/** Signed minutes east of UTC. Never populated here: ASTM states no offset. */
|
|
4556
|
+
readonly offsetMinutes?: number;
|
|
4557
|
+
}
|
|
4558
|
+
/** The options {@link toDate} accepts. Carries `assumeOffsetMinutes` and nothing else. */
|
|
4559
|
+
interface ToDateOptions {
|
|
4560
|
+
/**
|
|
4561
|
+
* The zone to read an offset-less value in, as signed minutes east of UTC
|
|
4562
|
+
* (`-300` is UTC-05:00). Supplying `0` means "treat this value as UTC", which
|
|
4563
|
+
* is a decision only the caller can make: an ASTM value states no offset, so
|
|
4564
|
+
* without this option {@link toDate} returns `undefined` rather than guessing.
|
|
4565
|
+
*/
|
|
4566
|
+
readonly assumeOffsetMinutes?: number;
|
|
4567
|
+
}
|
|
4568
|
+
/**
|
|
4569
|
+
* Read a parsed ASTM date as the shared {@link DateParts} object: only the
|
|
4570
|
+
* components the value stated, frozen, with a spec-native 1-to-12 month.
|
|
4571
|
+
*
|
|
4572
|
+
* Returns `undefined` for `undefined`, for `null`, for a value that stated no
|
|
4573
|
+
* component at all, and for one whose stated components are not a real calendar
|
|
4574
|
+
* date (a month outside 1 to 12, a day past the end of that month, an hour past
|
|
4575
|
+
* 23, a minute or second past 59). Never throws, whatever it is handed. The
|
|
4576
|
+
* truncation flag, the precision and the raw digit run are deliberately not
|
|
4577
|
+
* carried over: a dangling half-component was never a complete component, so it
|
|
4578
|
+
* appears in no field here.
|
|
4579
|
+
*
|
|
4580
|
+
* The out-of-range refusal is total, not per component: `"19881301"` answers
|
|
4581
|
+
* `undefined`, not `{ year: 1988 }`, because a year-precision date of birth is
|
|
4582
|
+
* not what that instrument sent either.
|
|
4583
|
+
*
|
|
4584
|
+
* @param value - A parsed date, or the `undefined` {@link parseAstmDate} returns.
|
|
4585
|
+
* @returns The stated components, frozen, or `undefined`.
|
|
4586
|
+
* @example
|
|
4587
|
+
* ```ts
|
|
4588
|
+
* import { parseAstmDate, toObject } from "@cosyte/astm";
|
|
4589
|
+
* toObject(parseAstmDate("20240315")); // { year: 2024, month: 3, day: 15 }
|
|
4590
|
+
* Object.keys(toObject(parseAstmDate("2024")) ?? {}); // ["year"]
|
|
4591
|
+
* toObject(parseAstmDate("19881301")); // undefined: there is no month 13
|
|
4592
|
+
* ```
|
|
4593
|
+
*/
|
|
4594
|
+
declare function toObject(value: AstmDate | null | undefined): DateParts | undefined;
|
|
4595
|
+
/**
|
|
4596
|
+
* Render a parsed ASTM date as ISO-8601, truncated to the precision it stated
|
|
4597
|
+
* and **never** padded out to a precision it did not.
|
|
4598
|
+
*
|
|
4599
|
+
* No `Z` and no offset is ever appended, because ASTM states none and appending
|
|
4600
|
+
* one would fabricate the instrument's zone. The string is deliberately
|
|
4601
|
+
* zone-less. It is identical to what {@link astmDateToLocalISO} returns for every
|
|
4602
|
+
* value {@link parseAstmDate} produces **whose components are a real calendar
|
|
4603
|
+
* date**; the shared name is the portable route and the repo-native name is
|
|
4604
|
+
* unchanged. On a run that is not, the two differ on purpose and only in one
|
|
4605
|
+
* direction: `astmDateToLocalISO` still renders the digits it was given
|
|
4606
|
+
* (`"1988-13-01"`), because that is its pinned behaviour, and `toISO` answers
|
|
4607
|
+
* `undefined` rather than emit a string no ISO-8601 reader accepts.
|
|
4608
|
+
*
|
|
4609
|
+
* Returns `undefined` for `undefined`, for `null`, for a value stating no
|
|
4610
|
+
* component, for one whose components are not a real calendar date, and for one
|
|
4611
|
+
* stating no year: an ASTM timestamp opens with a mandatory four-digit year, so a
|
|
4612
|
+
* yearless value is not one this parser reads. Never throws.
|
|
4613
|
+
*
|
|
4614
|
+
* @param value - A parsed date, or the `undefined` {@link parseAstmDate} returns.
|
|
4615
|
+
* @returns e.g. `"2024-03-15T09:30"` (minute precision) or `"2024-03"` (month).
|
|
4616
|
+
* @example
|
|
4617
|
+
* ```ts
|
|
4618
|
+
* import { parseAstmDate, toISO } from "@cosyte/astm";
|
|
4619
|
+
* toISO(parseAstmDate("202403150930")); // "2024-03-15T09:30"
|
|
4620
|
+
* toISO(parseAstmDate("not a date")); // undefined
|
|
4621
|
+
* toISO(parseAstmDate("20240230")); // undefined: February has no 30th
|
|
4622
|
+
* ```
|
|
4623
|
+
*/
|
|
4624
|
+
declare function toISO(value: AstmDate | null | undefined): string | undefined;
|
|
4625
|
+
/**
|
|
4626
|
+
* Convert a parsed ASTM date to an absolute-instant JS `Date`, **only** when the
|
|
4627
|
+
* caller has made the zone determinate.
|
|
4628
|
+
*
|
|
4629
|
+
* ASTM carries no timezone, so `toDate` returns `undefined` unless
|
|
4630
|
+
* `options.assumeOffsetMinutes` says which zone the instrument was in. The host
|
|
4631
|
+
* machine's zone is never read and UTC is never assumed. A value stating no year
|
|
4632
|
+
* is never an instant either, and neither is one whose components are not a real
|
|
4633
|
+
* calendar date: month 13 becomes January of the next year in a JS `Date`, and
|
|
4634
|
+
* that silent roll-over is the reason the range is checked before the instant is
|
|
4635
|
+
* built rather than after.
|
|
4636
|
+
*
|
|
4637
|
+
* An `assumeOffsetMinutes` that names no usable zone is refused the same way,
|
|
4638
|
+
* with `undefined`: one that is not a finite number (`NaN`, either infinity),
|
|
4639
|
+
* and one so large that applying it puts the result outside the range a JS
|
|
4640
|
+
* `Date` represents. **The answer is never an `Invalid Date`.** Such a `Date`
|
|
4641
|
+
* satisfies this signature and defeats it, because a caller cannot tell it from
|
|
4642
|
+
* a real instant without testing `getTime()` for `NaN`, and `toISOString()` on
|
|
4643
|
+
* it throws.
|
|
4644
|
+
*
|
|
4645
|
+
* Components below the stated precision fill to their lowest legal value (month
|
|
4646
|
+
* and day to 1, time to 0) **for instant construction only**: the value itself is
|
|
4647
|
+
* unchanged, and {@link toObject} and {@link toISO} report exactly what they
|
|
4648
|
+
* reported before the call.
|
|
4649
|
+
*
|
|
4650
|
+
* @param value - A parsed date, or the `undefined` {@link parseAstmDate} returns.
|
|
4651
|
+
* @param options - The zone assumption to apply, as signed minutes east of UTC.
|
|
4652
|
+
* @returns The instant, or `undefined` when the zone or the year is unstated.
|
|
4653
|
+
* @example
|
|
4654
|
+
* ```ts
|
|
4655
|
+
* import { parseAstmDate, toDate } from "@cosyte/astm";
|
|
4656
|
+
* const d = parseAstmDate("20240315");
|
|
4657
|
+
* toDate(d); // undefined: no zone was stated
|
|
4658
|
+
* toDate(d, { assumeOffsetMinutes: -300 }); // 2024-03-15T05:00:00.000Z
|
|
4659
|
+
* toDate(parseAstmDate("19881301"), { assumeOffsetMinutes: 0 }); // undefined, not 1989
|
|
4660
|
+
* ```
|
|
4661
|
+
*/
|
|
4662
|
+
declare function toDate(value: AstmDate | null | undefined, options?: ToDateOptions): Date | undefined;
|
|
4663
|
+
|
|
4288
4664
|
/**
|
|
4289
4665
|
* Deep-freeze helper for the immutable ASTM model.
|
|
4290
4666
|
*
|
|
@@ -5092,6 +5468,207 @@ declare const astmProfiles: {
|
|
|
5092
5468
|
readonly referenceCorpus: typeof referenceCorpus;
|
|
5093
5469
|
};
|
|
5094
5470
|
|
|
5471
|
+
/**
|
|
5472
|
+
* The **terminology** warning registry (`ASTM_LIVD_*`) for the LIVD-aware LOINC
|
|
5473
|
+
* recognition layer: the fourth of the package's registries,
|
|
5474
|
+
* alongside the record layer's `ASTM_RECORD_*`, the frame codec's `ASTM_FRAME_*`,
|
|
5475
|
+
* and the protocol reducer's `ASTM_LTP_*`.
|
|
5476
|
+
*
|
|
5477
|
+
* A terminology warning is the record of a **safe non-mapping**: a reported
|
|
5478
|
+
* vendor test code that a consumer-supplied LIVD catalog did not map to a single
|
|
5479
|
+
* LOINC. It never carries a LOINC the catalog did not vouch for: the whole point
|
|
5480
|
+
* of the layer is that an unmapped or ambiguous code is surfaced as *unmapped*,
|
|
5481
|
+
* **never a guessed LOINC** (mis-identifying a test is safety-critical). Every
|
|
5482
|
+
* warning carries a stable code and a message that is a **constant**, and
|
|
5483
|
+
* **never** a field value, a reported code or any text the consumer stored in
|
|
5484
|
+
* their catalog. Consumers compare `warning.code ===
|
|
5485
|
+
* LIVD_WARNING_CODES.<CODE>`; renaming a code is a **breaking change**.
|
|
5486
|
+
*
|
|
5487
|
+
* **Two shapes, by what the warning is about.** A warning about a RECORD carries
|
|
5488
|
+
* positional context ({@link AstmPosition}) and is an {@link AstmLivdWarning}: one
|
|
5489
|
+
* per unmapped or ambiguous code, produced while a message is annotated. A warning
|
|
5490
|
+
* about the CATALOG ITSELF carries no position, because no record is implicated: it
|
|
5491
|
+
* is an {@link AstmLivdCatalogWarning}, raised once where the catalog is defined,
|
|
5492
|
+
* and it names the catalog through a structured field
|
|
5493
|
+
* ({@link LivdCatalogIdentity}) rather than through its message text, so a consumer
|
|
5494
|
+
* who logs only the message can never emit text they stored in their catalog.
|
|
5495
|
+
*
|
|
5496
|
+
* These codes live in their own registry and are deliberately **not** part of the
|
|
5497
|
+
* profile safety gate's universe (`ALL_ASTM_WARNING_CODES`): a LIVD non-mapping is
|
|
5498
|
+
* a post-parse advisory produced by the opt-in {@link applyLivd} helper, not a
|
|
5499
|
+
* parse-time deviation a vendor profile could ever "tolerate". A profile referencing
|
|
5500
|
+
* one is rejected as an unknown code: correctly, since there is nothing here to
|
|
5501
|
+
* quiet.
|
|
5502
|
+
*/
|
|
5503
|
+
|
|
5504
|
+
/**
|
|
5505
|
+
* Stable string codes for every terminology (LIVD) warning. `key === value` so
|
|
5506
|
+
* `Object.values(...)` yields a stable snapshot set.
|
|
5507
|
+
*
|
|
5508
|
+
* @example
|
|
5509
|
+
* ```ts
|
|
5510
|
+
* import { LIVD_WARNING_CODES } from "@cosyte/astm";
|
|
5511
|
+
* LIVD_WARNING_CODES.ASTM_LIVD_UNMAPPED_CODE; // "ASTM_LIVD_UNMAPPED_CODE"
|
|
5512
|
+
* ```
|
|
5513
|
+
*/
|
|
5514
|
+
declare const LIVD_WARNING_CODES: {
|
|
5515
|
+
/**
|
|
5516
|
+
* A record carried a vendor/local test code, but the consumer-supplied LIVD catalog held **no**
|
|
5517
|
+
* entry for it. The code stays surfaced verbatim and the mapping is `unmapped`: a LOINC is
|
|
5518
|
+
* **never** guessed. Purely advisory: the raw code and value are untouched.
|
|
5519
|
+
*/
|
|
5520
|
+
readonly ASTM_LIVD_UNMAPPED_CODE: "ASTM_LIVD_UNMAPPED_CODE";
|
|
5521
|
+
/**
|
|
5522
|
+
* A vendor/local test code matched **more than one distinct LOINC** in the catalog (e.g. the same
|
|
5523
|
+
* transmission code used by two devices for different analytes). The mapping is `ambiguous` and the
|
|
5524
|
+
* candidate LOINCs are surfaced for inspection, but **none is chosen**: refusing to pick is the
|
|
5525
|
+
* fail-safe, since guessing wrong mis-identifies the test.
|
|
5526
|
+
*/
|
|
5527
|
+
readonly ASTM_LIVD_AMBIGUOUS_MAPPING: "ASTM_LIVD_AMBIGUOUS_MAPPING";
|
|
5528
|
+
/**
|
|
5529
|
+
* A consumer-supplied LIVD catalog was defined **without a LOINC version**, so a mapping it
|
|
5530
|
+
* produces cannot say which version of LOINC it was made against. Advisory and **never a
|
|
5531
|
+
* refusal**: the catalog is still built, still indexed and still answers exactly as it would
|
|
5532
|
+
* have. Raised **once, where the catalog is defined**, and never per record: it is a fact about
|
|
5533
|
+
* the catalog rather than about any message, so it never joins the per-record warning stream.
|
|
5534
|
+
*/
|
|
5535
|
+
readonly ASTM_LIVD_CATALOG_NO_LOINC_VERSION: "ASTM_LIVD_CATALOG_NO_LOINC_VERSION";
|
|
5536
|
+
};
|
|
5537
|
+
/**
|
|
5538
|
+
* Discriminant type for every code in {@link LIVD_WARNING_CODES}, the per-record
|
|
5539
|
+
* codes and the catalog-level one alike. Narrowing by this code lets consumers
|
|
5540
|
+
* write exhaustive `switch` blocks against the registry. It tracks the registry
|
|
5541
|
+
* exactly, so `Object.values(LIVD_WARNING_CODES)` stays a snapshot of this type.
|
|
5542
|
+
*/
|
|
5543
|
+
type LivdWarningCode = (typeof LIVD_WARNING_CODES)[keyof typeof LIVD_WARNING_CODES];
|
|
5544
|
+
/**
|
|
5545
|
+
* A single terminology (LIVD) warning: a stable code, a value-free human-readable
|
|
5546
|
+
* message, and positional context. Never carries a test code, a value, or a LOINC.
|
|
5547
|
+
*
|
|
5548
|
+
* @example
|
|
5549
|
+
* ```ts
|
|
5550
|
+
* import type { AstmLivdWarning } from "@cosyte/astm";
|
|
5551
|
+
* const w: AstmLivdWarning = {
|
|
5552
|
+
* code: "ASTM_LIVD_UNMAPPED_CODE",
|
|
5553
|
+
* message: "Reported test code had no LIVD mapping, surfaced unmapped, never a guessed LOINC.",
|
|
5554
|
+
* position: { recordIndex: 3, recordType: "R" },
|
|
5555
|
+
* };
|
|
5556
|
+
* ```
|
|
5557
|
+
*/
|
|
5558
|
+
interface AstmLivdWarning {
|
|
5559
|
+
readonly code: LivdWarningCode;
|
|
5560
|
+
/** Human-readable detail for logs. Never contains a test code, a value, or a LOINC. */
|
|
5561
|
+
readonly message: string;
|
|
5562
|
+
readonly position: AstmPosition;
|
|
5563
|
+
}
|
|
5564
|
+
/**
|
|
5565
|
+
* Build an `ASTM_LIVD_UNMAPPED_CODE` warning. The reported code stays verbatim and
|
|
5566
|
+
* the mapping is `unmapped`; no LOINC is fabricated.
|
|
5567
|
+
*
|
|
5568
|
+
* @param position - Where the unmapped code was seen (record ordinal + type; never the code).
|
|
5569
|
+
* @returns The warning.
|
|
5570
|
+
* @example
|
|
5571
|
+
* ```ts
|
|
5572
|
+
* import { livdUnmappedCode } from "@cosyte/astm";
|
|
5573
|
+
* livdUnmappedCode({ recordIndex: 3, recordType: "R" });
|
|
5574
|
+
* ```
|
|
5575
|
+
*/
|
|
5576
|
+
declare function livdUnmappedCode(position: AstmPosition): AstmLivdWarning;
|
|
5577
|
+
/**
|
|
5578
|
+
* Build an `ASTM_LIVD_AMBIGUOUS_MAPPING` warning. The code matched multiple distinct
|
|
5579
|
+
* LOINCs; none is chosen (refusing to pick is the fail-safe).
|
|
5580
|
+
*
|
|
5581
|
+
* @param position - Where the ambiguous code was seen (record ordinal + type; never the code).
|
|
5582
|
+
* @returns The warning.
|
|
5583
|
+
* @example
|
|
5584
|
+
* ```ts
|
|
5585
|
+
* import { livdAmbiguousMapping } from "@cosyte/astm";
|
|
5586
|
+
* livdAmbiguousMapping({ recordIndex: 4, recordType: "O" });
|
|
5587
|
+
* ```
|
|
5588
|
+
*/
|
|
5589
|
+
declare function livdAmbiguousMapping(position: AstmPosition): AstmLivdWarning;
|
|
5590
|
+
/**
|
|
5591
|
+
* What a LIVD catalog declared about its own identity: the two publication elements
|
|
5592
|
+
* that name a publication, or the explicit statement that it declared neither.
|
|
5593
|
+
*
|
|
5594
|
+
* The same two shapes the rest of this package uses for attribution: a named source,
|
|
5595
|
+
* or a positive "nothing citable", never an absent field and never an invented name.
|
|
5596
|
+
* Discriminate on `declared`.
|
|
5597
|
+
*
|
|
5598
|
+
* @example
|
|
5599
|
+
* ```ts
|
|
5600
|
+
* import type { LivdCatalogIdentity } from "@cosyte/astm";
|
|
5601
|
+
* const named: LivdCatalogIdentity = { declared: true, publisher: "Example Diagnostics" };
|
|
5602
|
+
* ```
|
|
5603
|
+
*/
|
|
5604
|
+
type LivdCatalogIdentity = {
|
|
5605
|
+
/** Always `true`: the catalog declared at least one of the two elements below. */
|
|
5606
|
+
readonly declared: true;
|
|
5607
|
+
/** The **Publisher** the catalog declared, verbatim, when it declared one. */
|
|
5608
|
+
readonly publisher?: string;
|
|
5609
|
+
/** The **Publication Version ID** the catalog declared, verbatim, when it declared one. */
|
|
5610
|
+
readonly publicationVersion?: string;
|
|
5611
|
+
} | {
|
|
5612
|
+
/** Always `false`: the catalog declared neither a publisher nor a publication version. */
|
|
5613
|
+
readonly declared: false;
|
|
5614
|
+
/** Fixed prose saying that no identity was declared. Never an invented or indexed name. */
|
|
5615
|
+
readonly reason: string;
|
|
5616
|
+
};
|
|
5617
|
+
/**
|
|
5618
|
+
* The identity reported for a catalog that declared neither a publisher nor a
|
|
5619
|
+
* publication version: a positive statement that it declared none.
|
|
5620
|
+
*
|
|
5621
|
+
* It exists so that case is said rather than left to an absent field, and so nothing
|
|
5622
|
+
* has to invent a name, an ordinal or a position to stand in for one. Frozen.
|
|
5623
|
+
*
|
|
5624
|
+
* @example
|
|
5625
|
+
* ```ts
|
|
5626
|
+
* import { LIVD_CATALOG_IDENTITY_UNDECLARED } from "@cosyte/astm";
|
|
5627
|
+
* LIVD_CATALOG_IDENTITY_UNDECLARED.declared; // false
|
|
5628
|
+
* ```
|
|
5629
|
+
*/
|
|
5630
|
+
declare const LIVD_CATALOG_IDENTITY_UNDECLARED: LivdCatalogIdentity;
|
|
5631
|
+
/**
|
|
5632
|
+
* A catalog-level terminology warning: a stable code, a value-free constant message,
|
|
5633
|
+
* and the catalog's own declared identity. It carries no position, because no record
|
|
5634
|
+
* is implicated, and it is never produced while a message is annotated.
|
|
5635
|
+
*
|
|
5636
|
+
* @example
|
|
5637
|
+
* ```ts
|
|
5638
|
+
* import type { AstmLivdCatalogWarning } from "@cosyte/astm";
|
|
5639
|
+
* const w: AstmLivdCatalogWarning = {
|
|
5640
|
+
* code: "ASTM_LIVD_CATALOG_NO_LOINC_VERSION",
|
|
5641
|
+
* message: "...",
|
|
5642
|
+
* catalog: { declared: true, publisher: "Example Diagnostics", publicationVersion: "2026-01" },
|
|
5643
|
+
* };
|
|
5644
|
+
* ```
|
|
5645
|
+
*/
|
|
5646
|
+
interface AstmLivdCatalogWarning {
|
|
5647
|
+
/** Always `ASTM_LIVD_CATALOG_NO_LOINC_VERSION`. */
|
|
5648
|
+
readonly code: typeof LIVD_WARNING_CODES.ASTM_LIVD_CATALOG_NO_LOINC_VERSION;
|
|
5649
|
+
/**
|
|
5650
|
+
* Human-readable detail for logs. A **constant**: never a test code, a value, a LOINC, or any
|
|
5651
|
+
* text the consumer supplied. The catalog is named by the `catalog` field, not by this string.
|
|
5652
|
+
*/
|
|
5653
|
+
readonly message: string;
|
|
5654
|
+
/** What the catalog declared about itself, or the positive statement that it declared none. */
|
|
5655
|
+
readonly catalog: LivdCatalogIdentity;
|
|
5656
|
+
}
|
|
5657
|
+
/**
|
|
5658
|
+
* Build an `ASTM_LIVD_CATALOG_NO_LOINC_VERSION` warning. Advisory: the catalog it
|
|
5659
|
+
* describes is still built and still answers every lookup exactly as it would have.
|
|
5660
|
+
*
|
|
5661
|
+
* @param catalog - What the catalog declared about its identity; pass
|
|
5662
|
+
* {@link LIVD_CATALOG_IDENTITY_UNDECLARED} where it declared none.
|
|
5663
|
+
* @returns The warning.
|
|
5664
|
+
* @example
|
|
5665
|
+
* ```ts
|
|
5666
|
+
* import { livdCatalogMissingLoincVersion, LIVD_CATALOG_IDENTITY_UNDECLARED } from "@cosyte/astm";
|
|
5667
|
+
* livdCatalogMissingLoincVersion(LIVD_CATALOG_IDENTITY_UNDECLARED);
|
|
5668
|
+
* ```
|
|
5669
|
+
*/
|
|
5670
|
+
declare function livdCatalogMissingLoincVersion(catalog: LivdCatalogIdentity): AstmLivdCatalogWarning;
|
|
5671
|
+
|
|
5095
5672
|
/**
|
|
5096
5673
|
* The **consumer-supplied** LIVD catalog: a vendor-test-code → LOINC index built
|
|
5097
5674
|
* from an IICC LIVD ("LOINC to Vendor IVD") mapping the consumer provides.
|
|
@@ -5122,7 +5699,55 @@ declare const astmProfiles: {
|
|
|
5122
5699
|
* conflicting entries *within* one catalog are caught and surfaced as `ambiguous`
|
|
5123
5700
|
* (never resolved to a guess), but cross-device code reuse the catalog cannot see is
|
|
5124
5701
|
* a catalog-hygiene concern the consumer owns.
|
|
5702
|
+
*
|
|
5703
|
+
* **One vendor analyte code to many LOINCs is the ORDINARY case, and the units are
|
|
5704
|
+
* what tell them apart.** The mapping guide this catalog format comes from describes
|
|
5705
|
+
* the relationship as many-to-many by design, and its own worked examples are the
|
|
5706
|
+
* commonest chemistry analytes: a serum glucose maps to one LOINC as a mass
|
|
5707
|
+
* concentration and to another as a substance concentration, and a urine analyte maps
|
|
5708
|
+
* to one LOINC at `mmol/L` (a spot specimen) and to another at `mmol/(24.h)` (a 24
|
|
5709
|
+
* hour collection). The guide's remedy is to define a mapping per unit, so
|
|
5710
|
+
* {@link LivdEntry.representativeUnit} carries that unit and
|
|
5711
|
+
* {@link LivdCatalog.lookup} compares it with the units the `R` record reported.
|
|
5712
|
+
*
|
|
5713
|
+
* **That comparison is VERBATIM and CASE SENSITIVE, and it is not UCUM.** Nothing is
|
|
5714
|
+
* normalized, converted, case folded or scaled on either side: a catalog saying
|
|
5715
|
+
* `mg/dL` does not match a feed saying `MG/DL`, and a catalog saying `mg/L` never
|
|
5716
|
+
* matches `ug/dL` however convertible the two are. UCUM defines a case-insensitive
|
|
5717
|
+
* variant of every terminal symbol and requires a program claiming full conformance
|
|
5718
|
+
* to compare unit expressions by their SEMANTICS, so a verbatim string comparison is
|
|
5719
|
+
* a deliberately limited choice rather than UCUM conformance. It is the only
|
|
5720
|
+
* comparison that cannot invent an equivalence, and because a consumer could
|
|
5721
|
+
* otherwise read a matched unit as a conformance claim this package does not make,
|
|
5722
|
+
* every unit-selected answer states what the comparison was
|
|
5723
|
+
* ({@link LivdUnitComparison}).
|
|
5724
|
+
*
|
|
5725
|
+
* **A catalog can also say where the mapping came from, and none of it is checked.**
|
|
5726
|
+
* The mapping guide defines four elements about the PUBLICATION rather than about any
|
|
5727
|
+
* row: who published it, which publication version it is, which LOINC version the
|
|
5728
|
+
* mapping was made against, and the attribution statement the LOINC license requires.
|
|
5729
|
+
* {@link LivdPublication} carries all four, every one optional, every one preserved
|
|
5730
|
+
* verbatim, and **not one of them validated**: this package performs no LOINC
|
|
5731
|
+
* validation of any kind, so a LOINC version is stored and surfaced exactly as
|
|
5732
|
+
* supplied and is never parsed, ranged, formatted or compared. Carrying an
|
|
5733
|
+
* attribution statement is not discharging the obligation to make it: the terminology
|
|
5734
|
+
* data, and its license, stay the consumer's.
|
|
5735
|
+
*
|
|
5736
|
+
* **A catalog with no LOINC version is built, and says so.** A mapping whose LOINC
|
|
5737
|
+
* version is unrecorded cannot be reproduced later, so defining a catalog without one
|
|
5738
|
+
* surfaces a value-free `ASTM_LIVD_CATALOG_NO_LOINC_VERSION` warning on
|
|
5739
|
+
* {@link LivdCatalog.warnings}. It is a nudge and never a refusal: the catalog is
|
|
5740
|
+
* built, every lookup answers exactly as it would have, and no per-record warning
|
|
5741
|
+
* moves.
|
|
5742
|
+
*
|
|
5743
|
+
* **The three LIVD attributes are carried verbatim and only one of them is matched
|
|
5744
|
+
* on.** {@link LivdEntry.vendorSpecimenDescription} and
|
|
5745
|
+
* {@link LivdEntry.vendorResultDescription} are free text the guide says is there to
|
|
5746
|
+
* help a laboratory choose by hand and is "not intended to be parsed by an IVD
|
|
5747
|
+
* Software System that automates the mapping": they are stored and surfaced, never
|
|
5748
|
+
* matched on, never normalized. Only the representative unit ever selects.
|
|
5125
5749
|
*/
|
|
5750
|
+
|
|
5126
5751
|
/**
|
|
5127
5752
|
* One LIVD mapping row a consumer supplies: a vendor test code and the LOINC it
|
|
5128
5753
|
* maps to, plus optional human-readable / provenance fields. Modeled on the IICC
|
|
@@ -5155,29 +5780,232 @@ interface LivdEntry {
|
|
|
5155
5780
|
readonly manufacturer?: string;
|
|
5156
5781
|
/** The device **Model**, when the catalog scopes the mapping to a device (optional provenance). */
|
|
5157
5782
|
readonly model?: string;
|
|
5783
|
+
/**
|
|
5784
|
+
* The **Vendor Specimen Description**: the vendor's own human-readable text for the specimen this
|
|
5785
|
+
* mapping is for, such as `"Serum or Plasma"`. Carried **verbatim** (never trimmed, case folded or
|
|
5786
|
+
* normalized) and surfaced for a human to read. **Never matched on**: the mapping guide states this
|
|
5787
|
+
* text is not intended to be parsed by software that automates the mapping, so choosing on it would
|
|
5788
|
+
* be a string guess. Optional, so an existing catalog keeps working unchanged.
|
|
5789
|
+
*/
|
|
5790
|
+
readonly vendorSpecimenDescription?: string;
|
|
5791
|
+
/**
|
|
5792
|
+
* The **Vendor Result Description**: the vendor's own human-readable text for the result this
|
|
5793
|
+
* mapping produces (binary, ordinal, nominal, or a numeric result with its unit). Carried
|
|
5794
|
+
* **verbatim** and surfaced for a human to read; **never matched on**, for the same reason as
|
|
5795
|
+
* {@link LivdEntry.vendorSpecimenDescription}. Optional.
|
|
5796
|
+
*/
|
|
5797
|
+
readonly vendorResultDescription?: string;
|
|
5798
|
+
/**
|
|
5799
|
+
* The **representative unit of measure** for this mapping, preferably a UCUM unit (e.g. `"mg/dL"`,
|
|
5800
|
+
* `"mmol/L"`, `"mmol/(24.h)"`). This is the **one** attribute a lookup ever selects on: when a
|
|
5801
|
+
* vendor analyte code carries several candidate LOINCs, the candidate whose representative unit is
|
|
5802
|
+
* **exactly equal** to the units the `R` record reported is chosen, compared verbatim and case
|
|
5803
|
+
* sensitively with no normalization, conversion or scale factor on either side.
|
|
5804
|
+
*
|
|
5805
|
+
* Absent, empty or whitespace only means **not unit qualified**: such a candidate is never selected
|
|
5806
|
+
* by a unit comparison, though it is still surfaced among an ambiguous answer's candidates.
|
|
5807
|
+
* Optional, so an existing catalog keeps working unchanged.
|
|
5808
|
+
*/
|
|
5809
|
+
readonly representativeUnit?: string;
|
|
5810
|
+
}
|
|
5811
|
+
/**
|
|
5812
|
+
* How a candidate was selected on its unit, stated on the answer so a consumer cannot
|
|
5813
|
+
* read a matched unit as a UCUM conformance claim this package does not make.
|
|
5814
|
+
*
|
|
5815
|
+
* Present on a {@link LivdLookup} **only** when a unit comparison actually chose
|
|
5816
|
+
* between candidate LOINCs. Its whole content is a disclosure: the comparison was a
|
|
5817
|
+
* verbatim, case-sensitive string equality, and **not** a UCUM semantic comparison.
|
|
5818
|
+
* Nothing was normalized, case folded, scaled or converted on either side.
|
|
5819
|
+
*
|
|
5820
|
+
* @example
|
|
5821
|
+
* ```ts
|
|
5822
|
+
* import type { LivdUnitComparison } from "@cosyte/astm";
|
|
5823
|
+
* const c: LivdUnitComparison = {
|
|
5824
|
+
* comparison: "verbatim-case-sensitive",
|
|
5825
|
+
* ucumSemantic: false,
|
|
5826
|
+
* reportedUnits: "mg/dL",
|
|
5827
|
+
* representativeUnit: "mg/dL",
|
|
5828
|
+
* note: "...",
|
|
5829
|
+
* };
|
|
5830
|
+
* ```
|
|
5831
|
+
*/
|
|
5832
|
+
interface LivdUnitComparison {
|
|
5833
|
+
/** Always `"verbatim-case-sensitive"`: an exact string equality, nothing normalized. */
|
|
5834
|
+
readonly comparison: "verbatim-case-sensitive";
|
|
5835
|
+
/** Always `false`. This package does not compare unit expressions by their semantics. */
|
|
5836
|
+
readonly ucumSemantic: false;
|
|
5837
|
+
/** The units the record reported, verbatim. */
|
|
5838
|
+
readonly reportedUnits: string;
|
|
5839
|
+
/** The chosen candidate's representative unit, verbatim. Byte-identical to `reportedUnits`. */
|
|
5840
|
+
readonly representativeUnit: string;
|
|
5841
|
+
/** A human-readable restatement of the two facts above, for a log or a review screen. */
|
|
5842
|
+
readonly note: string;
|
|
5843
|
+
}
|
|
5844
|
+
/**
|
|
5845
|
+
* One candidate mapping behind an `ambiguous` answer: the LOINC plus the LIVD
|
|
5846
|
+
* attributes that tell candidates apart, so a human can choose what this package
|
|
5847
|
+
* refuses to guess.
|
|
5848
|
+
*
|
|
5849
|
+
* One per catalog row for the vendor code, in catalog order, so a LOINC appearing in
|
|
5850
|
+
* two rows appears twice. Every candidate is surfaced, including one that is not unit
|
|
5851
|
+
* qualified: it can never be selected on a unit, but hiding it would hide a mapping
|
|
5852
|
+
* the consumer's own catalog holds.
|
|
5853
|
+
*
|
|
5854
|
+
* @example
|
|
5855
|
+
* ```ts
|
|
5856
|
+
* import type { LivdCandidate } from "@cosyte/astm";
|
|
5857
|
+
* const c: LivdCandidate = {
|
|
5858
|
+
* loinc: "2345-7",
|
|
5859
|
+
* vendorSpecimenDescription: "Serum or Plasma",
|
|
5860
|
+
* representativeUnit: "mg/dL",
|
|
5861
|
+
* unitQualified: true,
|
|
5862
|
+
* };
|
|
5863
|
+
* ```
|
|
5864
|
+
*/
|
|
5865
|
+
interface LivdCandidate {
|
|
5866
|
+
/** The candidate LOINC, verbatim from the catalog row. Never validated. */
|
|
5867
|
+
readonly loinc: string;
|
|
5868
|
+
/** The row's LOINC Long Common Name, when supplied. */
|
|
5869
|
+
readonly loincLongName?: string;
|
|
5870
|
+
/** The row's Vendor Specimen Description, verbatim, when supplied. Never matched on. */
|
|
5871
|
+
readonly vendorSpecimenDescription?: string;
|
|
5872
|
+
/** The row's Vendor Result Description, verbatim, when supplied. Never matched on. */
|
|
5873
|
+
readonly vendorResultDescription?: string;
|
|
5874
|
+
/** The row's representative unit, verbatim, when supplied. */
|
|
5875
|
+
readonly representativeUnit?: string;
|
|
5876
|
+
/**
|
|
5877
|
+
* `false` when the representative unit is absent, empty or whitespace only. Such a candidate is
|
|
5878
|
+
* **never** selected by a unit comparison against any reported units, and is surfaced here anyway.
|
|
5879
|
+
*/
|
|
5880
|
+
readonly unitQualified: boolean;
|
|
5158
5881
|
}
|
|
5882
|
+
/**
|
|
5883
|
+
* Why a code carrying several candidate LOINCs stayed `ambiguous` after the unit
|
|
5884
|
+
* comparison ran, or why the comparison could not run at all.
|
|
5885
|
+
*
|
|
5886
|
+
* - `no-reported-units`: the record reported no usable units (absent, empty or whitespace only), so
|
|
5887
|
+
* nothing could be compared. A unit-qualified candidate is never chosen in this case.
|
|
5888
|
+
* - `no-candidate-matched-units`: units were reported and **no** unit-qualified candidate's
|
|
5889
|
+
* representative unit was exactly equal to them.
|
|
5890
|
+
* - `multiple-candidates-matched-units`: units were reported and **more than one distinct** candidate
|
|
5891
|
+
* LOINC matched them exactly. Picking one would be a guess.
|
|
5892
|
+
*
|
|
5893
|
+
* Every one of them surfaces every candidate and chooses no LOINC.
|
|
5894
|
+
*/
|
|
5895
|
+
type LivdAmbiguityReason = "no-reported-units" | "no-candidate-matched-units" | "multiple-candidates-matched-units";
|
|
5159
5896
|
/**
|
|
5160
5897
|
* The outcome of looking a vendor code up in a {@link LivdCatalog}. A distinct
|
|
5161
5898
|
* value per safe disposition: a hit is `mapped`; a miss is `unmapped`; a code that
|
|
5162
|
-
* matched more than one **distinct** LOINC
|
|
5163
|
-
* surfaced but **none chosen**. There is
|
|
5899
|
+
* matched more than one **distinct** LOINC and that the reported units did not
|
|
5900
|
+
* settle is `ambiguous` with the candidates surfaced but **none chosen**. There is
|
|
5901
|
+
* deliberately no "guessed" case.
|
|
5902
|
+
*
|
|
5903
|
+
* **The added fields are all optional, and a catalog carrying none of the three LIVD
|
|
5904
|
+
* attributes answers byte-identically to how it answered before they existed.** They
|
|
5905
|
+
* appear only where the consumer's own catalog rows supply something to put in them.
|
|
5164
5906
|
*/
|
|
5165
5907
|
type LivdLookup =
|
|
5166
|
-
/**
|
|
5908
|
+
/**
|
|
5909
|
+
* Exactly one LOINC: one entry, several entries that all agree on the same LOINC, or several
|
|
5910
|
+
* candidates of which exactly one had a representative unit equal to the units the record
|
|
5911
|
+
* reported (and then, and only then, `unitComparison` says how that comparison was made).
|
|
5912
|
+
*/
|
|
5167
5913
|
{
|
|
5168
5914
|
readonly status: "mapped";
|
|
5169
5915
|
readonly loinc: string;
|
|
5170
5916
|
readonly loincLongName?: string;
|
|
5917
|
+
/** The chosen row's Vendor Specimen Description, verbatim, when supplied. Never matched on. */
|
|
5918
|
+
readonly vendorSpecimenDescription?: string;
|
|
5919
|
+
/** The chosen row's Vendor Result Description, verbatim, when supplied. Never matched on. */
|
|
5920
|
+
readonly vendorResultDescription?: string;
|
|
5921
|
+
/**
|
|
5922
|
+
* The chosen row's representative unit, verbatim, when supplied.
|
|
5923
|
+
*
|
|
5924
|
+
* **This is provenance about the CATALOG ROW, not a restatement of what the record
|
|
5925
|
+
* reported.** Where a vendor code carried a single candidate LOINC across several rows
|
|
5926
|
+
* that spell the unit differently, the answer takes the FIRST row's attributes (exactly
|
|
5927
|
+
* as it has always taken the first row's `loincLongName`), so this can name a unit the
|
|
5928
|
+
* record did not report. Only {@link LivdUnitComparison} asserts the two were equal, and
|
|
5929
|
+
* it is present only where a unit actually chose between candidates.
|
|
5930
|
+
*/
|
|
5931
|
+
readonly representativeUnit?: string;
|
|
5932
|
+
/**
|
|
5933
|
+
* Present **if and only if** a unit comparison chose this LOINC from more than one candidate.
|
|
5934
|
+
* Absent where the code carried a single candidate LOINC, which is answered whether or not the
|
|
5935
|
+
* units agree: nothing was selected on a unit there, so claiming it was would be false.
|
|
5936
|
+
*/
|
|
5937
|
+
readonly unitComparison?: LivdUnitComparison;
|
|
5171
5938
|
}
|
|
5172
5939
|
/** No entry for this code: a miss. The code stays verbatim; no LOINC is invented. */
|
|
5173
5940
|
| {
|
|
5174
5941
|
readonly status: "unmapped";
|
|
5175
5942
|
}
|
|
5176
|
-
/** More than one distinct LOINC: surfaced for inspection, never resolved to one. */
|
|
5943
|
+
/** More than one distinct LOINC, unsettled: surfaced for inspection, never resolved to one. */
|
|
5177
5944
|
| {
|
|
5178
5945
|
readonly status: "ambiguous";
|
|
5946
|
+
/** Every distinct candidate LOINC, deduplicated, in first-seen catalog order. */
|
|
5179
5947
|
readonly candidates: readonly string[];
|
|
5948
|
+
/**
|
|
5949
|
+
* Every candidate row with its LIVD attributes, one per catalog row (so a LOINC held by two
|
|
5950
|
+
* rows appears twice), including rows that are not unit qualified. Present only where at least
|
|
5951
|
+
* one row for this vendor code carries one of the three LIVD attributes.
|
|
5952
|
+
*/
|
|
5953
|
+
readonly candidateDetails?: readonly LivdCandidate[];
|
|
5954
|
+
/**
|
|
5955
|
+
* Why the unit comparison did not settle it. Present under the same condition as
|
|
5956
|
+
* `candidateDetails`: a catalog carrying none of the LIVD attributes answers exactly as it did
|
|
5957
|
+
* before this field existed.
|
|
5958
|
+
*/
|
|
5959
|
+
readonly reason?: LivdAmbiguityReason;
|
|
5180
5960
|
};
|
|
5961
|
+
/**
|
|
5962
|
+
* The publication-level metadata a consumer declares about the LIVD publication
|
|
5963
|
+
* their catalog was built from: what the mapping guide defines about the publication
|
|
5964
|
+
* rather than about any one row.
|
|
5965
|
+
*
|
|
5966
|
+
* Every field is **optional** and every declared value is preserved **verbatim**:
|
|
5967
|
+
* nothing is trimmed, case folded, reordered, reformatted, defaulted or validated,
|
|
5968
|
+
* and no value is ever rejected, corrected or warned about on account of its content
|
|
5969
|
+
* or its shape. A value that is absent, empty or whitespace only is one case, **no
|
|
5970
|
+
* value declared**, which is the only inspection any of these strings gets.
|
|
5971
|
+
*
|
|
5972
|
+
* **None of it is checked, and none of it is a claim by this package.** This library
|
|
5973
|
+
* is not the LOINC licensee and performs no LOINC validation of any kind, so it
|
|
5974
|
+
* cannot tell a real LOINC version from a typed one and does not try.
|
|
5975
|
+
*
|
|
5976
|
+
* @example
|
|
5977
|
+
* ```ts
|
|
5978
|
+
* import type { LivdPublication } from "@cosyte/astm";
|
|
5979
|
+
* const p: LivdPublication = { publisher: "Example Diagnostics", loincVersion: "2.78" };
|
|
5980
|
+
* ```
|
|
5981
|
+
*/
|
|
5982
|
+
interface LivdPublication {
|
|
5983
|
+
/** The **Publisher**: the entity publishing the mapping information. Verbatim, never checked. */
|
|
5984
|
+
readonly publisher?: string;
|
|
5985
|
+
/**
|
|
5986
|
+
* The **Publication Version ID**: human-readable information the vendor provides that tells one
|
|
5987
|
+
* LIVD publication version from another. Verbatim, never parsed and never ordered against another.
|
|
5988
|
+
*/
|
|
5989
|
+
readonly publicationVersion?: string;
|
|
5990
|
+
/**
|
|
5991
|
+
* The **LOINC Version ID**: the version of LOINC the mapping was made against. Carried verbatim
|
|
5992
|
+
* onto every annotation this catalog produces ({@link LivdAnnotation.catalogLoincVersion}), so a
|
|
5993
|
+
* mapping can be reproduced later. It is **provenance the consumer declared**, never a statement
|
|
5994
|
+
* that any LOINC was checked against it: nothing here validates a LOINC or a LOINC version.
|
|
5995
|
+
*
|
|
5996
|
+
* Declaring none is allowed and surfaces a value-free warning on {@link LivdCatalog.warnings};
|
|
5997
|
+
* the catalog is still built and every answer is unchanged.
|
|
5998
|
+
*/
|
|
5999
|
+
readonly loincVersion?: string;
|
|
6000
|
+
/**
|
|
6001
|
+
* The **LOINCCopyright**: the attribution statement the LOINC license requires beside content
|
|
6002
|
+
* that carries LOINC codes. Stored verbatim so it travels with the mapping it applies to.
|
|
6003
|
+
*
|
|
6004
|
+
* **Carrying it is not discharging it.** The obligation is the consumer's, this package supplies
|
|
6005
|
+
* no statement on anyone's behalf, and it checks neither the presence nor the wording of one.
|
|
6006
|
+
*/
|
|
6007
|
+
readonly loincCopyright?: string;
|
|
6008
|
+
}
|
|
5181
6009
|
/**
|
|
5182
6010
|
* An immutable, consumer-supplied LIVD catalog. Look a vendor code up with
|
|
5183
6011
|
* {@link LivdCatalog.lookup}; the catalog **never** picks between conflicting
|
|
@@ -5186,15 +6014,45 @@ type LivdLookup =
|
|
|
5186
6014
|
interface LivdCatalog {
|
|
5187
6015
|
/** The number of distinct vendor codes indexed (not the number of input rows). */
|
|
5188
6016
|
readonly size: number;
|
|
6017
|
+
/**
|
|
6018
|
+
* The publication-level metadata the consumer declared, each value **verbatim**. Absent where
|
|
6019
|
+
* the catalog declared none, and each field inside it absent where that value was not declared:
|
|
6020
|
+
* a blank is never stored as a blank, and nothing is ever defaulted.
|
|
6021
|
+
*
|
|
6022
|
+
* Optional on the interface, so a catalog a consumer implements by hand needs no metadata and
|
|
6023
|
+
* stays source compatible.
|
|
6024
|
+
*/
|
|
6025
|
+
readonly publication?: LivdPublication;
|
|
6026
|
+
/**
|
|
6027
|
+
* The value-free warnings raised where this catalog was **defined**, in the order they were
|
|
6028
|
+
* raised. {@link defineLivdCatalog} always sets it, empty where it had nothing to say.
|
|
6029
|
+
*
|
|
6030
|
+
* These are facts about the CATALOG, so they never join the per-record warning stream
|
|
6031
|
+
* {@link applyLivd} returns and they implicate no record. Optional on the interface, so a
|
|
6032
|
+
* hand-implemented catalog that offers none stays source compatible.
|
|
6033
|
+
*/
|
|
6034
|
+
readonly warnings?: readonly AstmLivdCatalogWarning[];
|
|
5189
6035
|
/**
|
|
5190
6036
|
* Look a vendor code up, verbatim (exact, case-sensitive). Returns `mapped` on a
|
|
5191
6037
|
* single-LOINC hit, `unmapped` on a miss, and `ambiguous` when the code carries
|
|
5192
|
-
* more than one distinct LOINC: never a
|
|
6038
|
+
* more than one distinct LOINC that the reported units did not settle: never a
|
|
6039
|
+
* guess.
|
|
6040
|
+
*
|
|
6041
|
+
* `reportedUnits` are the units the `R` record carried, verbatim. They are compared
|
|
6042
|
+
* with each candidate's {@link LivdEntry.representativeUnit} by exact,
|
|
6043
|
+
* case-sensitive string equality and by nothing else. Omitting them, or passing an
|
|
6044
|
+
* empty or whitespace-only string, means **no units were reported**: no
|
|
6045
|
+
* unit-qualified candidate is chosen and a code carrying several candidates stays
|
|
6046
|
+
* `ambiguous`. A code carrying exactly one candidate LOINC is answered either way.
|
|
6047
|
+
*
|
|
6048
|
+
* Implementing this interface by hand stays source compatible: a `lookup` declared
|
|
6049
|
+
* with the vendor code alone simply ignores the units, and answers as it always did.
|
|
5193
6050
|
*
|
|
5194
6051
|
* @param vendorCode - The reported vendor/local test code.
|
|
6052
|
+
* @param reportedUnits - The units the record reported, verbatim, when it reported any.
|
|
5195
6053
|
* @returns The lookup outcome.
|
|
5196
6054
|
*/
|
|
5197
|
-
lookup(vendorCode: string): LivdLookup;
|
|
6055
|
+
lookup(vendorCode: string, reportedUnits?: string): LivdLookup;
|
|
5198
6056
|
}
|
|
5199
6057
|
/**
|
|
5200
6058
|
* Build a {@link LivdCatalog} from LIVD entries a consumer supplies. Entries are
|
|
@@ -5202,13 +6060,26 @@ interface LivdCatalog {
|
|
|
5202
6060
|
* code:
|
|
5203
6061
|
*
|
|
5204
6062
|
* - all agreeing on the same `loinc` → a single `mapped` result (the first entry's
|
|
5205
|
-
* optional `loincLongName`
|
|
5206
|
-
*
|
|
5207
|
-
*
|
|
6063
|
+
* optional `loincLongName` and LIVD attributes are kept), whether or not the
|
|
6064
|
+
* reported units equal that entry's representative unit;
|
|
6065
|
+
* - disagreeing (two distinct LOINCs) → the reported units decide, by exact
|
|
6066
|
+
* case-sensitive equality against each row's
|
|
6067
|
+
* {@link LivdEntry.representativeUnit}. Exactly one distinct LOINC matching is
|
|
6068
|
+
* `mapped`, and the answer states that the comparison was verbatim. None matching,
|
|
6069
|
+
* more than one matching, or no units reported is an `ambiguous` result carrying
|
|
6070
|
+
* every distinct candidate and **no** choice between them.
|
|
6071
|
+
*
|
|
6072
|
+
* Publication-level metadata is supplied beside the rows, and every element of it is
|
|
6073
|
+
* optional, so the single-argument call keeps working exactly as it did. Each declared
|
|
6074
|
+
* value is preserved verbatim and readable back off {@link LivdCatalog.publication};
|
|
6075
|
+
* none of it is validated. Declaring no LOINC version is allowed and puts a value-free
|
|
6076
|
+
* {@link AstmLivdCatalogWarning} on {@link LivdCatalog.warnings}: a nudge, never a
|
|
6077
|
+
* refusal, and no lookup answers differently because of it.
|
|
5208
6078
|
*
|
|
5209
6079
|
* The returned catalog is deeply frozen; nothing is mutated after construction.
|
|
5210
6080
|
*
|
|
5211
6081
|
* @param entries - The consumer's LIVD mapping rows.
|
|
6082
|
+
* @param publication - The consumer's publication-level metadata, when they declare any.
|
|
5212
6083
|
* @returns An immutable catalog.
|
|
5213
6084
|
* @example
|
|
5214
6085
|
* ```ts
|
|
@@ -5220,108 +6091,20 @@ interface LivdCatalog {
|
|
|
5220
6091
|
* catalog.lookup("687"); // { status: "mapped", loinc: "1920-8", loincLongName: "AST" }
|
|
5221
6092
|
* catalog.lookup("999"); // { status: "unmapped" }
|
|
5222
6093
|
* ```
|
|
5223
|
-
*/
|
|
5224
|
-
declare function defineLivdCatalog(entries: readonly LivdEntry[]): LivdCatalog;
|
|
5225
|
-
|
|
5226
|
-
/**
|
|
5227
|
-
* The **terminology** warning registry (`ASTM_LIVD_*`) for the LIVD-aware LOINC
|
|
5228
|
-
* recognition layer: the fourth of the package's registries,
|
|
5229
|
-
* alongside the record layer's `ASTM_RECORD_*`, the frame codec's `ASTM_FRAME_*`,
|
|
5230
|
-
* and the protocol reducer's `ASTM_LTP_*`.
|
|
5231
|
-
*
|
|
5232
|
-
* A terminology warning is the record of a **safe non-mapping**: a reported
|
|
5233
|
-
* vendor test code that a consumer-supplied LIVD catalog did not map to a single
|
|
5234
|
-
* LOINC. It never carries a LOINC the catalog did not vouch for: the whole point
|
|
5235
|
-
* of the layer is that an unmapped or ambiguous code is surfaced as *unmapped*,
|
|
5236
|
-
* **never a guessed LOINC** (mis-identifying a test is safety-critical). Every
|
|
5237
|
-
* warning carries a stable code plus positional context ({@link AstmPosition}) and
|
|
5238
|
-
* **never** a field value. Consumers compare `warning.code ===
|
|
5239
|
-
* LIVD_WARNING_CODES.<CODE>`; renaming a code is a **breaking change**.
|
|
5240
|
-
*
|
|
5241
|
-
* These codes live in their own registry and are deliberately **not** part of the
|
|
5242
|
-
* profile safety gate's universe (`ALL_ASTM_WARNING_CODES`): a LIVD non-mapping is
|
|
5243
|
-
* a post-parse advisory produced by the opt-in {@link applyLivd} helper, not a
|
|
5244
|
-
* parse-time deviation a vendor profile could ever "tolerate". A profile referencing
|
|
5245
|
-
* one is rejected as an unknown code: correctly, since there is nothing here to
|
|
5246
|
-
* quiet.
|
|
5247
|
-
*/
|
|
5248
|
-
|
|
5249
|
-
/**
|
|
5250
|
-
* Stable string codes for every terminology (LIVD) warning. `key === value` so
|
|
5251
|
-
* `Object.values(...)` yields a stable snapshot set.
|
|
5252
|
-
*
|
|
5253
|
-
* @example
|
|
5254
|
-
* ```ts
|
|
5255
|
-
* import { LIVD_WARNING_CODES } from "@cosyte/astm";
|
|
5256
|
-
* LIVD_WARNING_CODES.ASTM_LIVD_UNMAPPED_CODE; // "ASTM_LIVD_UNMAPPED_CODE"
|
|
5257
|
-
* ```
|
|
5258
|
-
*/
|
|
5259
|
-
declare const LIVD_WARNING_CODES: {
|
|
5260
|
-
/**
|
|
5261
|
-
* A record carried a vendor/local test code, but the consumer-supplied LIVD catalog held **no**
|
|
5262
|
-
* entry for it. The code stays surfaced verbatim and the mapping is `unmapped`: a LOINC is
|
|
5263
|
-
* **never** guessed. Purely advisory: the raw code and value are untouched.
|
|
5264
|
-
*/
|
|
5265
|
-
readonly ASTM_LIVD_UNMAPPED_CODE: "ASTM_LIVD_UNMAPPED_CODE";
|
|
5266
|
-
/**
|
|
5267
|
-
* A vendor/local test code matched **more than one distinct LOINC** in the catalog (e.g. the same
|
|
5268
|
-
* transmission code used by two devices for different analytes). The mapping is `ambiguous` and the
|
|
5269
|
-
* candidate LOINCs are surfaced for inspection, but **none is chosen**: refusing to pick is the
|
|
5270
|
-
* fail-safe, since guessing wrong mis-identifies the test.
|
|
5271
|
-
*/
|
|
5272
|
-
readonly ASTM_LIVD_AMBIGUOUS_MAPPING: "ASTM_LIVD_AMBIGUOUS_MAPPING";
|
|
5273
|
-
};
|
|
5274
|
-
/**
|
|
5275
|
-
* Discriminant type for {@link AstmLivdWarning.code}. Narrowing by this code lets
|
|
5276
|
-
* consumers write exhaustive `switch` blocks against {@link LIVD_WARNING_CODES}.
|
|
5277
|
-
*/
|
|
5278
|
-
type LivdWarningCode = (typeof LIVD_WARNING_CODES)[keyof typeof LIVD_WARNING_CODES];
|
|
5279
|
-
/**
|
|
5280
|
-
* A single terminology (LIVD) warning: a stable code, a value-free human-readable
|
|
5281
|
-
* message, and positional context. Never carries a test code, a value, or a LOINC.
|
|
5282
|
-
*
|
|
5283
6094
|
* @example
|
|
5284
6095
|
* ```ts
|
|
5285
|
-
* import
|
|
5286
|
-
*
|
|
5287
|
-
*
|
|
5288
|
-
*
|
|
5289
|
-
*
|
|
5290
|
-
*
|
|
5291
|
-
*
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
readonly code: LivdWarningCode;
|
|
5295
|
-
/** Human-readable detail for logs. Never contains a test code, a value, or a LOINC. */
|
|
5296
|
-
readonly message: string;
|
|
5297
|
-
readonly position: AstmPosition;
|
|
5298
|
-
}
|
|
5299
|
-
/**
|
|
5300
|
-
* Build an `ASTM_LIVD_UNMAPPED_CODE` warning. The reported code stays verbatim and
|
|
5301
|
-
* the mapping is `unmapped`; no LOINC is fabricated.
|
|
5302
|
-
*
|
|
5303
|
-
* @param position - Where the unmapped code was seen (record ordinal + type; never the code).
|
|
5304
|
-
* @returns The warning.
|
|
5305
|
-
* @example
|
|
5306
|
-
* ```ts
|
|
5307
|
-
* import { livdUnmappedCode } from "@cosyte/astm";
|
|
5308
|
-
* livdUnmappedCode({ recordIndex: 3, recordType: "R" });
|
|
5309
|
-
* ```
|
|
5310
|
-
*/
|
|
5311
|
-
declare function livdUnmappedCode(position: AstmPosition): AstmLivdWarning;
|
|
5312
|
-
/**
|
|
5313
|
-
* Build an `ASTM_LIVD_AMBIGUOUS_MAPPING` warning. The code matched multiple distinct
|
|
5314
|
-
* LOINCs; none is chosen (refusing to pick is the fail-safe).
|
|
5315
|
-
*
|
|
5316
|
-
* @param position - Where the ambiguous code was seen (record ordinal + type; never the code).
|
|
5317
|
-
* @returns The warning.
|
|
5318
|
-
* @example
|
|
5319
|
-
* ```ts
|
|
5320
|
-
* import { livdAmbiguousMapping } from "@cosyte/astm";
|
|
5321
|
-
* livdAmbiguousMapping({ recordIndex: 4, recordType: "O" });
|
|
6096
|
+
* import { defineLivdCatalog } from "@cosyte/astm";
|
|
6097
|
+
* // One vendor analyte code, two LOINCs, told apart by their representative unit.
|
|
6098
|
+
* const glucose = defineLivdCatalog([
|
|
6099
|
+
* { vendorCode: "GLU", loinc: "2345-7", representativeUnit: "mg/dL" },
|
|
6100
|
+
* { vendorCode: "GLU", loinc: "15074-8", representativeUnit: "mmol/L" },
|
|
6101
|
+
* ]);
|
|
6102
|
+
* glucose.lookup("GLU", "mmol/L").status; // "mapped": 15074-8, on a verbatim unit match
|
|
6103
|
+
* glucose.lookup("GLU", "MMOL/L").status; // "ambiguous": the comparison is case sensitive
|
|
6104
|
+
* glucose.lookup("GLU").status; // "ambiguous": no units reported, so nothing to compare
|
|
5322
6105
|
* ```
|
|
5323
6106
|
*/
|
|
5324
|
-
declare function
|
|
6107
|
+
declare function defineLivdCatalog(entries: readonly LivdEntry[], publication?: LivdPublication): LivdCatalog;
|
|
5325
6108
|
|
|
5326
6109
|
/**
|
|
5327
6110
|
* The **additive, advisory** LIVD annotation layer. {@link applyLivd}
|
|
@@ -5331,24 +6114,52 @@ declare function livdAmbiguousMapping(position: AstmPosition): AstmLivdWarning;
|
|
|
5331
6114
|
* annotation, not a rewrite: the wire stays exactly as parsed.
|
|
5332
6115
|
*
|
|
5333
6116
|
* **The never-fabricate rule (the safety-critical point).** A vendor code with no
|
|
5334
|
-
* single LIVD mapping surfaces as a typed `unmapped`/`ambiguous`/`no-code
|
|
5335
|
-
* annotation: **never** a guessed LOINC. A wrong LOINC mis-identifies a
|
|
5336
|
-
* the layer
|
|
5337
|
-
*
|
|
5338
|
-
*
|
|
6117
|
+
* single LIVD mapping surfaces as a typed `unmapped`/`ambiguous`/`no-vendor-code`/
|
|
6118
|
+
* `no-code` annotation: **never** a guessed LOINC. A wrong LOINC mis-identifies a
|
|
6119
|
+
* test, so the only LOINC this layer ever reports is one the consumer's catalog
|
|
6120
|
+
* vouched for (labeled `derived`), and otherwise it reports nothing but the miss.
|
|
6121
|
+
*
|
|
6122
|
+
* **The wire never answers the analyte-identity question.** The catalog is
|
|
6123
|
+
* consulted whenever a vendor/local code is present, and it is consulted with that
|
|
6124
|
+
* code alone. A populated component 1 rides along verbatim as
|
|
6125
|
+
* {@link LivdAnnotation.unvalidatedWireValue}, is never validated, and is never
|
|
6126
|
+
* reported as a LOINC. Where it differs from what the catalog vouched for, the
|
|
6127
|
+
* difference is reported as its own fact
|
|
6128
|
+
* ({@link LivdAnnotation.wireValueDisagreesWithCatalog}) and is **never resolved**:
|
|
6129
|
+
* both values are surfaced, and nothing here picks between them.
|
|
6130
|
+
*
|
|
6131
|
+
* **The units DO answer, and only for choosing between the catalog's own
|
|
6132
|
+
* candidates.** One vendor analyte code legitimately maps to several LOINCs that
|
|
6133
|
+
* differ by reporting unit, so the catalog is consulted with the vendor code AND with
|
|
6134
|
+
* the units field 5 of the `R` record carried, verbatim. That comparison is exact and
|
|
6135
|
+
* case sensitive, never a UCUM semantic comparison, and a unit-selected answer says
|
|
6136
|
+
* so on its output. It only ever narrows the candidate list the consumer's own
|
|
6137
|
+
* catalog produced: it can never introduce a LOINC, never overrides the catalog, and
|
|
6138
|
+
* a record with no readable units simply leaves the ambiguity standing.
|
|
6139
|
+
*
|
|
6140
|
+
* **The catalog's declared LOINC version rides on every annotation.** Where the
|
|
6141
|
+
* consumer declared one, {@link LivdAnnotation.catalogLoincVersion} carries it
|
|
6142
|
+
* verbatim on every annotation that catalog produced, whatever the outcome of the
|
|
6143
|
+
* lookup, so a mapping says which version of LOINC it was made against and can be
|
|
6144
|
+
* reproduced. It is provenance the CONSUMER declared and nothing else: no LOINC is
|
|
6145
|
+
* validated against it, or against anything, here or anywhere in this package.
|
|
5339
6146
|
*/
|
|
5340
6147
|
|
|
5341
6148
|
/**
|
|
5342
|
-
* The outcome of
|
|
5343
|
-
*
|
|
6149
|
+
* The outcome of looking one record's Universal Test ID up in a LIVD catalog: a
|
|
6150
|
+
* closed, mutually exclusive discriminant. There is no case in which a LOINC is
|
|
6151
|
+
* guessed, and no case in which a value the wire carried is reported as a LOINC.
|
|
5344
6152
|
*
|
|
5345
6153
|
* - `mapped`, the vendor/local code resolved to a single LOINC **via the catalog**
|
|
5346
6154
|
* (labeled `derived: true`, `source: "livd"`).
|
|
5347
|
-
* - `
|
|
5348
|
-
* (
|
|
5349
|
-
*
|
|
6155
|
+
* - `unmapped`: a vendor/local code was looked up and the catalog held no entry
|
|
6156
|
+
* for it (a hit whose LOINC is a zero-length string is reported here too: an
|
|
6157
|
+
* empty LOINC is not an answer).
|
|
5350
6158
|
* - `ambiguous`: a vendor/local code matching more than one distinct LOINC; the
|
|
5351
6159
|
* candidates are surfaced but **none is chosen**.
|
|
6160
|
+
* - `no-vendor-code`: component 1 is populated and there is no vendor/local code,
|
|
6161
|
+
* so nothing was looked up. The wire value is surfaced unvalidated, and is never
|
|
6162
|
+
* used as a lookup key: the catalog is keyed on the vendor transmission code.
|
|
5352
6163
|
* - `no-code`: the record carried no usable test code at all (name-only/empty), so
|
|
5353
6164
|
* there was nothing to map.
|
|
5354
6165
|
*/
|
|
@@ -5356,24 +6167,38 @@ type LivdMapping = {
|
|
|
5356
6167
|
readonly status: "mapped";
|
|
5357
6168
|
readonly loinc: string;
|
|
5358
6169
|
readonly loincLongName?: string;
|
|
6170
|
+
/** The chosen catalog row's Vendor Specimen Description, verbatim, when supplied. */
|
|
6171
|
+
readonly vendorSpecimenDescription?: string;
|
|
6172
|
+
/** The chosen catalog row's Vendor Result Description, verbatim, when supplied. */
|
|
6173
|
+
readonly vendorResultDescription?: string;
|
|
6174
|
+
/** The chosen catalog row's representative unit, verbatim, when supplied. */
|
|
6175
|
+
readonly representativeUnit?: string;
|
|
6176
|
+
/**
|
|
6177
|
+
* Present **if and only if** the record's units chose this LOINC from more than one candidate,
|
|
6178
|
+
* and it states what that comparison was: verbatim and case sensitive, not UCUM semantic.
|
|
6179
|
+
*/
|
|
6180
|
+
readonly unitComparison?: LivdUnitComparison;
|
|
5359
6181
|
readonly source: "livd";
|
|
5360
6182
|
readonly derived: true;
|
|
5361
|
-
} | {
|
|
5362
|
-
readonly status: "inline-loinc";
|
|
5363
|
-
readonly loinc: string;
|
|
5364
|
-
readonly source: "wire";
|
|
5365
6183
|
} | {
|
|
5366
6184
|
readonly status: "unmapped";
|
|
5367
6185
|
} | {
|
|
5368
6186
|
readonly status: "ambiguous";
|
|
5369
6187
|
readonly candidates: readonly string[];
|
|
6188
|
+
/** Every candidate row with its LIVD attributes, when the catalog supplied any. */
|
|
6189
|
+
readonly candidateDetails?: readonly LivdCandidate[];
|
|
6190
|
+
/** Why the units did not settle it, when the catalog supplied the attributes to say. */
|
|
6191
|
+
readonly reason?: LivdAmbiguityReason;
|
|
6192
|
+
} | {
|
|
6193
|
+
readonly status: "no-vendor-code";
|
|
5370
6194
|
} | {
|
|
5371
6195
|
readonly status: "no-code";
|
|
5372
6196
|
};
|
|
5373
6197
|
/**
|
|
5374
|
-
* One record's LIVD annotation
|
|
5375
|
-
* (verbatim), how it was recognized,
|
|
5376
|
-
*
|
|
6198
|
+
* One record's LIVD annotation: which record, the code the catalog was consulted
|
|
6199
|
+
* with (verbatim), how it was recognized, the lookup outcome, and the two facts
|
|
6200
|
+
* about a populated component 1 that ride alongside **any** outcome. Additive: it
|
|
6201
|
+
* points at the record by index and never replaces it.
|
|
5377
6202
|
*
|
|
5378
6203
|
* @example
|
|
5379
6204
|
* ```ts
|
|
@@ -5382,6 +6207,8 @@ type LivdMapping = {
|
|
|
5382
6207
|
* recordIndex: 3,
|
|
5383
6208
|
* recordType: "R",
|
|
5384
6209
|
* reportedCode: "687",
|
|
6210
|
+
* unvalidatedWireValue: "Glucose",
|
|
6211
|
+
* wireValueDisagreesWithCatalog: true,
|
|
5385
6212
|
* provenance: "local-code",
|
|
5386
6213
|
* mapping: { status: "mapped", loinc: "1920-8", source: "livd", derived: true },
|
|
5387
6214
|
* };
|
|
@@ -5392,12 +6219,47 @@ interface LivdAnnotation {
|
|
|
5392
6219
|
readonly recordIndex: number;
|
|
5393
6220
|
/** The annotated record's type. */
|
|
5394
6221
|
readonly recordType: "R" | "O";
|
|
5395
|
-
/**
|
|
6222
|
+
/**
|
|
6223
|
+
* The vendor/local code the catalog was consulted with, verbatim. Absent when no
|
|
6224
|
+
* vendor/local code was present, because then nothing was looked up. It is never
|
|
6225
|
+
* a component 1 value.
|
|
6226
|
+
*/
|
|
5396
6227
|
readonly reportedCode?: string;
|
|
5397
|
-
/**
|
|
6228
|
+
/**
|
|
6229
|
+
* Component 1 when populated, verbatim: a wire value this library **does not
|
|
6230
|
+
* vouch for**, carried on every outcome and never validated, never promoted to a
|
|
6231
|
+
* LOINC, and never used as a lookup key. Absent when component 1 is empty.
|
|
6232
|
+
*/
|
|
6233
|
+
readonly unvalidatedWireValue?: string;
|
|
6234
|
+
/**
|
|
6235
|
+
* `true` if and only if the catalog vouched for exactly one LOINC for the
|
|
6236
|
+
* vendor/local code, component 1 is populated, and that value is not
|
|
6237
|
+
* byte-identical to that LOINC. `false` in **every** other case, including where
|
|
6238
|
+
* the catalog vouched for no single LOINC (a miss, an ambiguity, no vendor code,
|
|
6239
|
+
* no code at all): asserting a disagreement there would claim the catalog spoke
|
|
6240
|
+
* about a code it never spoke about.
|
|
6241
|
+
*
|
|
6242
|
+
* It reports the difference and **nothing else**. Neither value is marked
|
|
6243
|
+
* correct, neither is suppressed, and no field says the difference was settled.
|
|
6244
|
+
*/
|
|
6245
|
+
readonly wireValueDisagreesWithCatalog: boolean;
|
|
6246
|
+
/** How the identifier was recognized in the Universal Test ID (provenance only, never a lookup). */
|
|
5398
6247
|
readonly provenance: UniversalTestIdProvenance;
|
|
5399
|
-
/** The
|
|
6248
|
+
/** The lookup outcome: never a guessed LOINC. */
|
|
5400
6249
|
readonly mapping: LivdMapping;
|
|
6250
|
+
/**
|
|
6251
|
+
* The **LOINC version the catalog declared**, verbatim, carried on **every** annotation that
|
|
6252
|
+
* catalog produced, whatever the outcome of the lookup. It is what makes a mapping reproducible:
|
|
6253
|
+
* the reader can see which version of LOINC the consumer's catalog says it was built against.
|
|
6254
|
+
*
|
|
6255
|
+
* **It asserts nothing about this LOINC.** It is provenance about the CATALOG, not a claim that
|
|
6256
|
+
* any LOINC was checked, found, or validated against that version: this package performs no
|
|
6257
|
+
* LOINC validation of any kind, and nothing here reads the string beyond carrying it.
|
|
6258
|
+
*
|
|
6259
|
+
* Absent when the catalog declared no LOINC version (including a catalog a consumer implemented
|
|
6260
|
+
* by hand, which declares none), never a default, a placeholder or an empty string.
|
|
6261
|
+
*/
|
|
6262
|
+
readonly catalogLoincVersion?: string;
|
|
5401
6263
|
}
|
|
5402
6264
|
/**
|
|
5403
6265
|
* The result of {@link applyLivd}: the per-record annotations (one per `R`/`O`
|
|
@@ -5407,7 +6269,15 @@ interface LivdAnnotation {
|
|
|
5407
6269
|
interface LivdResult {
|
|
5408
6270
|
/** One annotation per `R`/`O` record, in wire order. */
|
|
5409
6271
|
readonly annotations: readonly LivdAnnotation[];
|
|
5410
|
-
/**
|
|
6272
|
+
/**
|
|
6273
|
+
* A value-free warning per `unmapped`/`ambiguous` code: never per `mapped`, and
|
|
6274
|
+
* never per `no-vendor-code`/`no-code`, where no lookup happened at all.
|
|
6275
|
+
*
|
|
6276
|
+
* Per-record only. A warning about the CATALOG, such as one declaring no LOINC
|
|
6277
|
+
* version, is raised where the catalog is defined and stays on
|
|
6278
|
+
* {@link LivdCatalog.warnings}: it implicates no record, so it never joins this
|
|
6279
|
+
* stream and never changes its codes, its order or its length.
|
|
6280
|
+
*/
|
|
5411
6281
|
readonly warnings: readonly AstmLivdWarning[];
|
|
5412
6282
|
}
|
|
5413
6283
|
/**
|
|
@@ -5435,9 +6305,14 @@ declare function lookupLivdForRecord(record: ResultRecord | OrderRecord, catalog
|
|
|
5435
6305
|
*
|
|
5436
6306
|
* Fail-safe: with no matching entry a code is `unmapped` (+ an
|
|
5437
6307
|
* `ASTM_LIVD_UNMAPPED_CODE` warning); with a conflicting mapping it is `ambiguous`
|
|
5438
|
-
* (+ an `ASTM_LIVD_AMBIGUOUS_MAPPING` warning); a LOINC is **never** guessed.
|
|
5439
|
-
*
|
|
5440
|
-
*
|
|
6308
|
+
* (+ an `ASTM_LIVD_AMBIGUOUS_MAPPING` warning); a LOINC is **never** guessed. A
|
|
6309
|
+
* populated component 1 never short-circuits the lookup and is never reported as a
|
|
6310
|
+
* LOINC: it is carried verbatim as an unvalidated wire value, and where it differs
|
|
6311
|
+
* from the catalog's answer the difference is reported and left unresolved.
|
|
6312
|
+
*
|
|
6313
|
+
* A catalog is code a consumer supplies, so a lookup that throws propagates to the
|
|
6314
|
+
* caller unchanged: a consumer's own failure is never reported as a catalog miss,
|
|
6315
|
+
* and no partially annotated result is returned.
|
|
5441
6316
|
*
|
|
5442
6317
|
* @param msg - A parsed ASTM message.
|
|
5443
6318
|
* @param catalog - The consumer-supplied LIVD catalog (build with {@link defineLivdCatalog}).
|
|
@@ -5445,10 +6320,12 @@ declare function lookupLivdForRecord(record: ResultRecord | OrderRecord, catalog
|
|
|
5445
6320
|
* @example
|
|
5446
6321
|
* ```ts
|
|
5447
6322
|
* import { parseAstmRecords, defineLivdCatalog, applyLivd } from "@cosyte/astm";
|
|
5448
|
-
* const msg = parseAstmRecords("H|\\^&\rR|1
|
|
6323
|
+
* const msg = parseAstmRecords("H|\\^&\rR|1|Glucose^^^687|28.6|U/L||N||F\rL|1\r");
|
|
5449
6324
|
* const catalog = defineLivdCatalog([{ vendorCode: "687", loinc: "1920-8", loincLongName: "AST" }]);
|
|
5450
|
-
* const
|
|
5451
|
-
*
|
|
6325
|
+
* const [a] = applyLivd(msg, catalog).annotations;
|
|
6326
|
+
* a?.mapping; // { status: "mapped", loinc: "1920-8", loincLongName: "AST", source: "livd", derived: true }
|
|
6327
|
+
* a?.unvalidatedWireValue; // "Glucose": carried verbatim, vouched for by nothing
|
|
6328
|
+
* a?.wireValueDisagreesWithCatalog; // true: reported, never resolved
|
|
5452
6329
|
* ```
|
|
5453
6330
|
*/
|
|
5454
6331
|
declare function applyLivd(msg: AstmMessage, catalog: LivdCatalog): LivdResult;
|
|
@@ -5490,8 +6367,8 @@ interface FrameChecksum {
|
|
|
5490
6367
|
*/
|
|
5491
6368
|
interface AstmFrame {
|
|
5492
6369
|
/**
|
|
5493
|
-
* The frame's sequence number as read from the `FN` byte. Normally `0
|
|
5494
|
-
* value outside that range means the `FN` byte was not a `0
|
|
6370
|
+
* The frame's sequence number as read from the `FN` byte. Normally `0` to `7`; a
|
|
6371
|
+
* value outside that range means the `FN` byte was not a `0` to `7` digit (a
|
|
5495
6372
|
* corruption that also trips a sequence-gap warning). `undefined` when the frame
|
|
5496
6373
|
* was too truncated to carry a frame number at all.
|
|
5497
6374
|
*/
|
|
@@ -5786,7 +6663,7 @@ declare function decodeAstmFrames(bytes: Uint8Array, options?: FrameOptions): De
|
|
|
5786
6663
|
* - the **modulo-256 checksum** over `FN … terminator` (inclusive), emitted as two
|
|
5787
6664
|
* **uppercase** hex chars (the conservative-emit form the decoder accepts either
|
|
5788
6665
|
* case of);
|
|
5789
|
-
* - the **frame number** `0
|
|
6666
|
+
* - the **frame number** `0` to `7`, starting at `1` and rolling over `7 → 0 → 1`,
|
|
5790
6667
|
* continuous across every frame in the stream (as the decoder's sequence check
|
|
5791
6668
|
* expects); a caller may start the sequence elsewhere to compose one transfer
|
|
5792
6669
|
* across several calls, but only at a number a frame can actually carry;
|
|
@@ -6128,7 +7005,7 @@ declare function serializeFramedAstm(input: AstmMessage | readonly AstmRecord[],
|
|
|
6128
7005
|
* @param bytes - The full decoded byte stream.
|
|
6129
7006
|
* @param start - First index to include (the frame-number byte, one past `STX`).
|
|
6130
7007
|
* @param endInclusive - Last index to include (the `ETB`/`ETX` terminator byte).
|
|
6131
|
-
* @returns The checksum in `0
|
|
7008
|
+
* @returns The checksum in `0` to `255`.
|
|
6132
7009
|
* @example
|
|
6133
7010
|
* ```ts
|
|
6134
7011
|
* import { computeChecksum } from "@cosyte/astm";
|
|
@@ -6141,7 +7018,7 @@ declare function computeChecksum(bytes: Uint8Array, start: number, endInclusive:
|
|
|
6141
7018
|
* Format a checksum byte as the two **uppercase** hex characters ASTM puts on the
|
|
6142
7019
|
* wire (the conservative-emit form). Decode accepts lowercase; emit is uppercase.
|
|
6143
7020
|
*
|
|
6144
|
-
* @param checksum - A value in `0
|
|
7021
|
+
* @param checksum - A value in `0` to `255`.
|
|
6145
7022
|
* @returns Two uppercase hex characters, zero-padded (e.g. `"0A"`, `"75"`).
|
|
6146
7023
|
* @example
|
|
6147
7024
|
* ```ts
|
|
@@ -6159,7 +7036,7 @@ declare function toChecksumHex(checksum: number): string;
|
|
|
6159
7036
|
* @param bytes - The full decoded byte stream.
|
|
6160
7037
|
* @param i0 - Index of the high hex nibble (immediately after the terminator).
|
|
6161
7038
|
* @param i1 - Index of the low hex nibble.
|
|
6162
|
-
* @returns The declared checksum in `0
|
|
7039
|
+
* @returns The declared checksum in `0` to `255`, or `undefined` if unreadable.
|
|
6163
7040
|
* @example
|
|
6164
7041
|
* ```ts
|
|
6165
7042
|
* import { parseChecksumHex } from "@cosyte/astm";
|
|
@@ -6271,4 +7148,4 @@ declare class AstmFrameStrictError extends Error {
|
|
|
6271
7148
|
*/
|
|
6272
7149
|
declare const VERSION: string;
|
|
6273
7150
|
|
|
6274
|
-
export { ALL_ASTM_WARNING_CODES, AMBIGUOUS_CODES, ACK as ASTM_ACK, ENQ as ASTM_ENQ, EOT as ASTM_EOT, NAK as ASTM_NAK, type AbnormalFlag, type AbnormalFlagCode, type AbnormalFlagMeaning, type AmbiguousAlignmentSink, type AmbiguousCode, type AnyAstmWarningCode, AstmAmbiguousStreamError, type AstmDate, type AstmDatePrecision, type AstmField, type AstmFrame, AstmFrameEncodeError, type AstmFrameEncodeErrorCode, type AstmFramePosition, AstmFrameStrictError, type AstmFrameWarning, type AstmFraming, type AstmLivdWarning, type AstmLtpWarning, type AstmMessage, type AstmMessageClassification, type AstmMessageKind, AstmParseError, type AstmParseOptions, type AstmPosition, type AstmProfile, AstmProfileDefinitionError, type AstmProfileProvenance, type AstmQuirkMatch, type AstmQuirkTolerance, type AstmRecord, type AstmRecordInput, type AstmRecordWarning, AstmSerializeError, type AstmSerializeErrorCode, type AstmStreamMessage, AstmStrictError, CANONICAL_DELIMITERS, type CommentInput, type CommentRecord, type ComposeFramesOptions, type DecodeAstmFramesResult, type DefineAstmProfileOptions, type DelimiterDeclarationFault, type DelimiterReadResult, type Delimiters, type DetectFramingOptions, type DetectFramingResult, FATAL_CODES, FRAME_WARNING_CODES, type FatalCode, type FrameChecksum, type FrameOptions, type FrameTerminator, type FrameWarningCode, type FramedAstmResult, type HeaderInput, type HeaderRecord, LIVD_WARNING_CODES, LTP_WARNING_CODES, type LivdAnnotation, type LivdCatalog, type LivdEntry, type LivdLookup, type LivdMapping, type LivdResult, type LivdWarningCode, type LtpAction, type LtpEvent, type LtpPhase, type LtpState, type LtpTransition, type LtpWarningCode, type ManufacturerRecord, type MessageInput, type OrderInput, type OrderRecord, type PatientInput, type PatientName, type PatientNameInput, type PatientRecord, type QueryInput, type QueryRecord, type ReferenceRange, type ReferenceRangeKind, type ResultInput, type ResultRecord, type ResultStatus, type ResultStatusCode, type ResultStatusMeaning, SAFETY_CRITICAL_CODES, type ScientificRecord, type ShiftedComponentsSink, type ShiftedFieldsSink, type SwallowedDelimiterSink, TOLERABLE_CODES, type TerminatorRecord, type TruncatedFieldSink, type UniversalTestId, type UniversalTestIdProvenance, type UnknownEscapeSink, type UnpairedEscapeSink, type UnsupportedRecord, VERSION, type VerbatimInput, WARNING_CODES, type WarningCode, alignmentShiftedComponents, alignmentShiftedFields, alignmentTruncatedField, ambiguousEscapeAlignment, ambiguousMessageKind, ambiguousValueSplit, applyAstmProfile, applyAstmProfileToWarnings, applyLivd, astmDateToLocalISO, astmProfiles, attachComments, buildAstmMessage, classifyMessage, comments, commentsFor, composeAstmFrames, computeChecksum, decodeAstmFrames, decodeEscapes, deepFreeze, defineAstmProfile, defineLivdCatalog, delimiterRoleCollision, delimiterSwallowedByEscape, delimitersRedeclared, detectFraming, encodeComponent, fieldScalar, fieldsUnseparated, frameBadChecksum, frameOversize, frameSequenceGap, frameUnterminated, getAstmProfile, getDefaultAstmProfile, hasCollidingRoles, interpretAbnormalFlag, interpretResultStatus, isNonStandard, isSafetyCriticalCode, listAstmProfiles, livdAmbiguousMapping, livdUnmappedCode, lookupLivdForRecord, ltpAmbiguousTransport, ltpFrameRejected, ltpInitialState, ltpReduce, ltpUnexpectedEvent, messages, nonStandardDelimiters, orders, orphanComment, parseAstmDate, parseAstmRecords, parseChecksumHex, parseFramedAstm, parseReferenceRange, partialTimestamp, patient, primaryCode, profileQuirkApplied, query, readDelimiterDeclaration, readDelimiters, recognizeUniversalTestId, resolveProfileTransport, results, serializeAstmRecord, serializeAstmRecords, serializeField, serializeFramedAstm, setDefaultAstmProfile, splitEscapeAware, toChecksumHex, tokenizeHeader, tokenizeRecord, undefinedAbnormalFlag, undefinedResultStatus, uninterpretedQueryStatus, unitsAbsent, unknownEscapeSequence, unknownRecordType, unpairedEscapeCharacter, unparseableReferenceRange, unreadableRedeclaration };
|
|
7151
|
+
export { ABNORMAL_FLAG_CODES, ABNORMAL_FLAG_VOCABULARY, ALL_ASTM_WARNING_CODES, AMBIGUOUS_CODES, ACK as ASTM_ACK, ENQ as ASTM_ENQ, EOT as ASTM_EOT, NAK as ASTM_NAK, type AbnormalFlag, type AbnormalFlagCode, type AbnormalFlagMeaning, type AmbiguousAlignmentSink, type AmbiguousCode, type AnyAstmWarningCode, AstmAmbiguousStreamError, type AstmDate, type AstmDatePrecision, type AstmField, type AstmFrame, AstmFrameEncodeError, type AstmFrameEncodeErrorCode, type AstmFramePosition, AstmFrameStrictError, type AstmFrameWarning, type AstmFraming, type AstmLivdCatalogWarning, type AstmLivdWarning, type AstmLtpWarning, type AstmMessage, type AstmMessageClassification, type AstmMessageKind, AstmParseError, type AstmParseOptions, type AstmPosition, type AstmProfile, AstmProfileDefinitionError, type AstmProfileProvenance, type AstmQuirkMatch, type AstmQuirkTolerance, type AstmRecord, type AstmRecordInput, type AstmRecordWarning, AstmSerializeError, type AstmSerializeErrorCode, type AstmStreamMessage, AstmStrictError, CANONICAL_DELIMITERS, type CommentInput, type CommentRecord, type ComposeFramesOptions, type DateParts, type DecodeAstmFramesResult, type DefineAstmProfileOptions, type DelimiterDeclarationFault, type DelimiterReadResult, type Delimiters, type DetectFramingOptions, type DetectFramingResult, FATAL_CODES, FRAME_WARNING_CODES, type FatalCode, type FrameChecksum, type FrameOptions, type FrameTerminator, type FrameWarningCode, type FramedAstmResult, type HeaderInput, type HeaderRecord, LIVD_CATALOG_IDENTITY_UNDECLARED, LIVD_WARNING_CODES, LTP_WARNING_CODES, type LivdAmbiguityReason, type LivdAnnotation, type LivdCandidate, type LivdCatalog, type LivdCatalogIdentity, type LivdEntry, type LivdLookup, type LivdMapping, type LivdPublication, type LivdResult, type LivdUnitComparison, type LivdWarningCode, type LtpAction, type LtpEvent, type LtpPhase, type LtpState, type LtpTransition, type LtpWarningCode, type ManufacturerRecord, type MessageInput, type NamedVocabulary, type OrderInput, type OrderRecord, type PatientInput, type PatientName, type PatientNameInput, type PatientRecord, type QueryInput, type QueryRecord, RESULT_STATUS_VOCABULARY, type ReferenceRange, type ReferenceRangeKind, type ResultInput, type ResultRecord, type ResultStatus, type ResultStatusCode, type ResultStatusMeaning, SAFETY_CRITICAL_CODES, type ScientificRecord, type ShiftedComponentsSink, type ShiftedFieldsSink, type SwallowedDelimiterSink, TOLERABLE_CODES, type TerminatorRecord, type ToDateOptions, type TruncatedFieldSink, type UnattributedVocabulary, type UniversalTestId, type UniversalTestIdProvenance, type UnknownEscapeSink, type UnpairedEscapeSink, type UnsupportedRecord, VERSION, type VerbatimInput, type VocabularyAttribution, WARNING_CODES, type WarningCode, alignmentShiftedComponents, alignmentShiftedFields, alignmentTruncatedField, ambiguousEscapeAlignment, ambiguousMessageKind, ambiguousValueSplit, applyAstmProfile, applyAstmProfileToWarnings, applyLivd, astmDateToLocalISO, astmProfiles, attachComments, buildAstmMessage, classifyMessage, comments, commentsFor, composeAstmFrames, computeChecksum, decodeAstmFrames, decodeEscapes, deepFreeze, defineAstmProfile, defineLivdCatalog, delimiterRoleCollision, delimiterSwallowedByEscape, delimitersRedeclared, describeVocabulary, detectFraming, encodeComponent, fieldScalar, fieldsUnseparated, frameBadChecksum, frameOversize, frameSequenceGap, frameUnterminated, getAstmProfile, getDefaultAstmProfile, hasCollidingRoles, interpretAbnormalFlag, interpretResultStatus, isNonStandard, isSafetyCriticalCode, listAstmProfiles, livdAmbiguousMapping, livdCatalogMissingLoincVersion, livdUnmappedCode, lookupLivdForRecord, ltpAmbiguousTransport, ltpFrameRejected, ltpInitialState, ltpReduce, ltpUnexpectedEvent, messages, nonStandardDelimiters, orders, orphanComment, parseAstmDate, parseAstmRecords, parseChecksumHex, parseFramedAstm, parseReferenceRange, partialTimestamp, patient, primaryCode, profileQuirkApplied, query, readDelimiterDeclaration, readDelimiters, recognizeUniversalTestId, resolveProfileTransport, results, serializeAstmRecord, serializeAstmRecords, serializeField, serializeFramedAstm, setDefaultAstmProfile, splitEscapeAware, toChecksumHex, toDate, toISO, toObject, tokenizeHeader, tokenizeRecord, undefinedAbnormalFlag, undefinedResultStatus, uninterpretedQueryStatus, unitsAbsent, unknownEscapeSequence, unknownRecordType, unpairedEscapeCharacter, unparseableReferenceRange, unreadableRedeclaration };
|