@cosyte/dicom 0.0.16 → 0.0.18
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 +357 -0
- package/README.md +4 -2
- package/dist/index.cjs +163 -91
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +258 -121
- package/dist/index.d.ts +258 -121
- package/dist/index.mjs +163 -92
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/index.d.cts
CHANGED
|
@@ -184,6 +184,220 @@ declare namespace index {
|
|
|
184
184
|
export { type index_DictionaryEntry as DictionaryEntry, type index_Tag as Tag, type index_UidEntry as UidEntry, type index_VR as VR, index_byKeyword as byKeyword, index_lookup as lookup, index_uid as uid };
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
+
/**
|
|
188
|
+
* Fatal error taxonomy for the `@cosyte/dicom` parser pipeline.
|
|
189
|
+
*
|
|
190
|
+
* Phase 2 core-parser context:
|
|
191
|
+
* - D-09 - `FATAL_CODES` is a frozen `as const` registry with EXACTLY
|
|
192
|
+
* four codes; anything less severe MUST be a Tier-2 warning.
|
|
193
|
+
* - D-10 - `DicomParseError` carries `code`, `byteOffset`, `offsetFrame`,
|
|
194
|
+
* `snippet` (up to 16 source bytes, space-separated lowercase hex), and
|
|
195
|
+
* an optional `contextPath`. The thrown `Error.message` is formatted
|
|
196
|
+
* `[CODE] msg (offset=N frame=F)` with `… in path/segments` appended when
|
|
197
|
+
* `contextPath` is provided.
|
|
198
|
+
*
|
|
199
|
+
* @module
|
|
200
|
+
*/
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Stable string codes for every Tier-3 fatal the parser may throw.
|
|
204
|
+
*
|
|
205
|
+
* Locked at four codes per `PROJECT.md` "Fatal errors only for unrecoverable
|
|
206
|
+
* structural corruption": anything less severe MUST be a Tier-2 warning
|
|
207
|
+
* (see `./warnings.ts`). Consumers narrow on `err.code` to react to
|
|
208
|
+
* specific structural failures.
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* ```ts
|
|
212
|
+
* import { parseDicom, FATAL_CODES, DicomParseError } from "@cosyte/dicom";
|
|
213
|
+
* try {
|
|
214
|
+
* parseDicom(Buffer.alloc(0));
|
|
215
|
+
* } catch (err) {
|
|
216
|
+
* if (err instanceof DicomParseError && err.code === FATAL_CODES.EMPTY_INPUT) {
|
|
217
|
+
* // handle empty input
|
|
218
|
+
* }
|
|
219
|
+
* }
|
|
220
|
+
* ```
|
|
221
|
+
*/
|
|
222
|
+
declare const FATAL_CODES: {
|
|
223
|
+
readonly NOT_DICOM_PART_10: "NOT_DICOM_PART_10";
|
|
224
|
+
readonly INVALID_FILE_META: "INVALID_FILE_META";
|
|
225
|
+
readonly UNSUPPORTED_TRANSFER_SYNTAX: "UNSUPPORTED_TRANSFER_SYNTAX";
|
|
226
|
+
readonly EMPTY_INPUT: "EMPTY_INPUT";
|
|
227
|
+
};
|
|
228
|
+
/**
|
|
229
|
+
* Discriminant type for `DicomParseError.code`. Narrowing a caught error
|
|
230
|
+
* by this code lets consumers write exhaustive `switch` blocks (enabled
|
|
231
|
+
* by the `switch-exhaustiveness-check` lint rule) and guarantees a
|
|
232
|
+
* typo-free comparison against the `FATAL_CODES` registry.
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* ```ts
|
|
236
|
+
* import type { FatalCode } from "@cosyte/dicom";
|
|
237
|
+
* function describe(code: FatalCode): string {
|
|
238
|
+
* switch (code) {
|
|
239
|
+
* case "EMPTY_INPUT":
|
|
240
|
+
* return "input was empty";
|
|
241
|
+
* case "NOT_DICOM_PART_10":
|
|
242
|
+
* return "input is not a DICOM Part 10 file";
|
|
243
|
+
* case "INVALID_FILE_META":
|
|
244
|
+
* return "File Meta group is missing or malformed";
|
|
245
|
+
* case "UNSUPPORTED_TRANSFER_SYNTAX":
|
|
246
|
+
* return "Transfer Syntax UID is not supported by v1";
|
|
247
|
+
* }
|
|
248
|
+
* }
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
251
|
+
type FatalCode = (typeof FATAL_CODES)[keyof typeof FATAL_CODES];
|
|
252
|
+
/**
|
|
253
|
+
* The coordinate systems a `byteOffset` this parser publishes can be counted
|
|
254
|
+
* in.
|
|
255
|
+
*
|
|
256
|
+
* A byte offset is a number and a number alone says nothing about where its
|
|
257
|
+
* zero is. This parser reads a Data Set out of three different buffers over one
|
|
258
|
+
* `parseDicom` call, so the same small integer means three different things
|
|
259
|
+
* depending on which one is being read - and until `DICOM-DIAGNOSTIC-PHI-
|
|
260
|
+
* RESIDUALS` closed it, nothing on the thrown error said which. A consumer
|
|
261
|
+
* cutting `input.subarray(err.byteOffset, err.byteOffset + 16)` to see what
|
|
262
|
+
* upset the parser was, inside a Sequence Item, cutting an unrelated element -
|
|
263
|
+
* the exact defect the `{ strict: true }` snippet itself was fixed for in
|
|
264
|
+
* `#80`.
|
|
265
|
+
*
|
|
266
|
+
* **A frame NAME is published; a frame ORIGIN is not, and that asymmetry is
|
|
267
|
+
* deliberate.** The name is drawn from the closed set below, which the parser
|
|
268
|
+
* chooses and no sender can influence, and that membership is the whole of its
|
|
269
|
+
* bound. An origin has no such table: it is a position reached by summing the
|
|
270
|
+
* declared lengths that led to it, so two of them differ by a wire field, and a
|
|
271
|
+
* message that already publishes `byteOffset` would be one number short of
|
|
272
|
+
* one. **That is a weaker argument than an impossibility and is stated as
|
|
273
|
+
* weaker**, since the library publishes positions freely in the `"input"`
|
|
274
|
+
* frame; a graded pass said so. The item asked for the frame to be NAMED, and
|
|
275
|
+
* nothing here needs the origin, so the cheap side of the trade is taken.
|
|
276
|
+
*
|
|
277
|
+
* @example
|
|
278
|
+
* ```ts
|
|
279
|
+
* import { parseDicom, DicomParseError, OFFSET_FRAMES } from "@cosyte/dicom";
|
|
280
|
+
* try {
|
|
281
|
+
* parseDicom(buffer);
|
|
282
|
+
* } catch (err) {
|
|
283
|
+
* if (err instanceof DicomParseError && err.offsetFrame === OFFSET_FRAMES.INPUT) {
|
|
284
|
+
* // Only here is `err.byteOffset` an index into the buffer you passed in.
|
|
285
|
+
* console.error(buffer.subarray(err.byteOffset, err.byteOffset + 16));
|
|
286
|
+
* }
|
|
287
|
+
* }
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
290
|
+
declare const OFFSET_FRAMES: {
|
|
291
|
+
/**
|
|
292
|
+
* Byte 0 is byte 0 of the buffer handed to `parseDicom`. The only frame in
|
|
293
|
+
* which indexing the caller's own input by `byteOffset` is meaningful.
|
|
294
|
+
*/
|
|
295
|
+
readonly INPUT: "input";
|
|
296
|
+
/**
|
|
297
|
+
* Byte 0 is byte 0 of the inflated Data Set of a Deflated Explicit VR LE
|
|
298
|
+
* object (`1.2.840.10008.1.2.1.99`). The compressed input holds no such
|
|
299
|
+
* byte, so the offset does not index it at any scale.
|
|
300
|
+
*/
|
|
301
|
+
readonly INFLATED_DATASET: "inflated-dataset";
|
|
302
|
+
/**
|
|
303
|
+
* Byte 0 is byte 0 of a slice this parser cut from inside a Value Field: a
|
|
304
|
+
* defined-length Sequence Item's value, or an `SQ`/`UN` value handed to a
|
|
305
|
+
* descent. **Where that slice begins is deliberately not published** - see
|
|
306
|
+
* this table's own note.
|
|
307
|
+
*/
|
|
308
|
+
readonly VALUE_SLICE: "value-slice";
|
|
309
|
+
};
|
|
310
|
+
/**
|
|
311
|
+
* The frame a `DicomParseError.byteOffset` is counted in. See
|
|
312
|
+
* {@link OFFSET_FRAMES}.
|
|
313
|
+
*
|
|
314
|
+
* @example
|
|
315
|
+
* ```ts
|
|
316
|
+
* import type { OffsetFrame } from "@cosyte/dicom";
|
|
317
|
+
* function indexable(frame: OffsetFrame): boolean {
|
|
318
|
+
* // Only the root frame's offsets index the buffer the caller passed in.
|
|
319
|
+
* switch (frame) {
|
|
320
|
+
* case "input":
|
|
321
|
+
* return true;
|
|
322
|
+
* case "inflated-dataset":
|
|
323
|
+
* case "value-slice":
|
|
324
|
+
* return false;
|
|
325
|
+
* }
|
|
326
|
+
* }
|
|
327
|
+
* ```
|
|
328
|
+
*/
|
|
329
|
+
type OffsetFrame = (typeof OFFSET_FRAMES)[keyof typeof OFFSET_FRAMES];
|
|
330
|
+
/**
|
|
331
|
+
* Thrown by `parseDicom` when the input violates one of the four
|
|
332
|
+
* unrecoverable Tier-3 structural rules - or, under `{ strict: true }`,
|
|
333
|
+
* when any Tier-2 warning is escalated through the single `emit`
|
|
334
|
+
* chokepoint (D-35). Carries byte-offset positional context plus a short
|
|
335
|
+
* source snippet so consumers can log actionable errors.
|
|
336
|
+
*
|
|
337
|
+
* Message format: `[CODE] msg (offset=N frame=F)`, with `… in a/b/c`
|
|
338
|
+
* appended when `contextPath` is provided.
|
|
339
|
+
*
|
|
340
|
+
* @remarks
|
|
341
|
+
* Snippets may contain PHI when parsing real clinical files - redact at
|
|
342
|
+
* the call site if required by your compliance posture. The library does
|
|
343
|
+
* not redact snippets itself.
|
|
344
|
+
*
|
|
345
|
+
* **`byteOffset` is only an index into your own buffer when `offsetFrame` is
|
|
346
|
+
* `"input"`.** This parser reads a Data Set out of a slice in two situations -
|
|
347
|
+
* a defined-length Sequence Item, and an `SQ`/`UN` descent - and out of an
|
|
348
|
+
* inflated stream in a third, and an offset raised in any of them counts from
|
|
349
|
+
* that buffer's byte 0. {@link OFFSET_FRAMES} names which; where a slice
|
|
350
|
+
* begins is deliberately not published, because the distance between two
|
|
351
|
+
* frames is a declared length off the wire.
|
|
352
|
+
*
|
|
353
|
+
* **`snippet` is cut in the frame `offsetFrame` names, on every fatal but one.**
|
|
354
|
+
* The exception is `UNSUPPORTED_TRANSFER_SYNTAX`, whose snippet slot carries
|
|
355
|
+
* PS3.6's own NAME for the unsupported UID when the registry publishes one
|
|
356
|
+
* (`"RLE Lossless"`), and 16 raw bytes only when it does not. That is
|
|
357
|
+
* deliberate and predates the frame; it is named here because a universal about
|
|
358
|
+
* `snippet` written without it is false on the code a compressed object reaches
|
|
359
|
+
* first. Everywhere else the two agree, so a consumer that only wants the bytes
|
|
360
|
+
* at the offset already has them. **The frame is what a consumer needs before
|
|
361
|
+
* indexing anything of its OWN by `byteOffset`**, which is the case no field on
|
|
362
|
+
* this class used to cover.
|
|
363
|
+
*
|
|
364
|
+
* @example
|
|
365
|
+
* ```ts
|
|
366
|
+
* import { parseDicom, DicomParseError, OFFSET_FRAMES } from "@cosyte/dicom";
|
|
367
|
+
* try {
|
|
368
|
+
* parseDicom(buffer);
|
|
369
|
+
* } catch (err) {
|
|
370
|
+
* if (err instanceof DicomParseError && err.code === "NOT_DICOM_PART_10") {
|
|
371
|
+
* // err.byteOffset, err.offsetFrame, err.snippet, err.contextPath
|
|
372
|
+
* if (err.offsetFrame !== OFFSET_FRAMES.INPUT) {
|
|
373
|
+
* // `byteOffset` counts from somewhere inside the file, not from its start.
|
|
374
|
+
* }
|
|
375
|
+
* }
|
|
376
|
+
* }
|
|
377
|
+
* ```
|
|
378
|
+
*/
|
|
379
|
+
declare class DicomParseError extends Error {
|
|
380
|
+
readonly code: FatalCode;
|
|
381
|
+
readonly byteOffset: number;
|
|
382
|
+
/**
|
|
383
|
+
* The coordinate system {@link DicomParseError.byteOffset} is counted in.
|
|
384
|
+
* See {@link OFFSET_FRAMES}.
|
|
385
|
+
*/
|
|
386
|
+
readonly offsetFrame: OffsetFrame;
|
|
387
|
+
readonly snippet: string;
|
|
388
|
+
readonly contextPath: readonly string[] | undefined;
|
|
389
|
+
/**
|
|
390
|
+
* Construct a new `DicomParseError`. All fields except `contextPath` are
|
|
391
|
+
* required so every thrower populates positional context per `TOL-02` - and
|
|
392
|
+
* `offsetFrame` is required for the same reason `byteOffset` is, because an
|
|
393
|
+
* offset whose frame is optional is an offset whose frame is usually
|
|
394
|
+
* missing.
|
|
395
|
+
*
|
|
396
|
+
* @internal
|
|
397
|
+
*/
|
|
398
|
+
constructor(code: FatalCode, message: string, byteOffset: number, offsetFrame: OffsetFrame, snippet: string, contextPath?: readonly string[]);
|
|
399
|
+
}
|
|
400
|
+
|
|
187
401
|
/**
|
|
188
402
|
* Shared parser-pipeline types for `@cosyte/dicom`.
|
|
189
403
|
*
|
|
@@ -263,10 +477,21 @@ interface Profile {
|
|
|
263
477
|
/**
|
|
264
478
|
* Positional context for a `DicomParseWarning` or `DicomParseError`.
|
|
265
479
|
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
* `deflated: true`
|
|
269
|
-
*
|
|
480
|
+
* **🛑 `byteOffset` IS NOT ALWAYS RELATIVE TO THE SOURCE BUFFER, AND THIS
|
|
481
|
+
* JSDOC SAID IT WAS.** For the Deflated Explicit VR LE transfer syntax (D-27),
|
|
482
|
+
* `deflated: true` says the offset indexes the inflated dataset buffer rather
|
|
483
|
+
* than the on-disk source. That flag is the only frame this type carries, and
|
|
484
|
+
* it is not the only frame this parser has: a defined-length Sequence Item is
|
|
485
|
+
* parsed from a **slice**, so a warning raised inside one carries an
|
|
486
|
+
* item-relative offset with nothing on the position to say so. The same is true
|
|
487
|
+
* of `Element.byteOffset`, and has been since the parser was written.
|
|
488
|
+
*
|
|
489
|
+
* **The residual is `PRE-EXISTING` and is not closed here.** What is closed is
|
|
490
|
+
* the thrown side: `DicomParseError.offsetFrame` names the coordinate system
|
|
491
|
+
* from a closed set (see `OFFSET_FRAMES`), and that covers a Tier-3 fatal and
|
|
492
|
+
* the `{ strict: true }` escalation of a Tier-2 warning. It does not reach a
|
|
493
|
+
* warning on the lenient path, which is this type. Do not read the fatal's
|
|
494
|
+
* frame contract as one this type has.
|
|
270
495
|
*
|
|
271
496
|
* With `exactOptionalPropertyTypes: true`, callers should omit unset keys
|
|
272
497
|
* rather than passing `undefined` (mirrors `@cosyte/hl7` sibling discipline).
|
|
@@ -356,8 +581,8 @@ interface ParseOptions {
|
|
|
356
581
|
* carries `snippet`,
|
|
357
582
|
* **16 raw bytes, unredacted** (D-10), read at the warning's own `byteOffset`.
|
|
358
583
|
* A message-only PHI review of the lenient path therefore does not transfer to
|
|
359
|
-
* the strict one. Log `err.code`, `err.byteOffset
|
|
360
|
-
* `err.snippet` as PHI.
|
|
584
|
+
* the strict one. Log `err.code`, `err.byteOffset`, `err.offsetFrame` and
|
|
585
|
+
* `err.message`; treat `err.snippet` as PHI.
|
|
361
586
|
*
|
|
362
587
|
* **The snippet is cut in the SAME FRAME the `byteOffset` is counted in**, so
|
|
363
588
|
* it is the bytes at the offset the diagnostic names: file-absolute at the
|
|
@@ -372,9 +597,15 @@ interface ParseOptions {
|
|
|
372
597
|
* message beside them is registry-bound is the mistake this whole paragraph
|
|
373
598
|
* exists to prevent.
|
|
374
599
|
*
|
|
375
|
-
* **`byteOffset`
|
|
376
|
-
*
|
|
377
|
-
*
|
|
600
|
+
* **`byteOffset` NOW CARRIES A FRAME-OF-REFERENCE CONTRACT, AND IT IS A NAME
|
|
601
|
+
* AND NOT AN ORIGIN.** `err.offsetFrame` says which of three coordinate
|
|
602
|
+
* systems the number is counted in (`OFFSET_FRAMES`), so a consumer can tell a
|
|
603
|
+
* root offset from an Item-relative one instead of guessing. **A nested offset
|
|
604
|
+
* is still not a key you can look up against the root**, and it is not made
|
|
605
|
+
* into one here: where a slice begins is deliberately unpublished, because the
|
|
606
|
+
* distance between two frames is a declared Value Length off the wire. The
|
|
607
|
+
* escalated warning's own `position` is unchanged and still carries no frame
|
|
608
|
+
* beyond `deflated` - see `DicomPosition`.
|
|
378
609
|
*
|
|
379
610
|
* Omit (do not pass `undefined`) to use the default.
|
|
380
611
|
*/
|
|
@@ -491,6 +722,7 @@ declare const WARNING_CODES: {
|
|
|
491
722
|
readonly DICOM_DEIDENT_METHOD_NOT_ADDED: "DICOM_DEIDENT_METHOD_NOT_ADDED";
|
|
492
723
|
readonly DICOM_DEIDENT_METHOD_NOT_LO: "DICOM_DEIDENT_METHOD_NOT_LO";
|
|
493
724
|
readonly DICOM_DEIDENT_METHOD_PRIOR_RETAINED: "DICOM_DEIDENT_METHOD_PRIOR_RETAINED";
|
|
725
|
+
readonly DICOM_DEIDENT_METHOD_VALUE_OVER_LENGTH: "DICOM_DEIDENT_METHOD_VALUE_OVER_LENGTH";
|
|
494
726
|
readonly DICOM_DEIDENT_SEQUENCE_NOT_AUDITABLE: "DICOM_DEIDENT_SEQUENCE_NOT_AUDITABLE";
|
|
495
727
|
readonly DICOM_DEIDENT_UNDEFINED_VR_NOT_AUDITABLE: "DICOM_DEIDENT_UNDEFINED_VR_NOT_AUDITABLE";
|
|
496
728
|
readonly DICOM_PRIVATE_CREATOR_UNKNOWN: "DICOM_PRIVATE_CREATOR_UNKNOWN";
|
|
@@ -1549,112 +1781,6 @@ declare class Sequence {
|
|
|
1549
1781
|
constructor(items: readonly Item[], length: number);
|
|
1550
1782
|
}
|
|
1551
1783
|
|
|
1552
|
-
/**
|
|
1553
|
-
* Fatal error taxonomy for the `@cosyte/dicom` parser pipeline.
|
|
1554
|
-
*
|
|
1555
|
-
* Phase 2 core-parser context:
|
|
1556
|
-
* - D-09 - `FATAL_CODES` is a frozen `as const` registry with EXACTLY
|
|
1557
|
-
* four codes; anything less severe MUST be a Tier-2 warning.
|
|
1558
|
-
* - D-10 - `DicomParseError` carries `code`, `byteOffset`, `snippet`
|
|
1559
|
-
* (up to 16 source bytes, space-separated lowercase hex), and an
|
|
1560
|
-
* optional `contextPath`. The thrown `Error.message` is formatted
|
|
1561
|
-
* `[CODE] msg (offset=N)` with `… in path/segments` appended when
|
|
1562
|
-
* `contextPath` is provided.
|
|
1563
|
-
*
|
|
1564
|
-
* @module
|
|
1565
|
-
*/
|
|
1566
|
-
|
|
1567
|
-
/**
|
|
1568
|
-
* Stable string codes for every Tier-3 fatal the parser may throw.
|
|
1569
|
-
*
|
|
1570
|
-
* Locked at four codes per `PROJECT.md` "Fatal errors only for unrecoverable
|
|
1571
|
-
* structural corruption": anything less severe MUST be a Tier-2 warning
|
|
1572
|
-
* (see `./warnings.ts`). Consumers narrow on `err.code` to react to
|
|
1573
|
-
* specific structural failures.
|
|
1574
|
-
*
|
|
1575
|
-
* @example
|
|
1576
|
-
* ```ts
|
|
1577
|
-
* import { parseDicom, FATAL_CODES, DicomParseError } from "@cosyte/dicom";
|
|
1578
|
-
* try {
|
|
1579
|
-
* parseDicom(Buffer.alloc(0));
|
|
1580
|
-
* } catch (err) {
|
|
1581
|
-
* if (err instanceof DicomParseError && err.code === FATAL_CODES.EMPTY_INPUT) {
|
|
1582
|
-
* // handle empty input
|
|
1583
|
-
* }
|
|
1584
|
-
* }
|
|
1585
|
-
* ```
|
|
1586
|
-
*/
|
|
1587
|
-
declare const FATAL_CODES: {
|
|
1588
|
-
readonly NOT_DICOM_PART_10: "NOT_DICOM_PART_10";
|
|
1589
|
-
readonly INVALID_FILE_META: "INVALID_FILE_META";
|
|
1590
|
-
readonly UNSUPPORTED_TRANSFER_SYNTAX: "UNSUPPORTED_TRANSFER_SYNTAX";
|
|
1591
|
-
readonly EMPTY_INPUT: "EMPTY_INPUT";
|
|
1592
|
-
};
|
|
1593
|
-
/**
|
|
1594
|
-
* Discriminant type for `DicomParseError.code`. Narrowing a caught error
|
|
1595
|
-
* by this code lets consumers write exhaustive `switch` blocks (enabled
|
|
1596
|
-
* by the `switch-exhaustiveness-check` lint rule) and guarantees a
|
|
1597
|
-
* typo-free comparison against the `FATAL_CODES` registry.
|
|
1598
|
-
*
|
|
1599
|
-
* @example
|
|
1600
|
-
* ```ts
|
|
1601
|
-
* import type { FatalCode } from "@cosyte/dicom";
|
|
1602
|
-
* function describe(code: FatalCode): string {
|
|
1603
|
-
* switch (code) {
|
|
1604
|
-
* case "EMPTY_INPUT":
|
|
1605
|
-
* return "input was empty";
|
|
1606
|
-
* case "NOT_DICOM_PART_10":
|
|
1607
|
-
* return "input is not a DICOM Part 10 file";
|
|
1608
|
-
* case "INVALID_FILE_META":
|
|
1609
|
-
* return "File Meta group is missing or malformed";
|
|
1610
|
-
* case "UNSUPPORTED_TRANSFER_SYNTAX":
|
|
1611
|
-
* return "Transfer Syntax UID is not supported by v1";
|
|
1612
|
-
* }
|
|
1613
|
-
* }
|
|
1614
|
-
* ```
|
|
1615
|
-
*/
|
|
1616
|
-
type FatalCode = (typeof FATAL_CODES)[keyof typeof FATAL_CODES];
|
|
1617
|
-
/**
|
|
1618
|
-
* Thrown by `parseDicom` when the input violates one of the four
|
|
1619
|
-
* unrecoverable Tier-3 structural rules - or, under `{ strict: true }`,
|
|
1620
|
-
* when any Tier-2 warning is escalated through the single `emit`
|
|
1621
|
-
* chokepoint (D-35). Carries byte-offset positional context plus a short
|
|
1622
|
-
* source snippet so consumers can log actionable errors.
|
|
1623
|
-
*
|
|
1624
|
-
* Message format: `[CODE] msg (offset=N)`, with `… in a/b/c` appended
|
|
1625
|
-
* when `contextPath` is provided.
|
|
1626
|
-
*
|
|
1627
|
-
* @remarks
|
|
1628
|
-
* Snippets may contain PHI when parsing real clinical files - redact at
|
|
1629
|
-
* the call site if required by your compliance posture. The library does
|
|
1630
|
-
* not redact snippets itself.
|
|
1631
|
-
*
|
|
1632
|
-
* @example
|
|
1633
|
-
* ```ts
|
|
1634
|
-
* import { parseDicom, DicomParseError } from "@cosyte/dicom";
|
|
1635
|
-
* try {
|
|
1636
|
-
* parseDicom(buffer);
|
|
1637
|
-
* } catch (err) {
|
|
1638
|
-
* if (err instanceof DicomParseError && err.code === "NOT_DICOM_PART_10") {
|
|
1639
|
-
* // err.byteOffset, err.snippet, err.contextPath all available
|
|
1640
|
-
* }
|
|
1641
|
-
* }
|
|
1642
|
-
* ```
|
|
1643
|
-
*/
|
|
1644
|
-
declare class DicomParseError extends Error {
|
|
1645
|
-
readonly code: FatalCode;
|
|
1646
|
-
readonly byteOffset: number;
|
|
1647
|
-
readonly snippet: string;
|
|
1648
|
-
readonly contextPath: readonly string[] | undefined;
|
|
1649
|
-
/**
|
|
1650
|
-
* Construct a new `DicomParseError`. All fields except `contextPath` are
|
|
1651
|
-
* required so every thrower populates positional context per `TOL-02`.
|
|
1652
|
-
*
|
|
1653
|
-
* @internal
|
|
1654
|
-
*/
|
|
1655
|
-
constructor(code: FatalCode, message: string, byteOffset: number, snippet: string, contextPath?: readonly string[]);
|
|
1656
|
-
}
|
|
1657
|
-
|
|
1658
1784
|
/**
|
|
1659
1785
|
* VR-aware value dispatch - the body behind `Element.value`.
|
|
1660
1786
|
*
|
|
@@ -2974,10 +3100,19 @@ interface DeidentifyOptions {
|
|
|
2974
3100
|
* legally carry. The Profile name is now one Value of 61 characters and each
|
|
2975
3101
|
* active option is its own, so no option subset can exceed the maximum.
|
|
2976
3102
|
*
|
|
2977
|
-
* **Your string is not bounded here
|
|
2978
|
-
* characters is written through as given
|
|
2979
|
-
* splitting or truncating it would invent a record you did not
|
|
2980
|
-
*
|
|
3103
|
+
* **Your string is not bounded here, but it is no longer silent.** A value of
|
|
3104
|
+
* your own longer than 64 characters is written through as given - it is
|
|
3105
|
+
* yours, and splitting or truncating it would invent a record you did not
|
|
3106
|
+
* write - and `report.warnings` carries
|
|
3107
|
+
* `DICOM_DEIDENT_METHOD_VALUE_OVER_LENGTH` to say so. Split it on `\` yourself
|
|
3108
|
+
* if a strict receiver is in your path. The same code covers an over-long
|
|
3109
|
+
* value the **source file** wrote and this run kept, which in the common case
|
|
3110
|
+
* is this library's own 76-character text from a release before the default
|
|
3111
|
+
* became multi-valued. The measurement is over **bytes**: a Value of 64 bytes
|
|
3112
|
+
* or fewer can never carry more than 64 characters, so it cannot miss one that
|
|
3113
|
+
* is genuinely over, but PS3.5 §6.2 specifies the bound in characters rather
|
|
3114
|
+
* than bytes and excludes Code Extension escape sequences from the count, so it
|
|
3115
|
+
* raises on any conformant Value whose bytes outnumber its counted characters.
|
|
2981
3116
|
*
|
|
2982
3117
|
* PS3.15 E.1.1 says this string is "inserted in or added to" the attribute, so
|
|
2983
3118
|
* a value the incoming Data Set already carried is kept and this one is
|
|
@@ -3016,7 +3151,9 @@ interface DeidentifyOptions {
|
|
|
3016
3151
|
* When the prior value **is** kept, `report.warnings` carries
|
|
3017
3152
|
* `DICOM_DEIDENT_METHOD_PRIOR_RETAINED`: `(0012,0063)` is not in Table E.1-1, so
|
|
3018
3153
|
* nothing in the run inspected or redacted those bytes, and a name a sender
|
|
3019
|
-
* wrote there is in output stamped `(0012,0062) = YES`.
|
|
3154
|
+
* wrote there is in output stamped `(0012,0062) = YES`. That code discloses the
|
|
3155
|
+
* **retention** only; the **length** of what is written, from whatever source,
|
|
3156
|
+
* is disclosed by `DICOM_DEIDENT_METHOD_VALUE_OVER_LENGTH` and by nothing else.
|
|
3020
3157
|
*/
|
|
3021
3158
|
readonly deidentificationMethod?: string;
|
|
3022
3159
|
}
|
|
@@ -3314,4 +3451,4 @@ interface UidRemapper {
|
|
|
3314
3451
|
*/
|
|
3315
3452
|
declare function makeUidRemapper(root?: string, cache?: Map<string, string>): UidRemapper;
|
|
3316
3453
|
|
|
3317
|
-
export { type AppliedAction, CODING_SCHEME_OIDS, type CodedConcept, DEFAULT_UID_ROOT, DEIDENTIFY_ERROR_CODES, DEIDENTIFY_OPTIONS, Dataset, type DefineProfileOptions, type DeidentifiedAttribute, DeidentifyError, type DeidentifyErrorCode, type DeidentifyOption, type DeidentifyOptions, type DeidentifyReport, type DeidentifyResult, type DicomDate, type DicomDateTime, DicomParseError, type DicomParseWarning, type DicomPosition, DicomSerializeError, type DicomTime, type DicomValue, DicomValueError, index as Dictionary, Element, type EmbeddedAttributeFinding, FATAL_CODES, type FatalCode, type FileMeta, type FileMetaRawElement, type FrameFunctionalGroups, type ImageView, Item, type OnWarningCallback, type OtherPatientId, type ParseOptions, type PatientView, type PersonName, type PersonNameGroup, type PrivateTagDefinition, type Profile, ProfileDefinitionError, type ProfilePrivateTags, type RealWorldValueMap, SERIALIZE_ERROR_CODES, Sequence, type SerializeErrorCode, type SeriesView, type StudyView, type UidRemapper, type UnauditableSequenceFinding, type UndefinedVrFinding, VALUE_ERROR_CODES, VERSION, type ValueErrorCode, WARNING_CODES, type WarningCode, codingSchemeOid, decodeElementValue, decodeText, defineProfile, deidentify, isKnownCharsetTerm, makeUidRemapper, parseDate, parseDateTime, parseDicom, parsePersonName, parseSpecificCharacterSet, parseTime, profiles, readCode, resolveDecoderLabel, serializeDicom };
|
|
3454
|
+
export { type AppliedAction, CODING_SCHEME_OIDS, type CodedConcept, DEFAULT_UID_ROOT, DEIDENTIFY_ERROR_CODES, DEIDENTIFY_OPTIONS, Dataset, type DefineProfileOptions, type DeidentifiedAttribute, DeidentifyError, type DeidentifyErrorCode, type DeidentifyOption, type DeidentifyOptions, type DeidentifyReport, type DeidentifyResult, type DicomDate, type DicomDateTime, DicomParseError, type DicomParseWarning, type DicomPosition, DicomSerializeError, type DicomTime, type DicomValue, DicomValueError, index as Dictionary, Element, type EmbeddedAttributeFinding, FATAL_CODES, type FatalCode, type FileMeta, type FileMetaRawElement, type FrameFunctionalGroups, type ImageView, Item, OFFSET_FRAMES, type OffsetFrame, type OnWarningCallback, type OtherPatientId, type ParseOptions, type PatientView, type PersonName, type PersonNameGroup, type PrivateTagDefinition, type Profile, ProfileDefinitionError, type ProfilePrivateTags, type RealWorldValueMap, SERIALIZE_ERROR_CODES, Sequence, type SerializeErrorCode, type SeriesView, type StudyView, type UidRemapper, type UnauditableSequenceFinding, type UndefinedVrFinding, VALUE_ERROR_CODES, VERSION, type ValueErrorCode, WARNING_CODES, type WarningCode, codingSchemeOid, decodeElementValue, decodeText, defineProfile, deidentify, isKnownCharsetTerm, makeUidRemapper, parseDate, parseDateTime, parseDicom, parsePersonName, parseSpecificCharacterSet, parseTime, profiles, readCode, resolveDecoderLabel, serializeDicom };
|