@cosyte/astm 0.0.4 → 0.0.5
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 +152 -119
- package/README.md +23 -23
- package/dist/index.cjs +57 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +394 -394
- package/dist/index.d.ts +394 -394
- package/dist/index.mjs +57 -57
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// src/common/errors.ts
|
|
2
2
|
var FATAL_CODES = {
|
|
3
|
-
/** Input was empty or whitespace-only
|
|
3
|
+
/** Input was empty or whitespace-only: there is nothing to parse. Shared across layers. */
|
|
4
4
|
EMPTY_INPUT: "EMPTY_INPUT",
|
|
5
|
-
/** The first record is not an `H` (header) record
|
|
5
|
+
/** The first record is not an `H` (header) record: an ASTM message must lead with `H`. */
|
|
6
6
|
ASTM_RECORD_NO_HEADER: "ASTM_RECORD_NO_HEADER",
|
|
7
7
|
/** The `H` record is too short to declare the four delimiters (field/repeat/component/escape). */
|
|
8
8
|
ASTM_RECORD_UNDECLARED_DELIMITERS: "ASTM_RECORD_UNDECLARED_DELIMITERS"
|
|
@@ -119,21 +119,21 @@ function primaryCode(u) {
|
|
|
119
119
|
|
|
120
120
|
// src/common/warnings.ts
|
|
121
121
|
var WARNING_CODES = {
|
|
122
|
-
/** A record's type letter is not one of the modeled types
|
|
122
|
+
/** A record's type letter is not one of the modeled types: surfaced as an unsupported record. */
|
|
123
123
|
ASTM_RECORD_UNKNOWN_TYPE: "ASTM_RECORD_UNKNOWN_TYPE",
|
|
124
|
-
/** The header declared delimiters other than the canonical `H
|
|
124
|
+
/** The header declared delimiters other than the canonical `H|\^&`: tolerated, noted. */
|
|
125
125
|
ASTM_NONSTANDARD_DELIMITERS: "ASTM_NONSTANDARD_DELIMITERS",
|
|
126
|
-
/** An escape sequence body was not one of `&F&`/`&S&`/`&R&`/`&E
|
|
126
|
+
/** An escape sequence body was not one of `&F&`/`&S&`/`&R&`/`&E&`: preserved verbatim. */
|
|
127
127
|
ASTM_UNKNOWN_ESCAPE_SEQUENCE: "ASTM_UNKNOWN_ESCAPE_SEQUENCE",
|
|
128
128
|
/**
|
|
129
129
|
* A result value field carried an *unescaped* component delimiter, so it split into more than one
|
|
130
|
-
* component. Both the full raw value and the split are surfaced and this warning fires
|
|
130
|
+
* component. Both the full raw value and the split are surfaced and this warning fires: the
|
|
131
131
|
* ambiguity is never resolved silently into a truncated value.
|
|
132
132
|
*/
|
|
133
133
|
ASTM_RECORD_AMBIGUOUS_VALUE_SPLIT: "ASTM_RECORD_AMBIGUOUS_VALUE_SPLIT",
|
|
134
134
|
/**
|
|
135
135
|
* A result's abnormal-flag field (`R` field 7) carried a letter outside HL7 Table 0078. The flag is
|
|
136
|
-
* surfaced as `undefined
|
|
136
|
+
* surfaced as `undefined`: never dropped, and **never coerced to `normal`** (a clinical error).
|
|
137
137
|
*/
|
|
138
138
|
ASTM_RECORD_UNDEFINED_ABNORMAL_FLAG: "ASTM_RECORD_UNDEFINED_ABNORMAL_FLAG",
|
|
139
139
|
/**
|
|
@@ -143,7 +143,7 @@ var WARNING_CODES = {
|
|
|
143
143
|
ASTM_RECORD_UNDEFINED_RESULT_STATUS: "ASTM_RECORD_UNDEFINED_RESULT_STATUS",
|
|
144
144
|
/**
|
|
145
145
|
* A result's reference-range field (`R` field 6) did not match a recognized form (`low-high`,
|
|
146
|
-
* `<high`, `>low`). The text is surfaced verbatim as `unparsed
|
|
146
|
+
* `<high`, `>low`). The text is surfaced verbatim as `unparsed`: a bound is **never fabricated**.
|
|
147
147
|
*/
|
|
148
148
|
ASTM_RECORD_UNPARSEABLE_REFERENCE_RANGE: "ASTM_RECORD_UNPARSEABLE_REFERENCE_RANGE",
|
|
149
149
|
/**
|
|
@@ -152,25 +152,25 @@ var WARNING_CODES = {
|
|
|
152
152
|
*/
|
|
153
153
|
ASTM_RECORD_UNITS_ABSENT: "ASTM_RECORD_UNITS_ABSENT",
|
|
154
154
|
/**
|
|
155
|
-
* A `C` (comment) record had no valid preceding `H`/`P`/`O`/`R` parent
|
|
155
|
+
* A `C` (comment) record had no valid preceding `H`/`P`/`O`/`R` parent: an **orphan**. The comment
|
|
156
156
|
* is attached to the message root (`attachedToRoot: true`) and surfaced, **never dropped**.
|
|
157
157
|
*/
|
|
158
158
|
ASTM_RECORD_ORPHAN_COMMENT: "ASTM_RECORD_ORPHAN_COMMENT",
|
|
159
159
|
/**
|
|
160
160
|
* A `YYYYMMDDHHMMSS` timestamp had an odd digit run that truncates a two-digit component in half
|
|
161
161
|
* (e.g. a partial day/hour). The raw run is preserved and the structured value stops at the last
|
|
162
|
-
* **complete** component
|
|
162
|
+
* **complete** component: the dangling digit is **never zero-filled into a fabricated time**.
|
|
163
163
|
*/
|
|
164
164
|
ASTM_RECORD_PARTIAL_TIMESTAMP: "ASTM_RECORD_PARTIAL_TIMESTAMP",
|
|
165
165
|
/**
|
|
166
166
|
* A `Q` (request-information) record carried a request-information status code (field 13). The code
|
|
167
167
|
* *set* is `[OSS-derived / paywalled]` with no publicly-groundable enumeration, so the parser
|
|
168
168
|
* interprets **none** of them: the status is surfaced verbatim and this value-free warning flags that
|
|
169
|
-
* it was passed through **uninterpreted
|
|
169
|
+
* it was passed through **uninterpreted**, never mapped to a guessed meaning.
|
|
170
170
|
*/
|
|
171
171
|
ASTM_RECORD_UNINTERPRETED_QUERY_STATUS: "ASTM_RECORD_UNINTERPRETED_QUERY_STATUS",
|
|
172
172
|
/**
|
|
173
|
-
* A message carried **both** a `Q` (request) and an `R` (result) record
|
|
173
|
+
* A message carried **both** a `Q` (request) and an `R` (result) record: a contradictory shape. The
|
|
174
174
|
* message is classified `host-query` (the `Q` **dominates**, so it is never read as a result set) and
|
|
175
175
|
* this warning flags the anomaly. Positional context only; no field value.
|
|
176
176
|
*/
|
|
@@ -179,7 +179,7 @@ var WARNING_CODES = {
|
|
|
179
179
|
* A later `H` (header) record declared a **different** delimiter set from the one in force, and the
|
|
180
180
|
* parser **followed it**: that header and every record after it are read with the newly-declared
|
|
181
181
|
* delimiters, until the next `H`. Records already read keep the set that was in force when they were
|
|
182
|
-
* read
|
|
182
|
+
* read: a redeclaration never reinterprets bytes that have already been consumed.
|
|
183
183
|
*
|
|
184
184
|
* A stream carrying several messages back to back is ordinary, and a header that simply **repeats**
|
|
185
185
|
* the delimiters already in force is a no-op that warns nothing. This code fires only when the set
|
|
@@ -188,13 +188,13 @@ var WARNING_CODES = {
|
|
|
188
188
|
*/
|
|
189
189
|
ASTM_RECORD_DELIMITERS_REDECLARED: "ASTM_RECORD_DELIMITERS_REDECLARED",
|
|
190
190
|
/**
|
|
191
|
-
* A later `H` (header) record could not declare a usable delimiter set
|
|
191
|
+
* A later `H` (header) record could not declare a usable delimiter set: it was too short, or the
|
|
192
192
|
* field separator it named also appeared among the other three, leaving the four roles
|
|
193
193
|
* indistinguishable. The delimiters **already in force are kept** and every record is still surfaced;
|
|
194
194
|
* a set is never guessed and no record is dropped.
|
|
195
195
|
*
|
|
196
196
|
* The same condition on the *first* header is unrecoverable and remains the
|
|
197
|
-
* `ASTM_RECORD_UNDECLARED_DELIMITERS` fatal
|
|
197
|
+
* `ASTM_RECORD_UNDECLARED_DELIMITERS` fatal: there is no earlier set to fall back to.
|
|
198
198
|
*/
|
|
199
199
|
ASTM_RECORD_UNREADABLE_REDECLARATION: "ASTM_RECORD_UNREADABLE_REDECLARATION",
|
|
200
200
|
/**
|
|
@@ -202,7 +202,7 @@ var WARNING_CODES = {
|
|
|
202
202
|
* (see `src/profiles/`). The original warning is **never dropped**: its code moves to
|
|
203
203
|
* {@link AstmRecordWarning.toleratedCode}, the warning is re-badged `PROFILE_QUIRK_APPLIED` with
|
|
204
204
|
* `expected: true` and the tolerating profile named, so a consumer can filter known, grounded noise
|
|
205
|
-
* while the fact of the deviation
|
|
205
|
+
* while the fact of the deviation, and where it was, survives. A profile can only ever reach this
|
|
206
206
|
* path for a **non-safety-critical** code (enforced at profile-definition time); a safety-critical
|
|
207
207
|
* deviation (a result value, flag, status, patient identifier, code system, or a frame-integrity
|
|
208
208
|
* warning) can **never** be tolerated, so it can never be re-badged here.
|
|
@@ -212,28 +212,28 @@ var WARNING_CODES = {
|
|
|
212
212
|
function unknownRecordType(position) {
|
|
213
213
|
return {
|
|
214
214
|
code: WARNING_CODES.ASTM_RECORD_UNKNOWN_TYPE,
|
|
215
|
-
message: "Unrecognized record type
|
|
215
|
+
message: "Unrecognized record type, surfaced verbatim as an unsupported record.",
|
|
216
216
|
position
|
|
217
217
|
};
|
|
218
218
|
}
|
|
219
219
|
function nonStandardDelimiters(position) {
|
|
220
220
|
return {
|
|
221
221
|
code: WARNING_CODES.ASTM_NONSTANDARD_DELIMITERS,
|
|
222
|
-
message: "Header declared non-canonical delimiters
|
|
222
|
+
message: "Header declared non-canonical delimiters, read from the header and honored.",
|
|
223
223
|
position
|
|
224
224
|
};
|
|
225
225
|
}
|
|
226
226
|
function delimitersRedeclared(position) {
|
|
227
227
|
return {
|
|
228
228
|
code: WARNING_CODES.ASTM_RECORD_DELIMITERS_REDECLARED,
|
|
229
|
-
message: "A later header declared different delimiters
|
|
229
|
+
message: "A later header declared different delimiters, honored from that header onward; earlier records keep the set they were read with.",
|
|
230
230
|
position
|
|
231
231
|
};
|
|
232
232
|
}
|
|
233
233
|
function unreadableRedeclaration(position) {
|
|
234
234
|
return {
|
|
235
235
|
code: WARNING_CODES.ASTM_RECORD_UNREADABLE_REDECLARATION,
|
|
236
|
-
message: "A later header could not declare a usable delimiter set
|
|
236
|
+
message: "A later header could not declare a usable delimiter set, the delimiters already in force were kept.",
|
|
237
237
|
position
|
|
238
238
|
};
|
|
239
239
|
}
|
|
@@ -247,63 +247,63 @@ function unknownEscapeSequence(position) {
|
|
|
247
247
|
function ambiguousValueSplit(position) {
|
|
248
248
|
return {
|
|
249
249
|
code: WARNING_CODES.ASTM_RECORD_AMBIGUOUS_VALUE_SPLIT,
|
|
250
|
-
message: "Result value contained an unescaped component delimiter
|
|
250
|
+
message: "Result value contained an unescaped component delimiter, full raw value and split both surfaced.",
|
|
251
251
|
position
|
|
252
252
|
};
|
|
253
253
|
}
|
|
254
254
|
function undefinedAbnormalFlag(position) {
|
|
255
255
|
return {
|
|
256
256
|
code: WARNING_CODES.ASTM_RECORD_UNDEFINED_ABNORMAL_FLAG,
|
|
257
|
-
message: "Abnormal flag is not in HL7 Table 0078
|
|
257
|
+
message: "Abnormal flag is not in HL7 Table 0078, surfaced as undefined, never as normal.",
|
|
258
258
|
position
|
|
259
259
|
};
|
|
260
260
|
}
|
|
261
261
|
function undefinedResultStatus(position) {
|
|
262
262
|
return {
|
|
263
263
|
code: WARNING_CODES.ASTM_RECORD_UNDEFINED_RESULT_STATUS,
|
|
264
|
-
message: "Result status is not a recognized status letter
|
|
264
|
+
message: "Result status is not a recognized status letter, surfaced as undefined.",
|
|
265
265
|
position
|
|
266
266
|
};
|
|
267
267
|
}
|
|
268
268
|
function unparseableReferenceRange(position) {
|
|
269
269
|
return {
|
|
270
270
|
code: WARNING_CODES.ASTM_RECORD_UNPARSEABLE_REFERENCE_RANGE,
|
|
271
|
-
message: "Reference range did not match a recognized form
|
|
271
|
+
message: "Reference range did not match a recognized form, surfaced verbatim, no bound invented.",
|
|
272
272
|
position
|
|
273
273
|
};
|
|
274
274
|
}
|
|
275
275
|
function unitsAbsent(position) {
|
|
276
276
|
return {
|
|
277
277
|
code: WARNING_CODES.ASTM_RECORD_UNITS_ABSENT,
|
|
278
|
-
message: "Numeric result value carried no units
|
|
278
|
+
message: "Numeric result value carried no units, never defaulted, guessed, or converted.",
|
|
279
279
|
position
|
|
280
280
|
};
|
|
281
281
|
}
|
|
282
282
|
function orphanComment(position) {
|
|
283
283
|
return {
|
|
284
284
|
code: WARNING_CODES.ASTM_RECORD_ORPHAN_COMMENT,
|
|
285
|
-
message: "Comment had no valid preceding parent
|
|
285
|
+
message: "Comment had no valid preceding parent, attached to the message root, never dropped.",
|
|
286
286
|
position
|
|
287
287
|
};
|
|
288
288
|
}
|
|
289
289
|
function partialTimestamp(position) {
|
|
290
290
|
return {
|
|
291
291
|
code: WARNING_CODES.ASTM_RECORD_PARTIAL_TIMESTAMP,
|
|
292
|
-
message: "Timestamp digit run truncates a component
|
|
292
|
+
message: "Timestamp digit run truncates a component, preserved verbatim, never zero-filled.",
|
|
293
293
|
position
|
|
294
294
|
};
|
|
295
295
|
}
|
|
296
296
|
function uninterpretedQueryStatus(position) {
|
|
297
297
|
return {
|
|
298
298
|
code: WARNING_CODES.ASTM_RECORD_UNINTERPRETED_QUERY_STATUS,
|
|
299
|
-
message: "Query request-information status surfaced verbatim
|
|
299
|
+
message: "Query request-information status surfaced verbatim, code set paywalled, never interpreted.",
|
|
300
300
|
position
|
|
301
301
|
};
|
|
302
302
|
}
|
|
303
303
|
function ambiguousMessageKind(position) {
|
|
304
304
|
return {
|
|
305
305
|
code: WARNING_CODES.ASTM_RECORD_AMBIGUOUS_MESSAGE_KIND,
|
|
306
|
-
message: "Message carried both a Q (request) and an R (result) record
|
|
306
|
+
message: "Message carried both a Q (request) and an R (result) record, classified host-query; Q dominates.",
|
|
307
307
|
position
|
|
308
308
|
};
|
|
309
309
|
}
|
|
@@ -567,12 +567,12 @@ var FRAME_WARNING_CODES = {
|
|
|
567
567
|
* A frame's two-hex-char checksum did not match the modulo-256 sum recomputed over its bytes. The
|
|
568
568
|
* frame is surfaced with `trusted: false` and its text is **never merged** into a reassembled
|
|
569
569
|
* record (default **warn** in lenient mode, escalated to a thrown error in `strict`). Corruption is
|
|
570
|
-
* never silently trusted
|
|
570
|
+
* never silently trusted: the "checksums are routinely not validated" claim was refuted; we
|
|
571
571
|
* validate.
|
|
572
572
|
*/
|
|
573
573
|
ASTM_FRAME_BAD_CHECKSUM: "ASTM_FRAME_BAD_CHECKSUM",
|
|
574
574
|
/**
|
|
575
|
-
* A frame's sequence number was not the expected next value (`1 → … → 7 → 0 → …`)
|
|
575
|
+
* A frame's sequence number was not the expected next value (`1 → … → 7 → 0 → …`): a frame was
|
|
576
576
|
* possibly dropped. The stream is **never silently concatenated across the gap** as if contiguous;
|
|
577
577
|
* the in-progress record is tainted and not emitted as a clean reassembly.
|
|
578
578
|
*/
|
|
@@ -586,7 +586,7 @@ var FRAME_WARNING_CODES = {
|
|
|
586
586
|
ASTM_FRAME_UNTERMINATED: "ASTM_FRAME_UNTERMINATED",
|
|
587
587
|
/**
|
|
588
588
|
* A frame's record text exceeded the 240-byte limit without a split. The frame is still surfaced
|
|
589
|
-
* (and, if its checksum validates, reassembled)
|
|
589
|
+
* (and, if its checksum validates, reassembled): the deviation is flagged, not silently dropped
|
|
590
590
|
* (warn in lenient, thrown in `strict`).
|
|
591
591
|
*/
|
|
592
592
|
ASTM_FRAME_OVERSIZE: "ASTM_FRAME_OVERSIZE"
|
|
@@ -594,28 +594,28 @@ var FRAME_WARNING_CODES = {
|
|
|
594
594
|
function frameBadChecksum(position) {
|
|
595
595
|
return {
|
|
596
596
|
code: FRAME_WARNING_CODES.ASTM_FRAME_BAD_CHECKSUM,
|
|
597
|
-
message: "Frame checksum mismatch
|
|
597
|
+
message: "Frame checksum mismatch, surfaced untrusted, never merged into a record.",
|
|
598
598
|
position
|
|
599
599
|
};
|
|
600
600
|
}
|
|
601
601
|
function frameSequenceGap(position) {
|
|
602
602
|
return {
|
|
603
603
|
code: FRAME_WARNING_CODES.ASTM_FRAME_SEQUENCE_GAP,
|
|
604
|
-
message: "Frame number out of sequence
|
|
604
|
+
message: "Frame number out of sequence, possible dropped frame, never silently bridged.",
|
|
605
605
|
position
|
|
606
606
|
};
|
|
607
607
|
}
|
|
608
608
|
function frameUnterminated(position) {
|
|
609
609
|
return {
|
|
610
610
|
code: FRAME_WARNING_CODES.ASTM_FRAME_UNTERMINATED,
|
|
611
|
-
message: "Unterminated frame
|
|
611
|
+
message: "Unterminated frame, partial bytes surfaced untrusted, no partial record invented.",
|
|
612
612
|
position
|
|
613
613
|
};
|
|
614
614
|
}
|
|
615
615
|
function frameOversize(position) {
|
|
616
616
|
return {
|
|
617
617
|
code: FRAME_WARNING_CODES.ASTM_FRAME_OVERSIZE,
|
|
618
|
-
message: "Frame text exceeded the 240-byte limit without a split
|
|
618
|
+
message: "Frame text exceeded the 240-byte limit without a split, flagged, never dropped.",
|
|
619
619
|
position
|
|
620
620
|
};
|
|
621
621
|
}
|
|
@@ -624,21 +624,21 @@ function frameOversize(position) {
|
|
|
624
624
|
var LTP_WARNING_CODES = {
|
|
625
625
|
/**
|
|
626
626
|
* The transport detector could not tell a framed stream from a raw (unframed) one from its leading
|
|
627
|
-
* byte
|
|
627
|
+
* byte: it was neither `STX`/`ENQ` nor a bare record letter. It **defaults to framed** and warns,
|
|
628
628
|
* never guessing silently into data loss; a profile override forces the mode. (cobas b121 drops
|
|
629
|
-
* framing over TCP; cobas 4800 / Iguana retain it
|
|
629
|
+
* framing over TCP; cobas 4800 / Iguana retain it, both realities exist, so an unrecognizable lead
|
|
630
630
|
* is defaulted, not assumed.)
|
|
631
631
|
*/
|
|
632
632
|
ASTM_LTP_AMBIGUOUS_TRANSPORT: "ASTM_LTP_AMBIGUOUS_TRANSPORT",
|
|
633
633
|
/**
|
|
634
|
-
* A control event arrived in a protocol state that did not expect it
|
|
634
|
+
* A control event arrived in a protocol state that did not expect it: e.g. an inbound `ACK`/`NAK`
|
|
635
635
|
* at a receiver (which sends, never receives, those), or an `ENQ` mid-transfer. The event is
|
|
636
636
|
* surfaced and handled defensively (an unexpected `ACK`/`NAK` is **never** read as acceptance of
|
|
637
637
|
* data); it never advances the transfer as if valid.
|
|
638
638
|
*/
|
|
639
639
|
ASTM_LTP_UNEXPECTED_EVENT: "ASTM_LTP_UNEXPECTED_EVENT",
|
|
640
640
|
/**
|
|
641
|
-
* The receiver rejected a received frame with a `NAK` instead of accepting it
|
|
641
|
+
* The receiver rejected a received frame with a `NAK` instead of accepting it: because its
|
|
642
642
|
* checksum failed, it was unterminated, or its frame number was out of sequence. The frame's text
|
|
643
643
|
* is **never** appended to the record and the transfer does **not** advance; the receiver awaits the
|
|
644
644
|
* sender's retransmit. This is the protocol-level face of the frame codec's fail-safe: a bad frame
|
|
@@ -649,20 +649,20 @@ var LTP_WARNING_CODES = {
|
|
|
649
649
|
function ltpAmbiguousTransport() {
|
|
650
650
|
return {
|
|
651
651
|
code: LTP_WARNING_CODES.ASTM_LTP_AMBIGUOUS_TRANSPORT,
|
|
652
|
-
message: "Leading byte was neither a frame start (STX/ENQ) nor a record letter
|
|
652
|
+
message: "Leading byte was neither a frame start (STX/ENQ) nor a record letter, defaulted to framed; override with a profile to force raw."
|
|
653
653
|
};
|
|
654
654
|
}
|
|
655
655
|
function ltpUnexpectedEvent(frameNumber) {
|
|
656
656
|
return {
|
|
657
657
|
code: LTP_WARNING_CODES.ASTM_LTP_UNEXPECTED_EVENT,
|
|
658
|
-
message: "Control event arrived in a state that did not expect it
|
|
658
|
+
message: "Control event arrived in a state that did not expect it, handled defensively, never read as acceptance.",
|
|
659
659
|
...frameNumber !== void 0 ? { frameNumber } : {}
|
|
660
660
|
};
|
|
661
661
|
}
|
|
662
662
|
function ltpFrameRejected(frameNumber) {
|
|
663
663
|
return {
|
|
664
664
|
code: LTP_WARNING_CODES.ASTM_LTP_FRAME_REJECTED,
|
|
665
|
-
message: "Frame rejected (bad checksum, unterminated, or out of sequence)
|
|
665
|
+
message: "Frame rejected (bad checksum, unterminated, or out of sequence), NAK sent, retransmit expected, never accepted.",
|
|
666
666
|
...frameNumber !== void 0 ? { frameNumber } : {}
|
|
667
667
|
};
|
|
668
668
|
}
|
|
@@ -770,7 +770,7 @@ function validateTolerations(tolerate, profileName) {
|
|
|
770
770
|
}
|
|
771
771
|
if (isSafetyCriticalCode(t.code)) {
|
|
772
772
|
throw new AstmProfileDefinitionError(
|
|
773
|
-
`Profile '${profileName}' may not tolerate '${t.code}'
|
|
773
|
+
`Profile '${profileName}' may not tolerate '${t.code}': it is a safety-critical warning code (a result value / flag / status / range / units, patient or comment context, message-kind ambiguity, code system, or a frame / LTP integrity warning). A profile quiets benign structural noise, never a deviation that could change a clinical reading or corrupt the wire: it can never make a bad checksum "ok" or a cancelled result read "final."`,
|
|
774
774
|
profileName
|
|
775
775
|
);
|
|
776
776
|
}
|
|
@@ -813,14 +813,14 @@ function defineAstmProfile(opts) {
|
|
|
813
813
|
// src/profiles/default.ts
|
|
814
814
|
var defaultProfile = defineAstmProfile({
|
|
815
815
|
name: "default",
|
|
816
|
-
description: "Conservative baseline
|
|
816
|
+
description: "Conservative baseline: tolerates nothing; every deviation surfaces as a warning.",
|
|
817
817
|
tolerate: []
|
|
818
818
|
});
|
|
819
819
|
|
|
820
820
|
// src/profiles/reference-corpus.ts
|
|
821
821
|
var referenceCorpus = defineAstmProfile({
|
|
822
822
|
name: "referenceCorpus",
|
|
823
|
-
description: "Non-standard-escape tolerance grounded firsthand in the escape-agnostic OSS reference corpus (python-astm / senaite). Syntactic encoding noise only
|
|
823
|
+
description: "Non-standard-escape tolerance grounded firsthand in the escape-agnostic OSS reference corpus (python-astm / senaite). Syntactic encoding noise only: the value is preserved verbatim, never a safety-critical value.",
|
|
824
824
|
provenance: {
|
|
825
825
|
source: "kxepal/python-astm codec.py (BSD) + senaite.astm / senaite.lis2a",
|
|
826
826
|
reference: "https://github.com/kxepal/python-astm/blob/master/astm/codec.py ; https://github.com/senaite/senaite.astm",
|
|
@@ -1084,7 +1084,7 @@ function buildRecord(line2, recordIndex, d, warnings) {
|
|
|
1084
1084
|
case "Q":
|
|
1085
1085
|
return buildQuery(recordIndex, fields, warnings);
|
|
1086
1086
|
// `M` (manufacturer) and `S` (scientific) are vendor-defined free-form data surfaced VERBATIM and
|
|
1087
|
-
// NEVER interpreted into typed clinical fields
|
|
1087
|
+
// NEVER interpreted into typed clinical fields: the exact wire line is preserved for round-trip.
|
|
1088
1088
|
case "M":
|
|
1089
1089
|
return { type: "M", recordIndex, fields, rawLine: line2 };
|
|
1090
1090
|
case "S":
|
|
@@ -1117,7 +1117,7 @@ function buildPatient(recordIndex, fields, warnings) {
|
|
|
1117
1117
|
recordIndex,
|
|
1118
1118
|
fields,
|
|
1119
1119
|
...definedString("seq", fieldScalar(astmField(fields, 2))),
|
|
1120
|
-
// The three patient identifiers stay DISTINCT
|
|
1120
|
+
// The three patient identifiers stay DISTINCT: practice-assigned (3), laboratory-assigned (4),
|
|
1121
1121
|
// and a third ID (5) never collapse into one; conflating them is the primary misfiling path.
|
|
1122
1122
|
...definedString("practiceAssignedId", fieldScalar(astmField(fields, 3))),
|
|
1123
1123
|
...definedString("laboratoryAssignedId", fieldScalar(astmField(fields, 4))),
|
|
@@ -1140,7 +1140,7 @@ function buildOrder(recordIndex, fields) {
|
|
|
1140
1140
|
...hasContent(utidField) ? { universalTestId: recognizeUniversalTestId(utidField.components) } : {},
|
|
1141
1141
|
// Priority (6), action code (~12), and report type (~26) are surfaced verbatim. The `~` field
|
|
1142
1142
|
// indices and the code sets are `[OSS-derived]` (paywalled), so they are never mapped to a
|
|
1143
|
-
// guessed meaning
|
|
1143
|
+
// guessed meaning: see the JSDoc on `OrderRecord`.
|
|
1144
1144
|
...definedString("priority", fieldScalar(astmField(fields, 6))),
|
|
1145
1145
|
...definedString("actionCode", fieldScalar(astmField(fields, 12))),
|
|
1146
1146
|
...definedString("reportType", fieldScalar(astmField(fields, 26)))
|
|
@@ -1539,7 +1539,7 @@ var AMBIGUOUS_CODES = {
|
|
|
1539
1539
|
ASTM_AMBIGUOUS_MULTI_PATIENT: "ASTM_AMBIGUOUS_MULTI_PATIENT"
|
|
1540
1540
|
};
|
|
1541
1541
|
var AstmAmbiguousStreamError = class extends Error {
|
|
1542
|
-
/** The stable discriminant
|
|
1542
|
+
/** The stable discriminant: see {@link AMBIGUOUS_CODES}. */
|
|
1543
1543
|
code;
|
|
1544
1544
|
/** Where the ambiguity became visible: the second header, or the second `P`. Value-free. */
|
|
1545
1545
|
position;
|
|
@@ -1684,14 +1684,14 @@ function defineLivdCatalog(entries) {
|
|
|
1684
1684
|
var LIVD_WARNING_CODES = {
|
|
1685
1685
|
/**
|
|
1686
1686
|
* A record carried a vendor/local test code, but the consumer-supplied LIVD catalog held **no**
|
|
1687
|
-
* entry for it. The code stays surfaced verbatim and the mapping is `unmapped
|
|
1687
|
+
* entry for it. The code stays surfaced verbatim and the mapping is `unmapped`: a LOINC is
|
|
1688
1688
|
* **never** guessed. Purely advisory: the raw code and value are untouched.
|
|
1689
1689
|
*/
|
|
1690
1690
|
ASTM_LIVD_UNMAPPED_CODE: "ASTM_LIVD_UNMAPPED_CODE",
|
|
1691
1691
|
/**
|
|
1692
1692
|
* A vendor/local test code matched **more than one distinct LOINC** in the catalog (e.g. the same
|
|
1693
1693
|
* transmission code used by two devices for different analytes). The mapping is `ambiguous` and the
|
|
1694
|
-
* candidate LOINCs are surfaced for inspection, but **none is chosen
|
|
1694
|
+
* candidate LOINCs are surfaced for inspection, but **none is chosen**: refusing to pick is the
|
|
1695
1695
|
* fail-safe, since guessing wrong mis-identifies the test.
|
|
1696
1696
|
*/
|
|
1697
1697
|
ASTM_LIVD_AMBIGUOUS_MAPPING: "ASTM_LIVD_AMBIGUOUS_MAPPING"
|
|
@@ -1699,14 +1699,14 @@ var LIVD_WARNING_CODES = {
|
|
|
1699
1699
|
function livdUnmappedCode(position) {
|
|
1700
1700
|
return {
|
|
1701
1701
|
code: LIVD_WARNING_CODES.ASTM_LIVD_UNMAPPED_CODE,
|
|
1702
|
-
message: "Reported test code had no LIVD mapping
|
|
1702
|
+
message: "Reported test code had no LIVD mapping, surfaced unmapped, never a guessed LOINC.",
|
|
1703
1703
|
position
|
|
1704
1704
|
};
|
|
1705
1705
|
}
|
|
1706
1706
|
function livdAmbiguousMapping(position) {
|
|
1707
1707
|
return {
|
|
1708
1708
|
code: LIVD_WARNING_CODES.ASTM_LIVD_AMBIGUOUS_MAPPING,
|
|
1709
|
-
message: "Reported test code mapped to multiple distinct LOINCs
|
|
1709
|
+
message: "Reported test code mapped to multiple distinct LOINCs, surfaced ambiguous, never one guessed.",
|
|
1710
1710
|
position
|
|
1711
1711
|
};
|
|
1712
1712
|
}
|
|
@@ -2150,7 +2150,7 @@ function encodeFrame(text, frameNumber, isFinal) {
|
|
|
2150
2150
|
}
|
|
2151
2151
|
function composeAstmFrames(records, options = {}) {
|
|
2152
2152
|
if (records.length === 0) {
|
|
2153
|
-
throw new AstmFrameEncodeError("Cannot frame an empty record list
|
|
2153
|
+
throw new AstmFrameEncodeError("Cannot frame an empty record list: nothing to transmit.");
|
|
2154
2154
|
}
|
|
2155
2155
|
const out = [];
|
|
2156
2156
|
let frameNumber = options.startFrameNumber ?? FIRST_FRAME_NUMBER;
|
|
@@ -2158,7 +2158,7 @@ function composeAstmFrames(records, options = {}) {
|
|
|
2158
2158
|
const bytes = toBytes(record);
|
|
2159
2159
|
if (bytes.length === 0) {
|
|
2160
2160
|
throw new AstmFrameEncodeError(
|
|
2161
|
-
"Cannot frame an empty record
|
|
2161
|
+
"Cannot frame an empty record: a frame must carry record bytes.",
|
|
2162
2162
|
recordIndex
|
|
2163
2163
|
);
|
|
2164
2164
|
}
|
|
@@ -2197,7 +2197,7 @@ function concatBytes3(chunks) {
|
|
|
2197
2197
|
}
|
|
2198
2198
|
|
|
2199
2199
|
// src/index.ts
|
|
2200
|
-
var VERSION = "0.0.
|
|
2200
|
+
var VERSION = "0.0.5";
|
|
2201
2201
|
|
|
2202
2202
|
export { ALL_ASTM_WARNING_CODES, AMBIGUOUS_CODES, ACK as ASTM_ACK, ENQ as ASTM_ENQ, EOT as ASTM_EOT, NAK as ASTM_NAK, AstmAmbiguousStreamError, AstmFrameEncodeError, AstmFrameStrictError, AstmParseError, AstmProfileDefinitionError, AstmSerializeError, AstmStrictError, CANONICAL_DELIMITERS, FATAL_CODES, FRAME_WARNING_CODES, LIVD_WARNING_CODES, LTP_WARNING_CODES, SAFETY_CRITICAL_CODES, TOLERABLE_CODES, VERSION, WARNING_CODES, ambiguousMessageKind, ambiguousValueSplit, applyAstmProfile, applyAstmProfileToWarnings, applyLivd, astmDateToLocalISO, astmProfiles, attachComments, buildAstmMessage, classifyMessage, comments, commentsFor, composeAstmFrames, computeChecksum, decodeAstmFrames, decodeEscapes, deepFreeze, defineAstmProfile, defineLivdCatalog, delimitersRedeclared, detectFraming, encodeComponent, fieldScalar, frameBadChecksum, frameOversize, frameSequenceGap, frameUnterminated, getAstmProfile, getDefaultAstmProfile, 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, readDelimiters, recognizeUniversalTestId, resolveProfileTransport, results, serializeAstmRecord, serializeAstmRecords, serializeField, serializeFramedAstm, setDefaultAstmProfile, splitEscapeAware, toChecksumHex, tokenizeHeader, tokenizeRecord, undefinedAbnormalFlag, undefinedResultStatus, uninterpretedQueryStatus, unitsAbsent, unknownEscapeSequence, unknownRecordType, unparseableReferenceRange, unreadableRedeclaration };
|
|
2203
2203
|
//# sourceMappingURL=index.mjs.map
|