@cosyte/dicom 0.0.13 → 0.0.15
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 +458 -0
- package/README.md +6 -4
- package/dist/index.cjs +120 -90
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +126 -28
- package/dist/index.d.ts +126 -28
- package/dist/index.mjs +120 -90
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -114,6 +114,18 @@ interface UidEntry {
|
|
|
114
114
|
* throw `TypeError` in strict mode (which all of `@cosyte/dicom`'s emitted code
|
|
115
115
|
* runs under, given `"use strict"` is implicit for ES modules).
|
|
116
116
|
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```ts
|
|
119
|
+
* import { Dictionary } from "@cosyte/dicom";
|
|
120
|
+
*
|
|
121
|
+
* // Tag or keyword, either way round, and `undefined` rather than a throw on a miss.
|
|
122
|
+
* Dictionary.lookup("00100020")?.name; // "Patient ID"
|
|
123
|
+
* Dictionary.byKeyword("Modality")?.tag; // "00080060"
|
|
124
|
+
*
|
|
125
|
+
* // UIDs resolve to their registered name, so nobody hard-codes a SOP Class table.
|
|
126
|
+
* Dictionary.uid("1.2.840.10008.5.1.4.1.1.2")?.name; // "CT Image Storage"
|
|
127
|
+
* ```
|
|
128
|
+
*
|
|
117
129
|
* @module
|
|
118
130
|
*/
|
|
119
131
|
|
|
@@ -317,8 +329,31 @@ interface ParseOptions {
|
|
|
317
329
|
*
|
|
318
330
|
* 🛑 **THE ESCALATED DIAGNOSTIC CARRIES SOURCE BYTES THAT THE WARNING DOES
|
|
319
331
|
* NOT.** A `DicomParseWarning.message` is a frozen registry string with only
|
|
320
|
-
* structural tokens filled in
|
|
321
|
-
* `
|
|
332
|
+
* structural tokens filled in: `{tag}` renders only a tag PS3.6's element
|
|
333
|
+
* registry carries a literal row for, `{vr}` only one of the 34 VRs PS3.5
|
|
334
|
+
* section 6.2 defines, and a raw length or byte value a header carries is
|
|
335
|
+
* bound out of the factory signature rather than rendered. That now holds on
|
|
336
|
+
* the `deidentify()` codes too:
|
|
337
|
+
* `DICOM_DEIDENT_UNDEFINED_VR_NOT_AUDITABLE` and
|
|
338
|
+
* `DICOM_DEIDENT_SEQUENCE_NOT_AUDITABLE` rendered `Element.rawBytes.length`
|
|
339
|
+
* through `0.0.14`, which equals the declared Value Length and was reachable
|
|
340
|
+
* from a fabricated header, and both slots are gone. So is
|
|
341
|
+
* `DICOM_ITEM_CROSSES_SEQUENCE_END`'s remaining-bytes count, because **a raw
|
|
342
|
+
* number shifted by a constant the reader can compute is that raw number**: it
|
|
343
|
+
* was the enclosing sequence's declared Value Length less the bytes of that
|
|
344
|
+
* sequence already consumed. **The exceptions are named in one place that is
|
|
345
|
+
* not a record of a past change, and are deliberately not restated here** -
|
|
346
|
+
* the `WARNING_MESSAGES` docblock in `./warnings.ts`, which this JSDoc used to
|
|
347
|
+
* carry a copy of.
|
|
348
|
+
* **This is a statement about `w.message` and about nothing else**: the two
|
|
349
|
+
* byte counts still exist on `report.undefinedVrElements[].byteLength` and
|
|
350
|
+
* `report.unauditableSequences[].byteLength`, model fields on a type whose own
|
|
351
|
+
* docs say it is not a value-free surface. **No
|
|
352
|
+
* safe-to-log verdict is stated here** - that sentence was corrected twice and
|
|
353
|
+
* is deleted rather than tried a third time; the mechanism is above and the
|
|
354
|
+
* treatment is in the package's troubleshooting docs. The `DicomParseError`
|
|
355
|
+
* this option raises in its place is a different and larger surface: it also
|
|
356
|
+
* carries `snippet`,
|
|
322
357
|
* **16 raw bytes, unredacted** (D-10), read at the warning's own `byteOffset`.
|
|
323
358
|
* A message-only PHI review of the lenient path therefore does not transfer to
|
|
324
359
|
* the strict one. Log `err.code`, `err.byteOffset` and `err.message`; treat
|
|
@@ -921,6 +956,21 @@ declare class Element {
|
|
|
921
956
|
* `(0002,0102)` Private Information - is captured here as raw bytes (the
|
|
922
957
|
* on-wire value, even-length per PS3.5 §6.2) rather than dropped. `value` is a
|
|
923
958
|
* defensive copy, so the view never aliases the parsed input buffer.
|
|
959
|
+
*
|
|
960
|
+
* @example
|
|
961
|
+
* ```ts
|
|
962
|
+
* import { parseDicom } from "@cosyte/dicom";
|
|
963
|
+
* const ds = parseDicom(buf);
|
|
964
|
+
* // Anything the typed FileMeta fields do not model, in ascending tag order.
|
|
965
|
+
* for (const raw of ds.fileMeta?.extraElements ?? []) {
|
|
966
|
+
* raw.tag; // e.g. "00020017" Sending Application Entity Title
|
|
967
|
+
* raw.vr; // the VR the source wrote (File Meta is always Explicit VR LE)
|
|
968
|
+
* raw.value.length; // even, per PS3.5 2026c section 7.1.1
|
|
969
|
+
* }
|
|
970
|
+
* ```
|
|
971
|
+
*
|
|
972
|
+
* `(0002,0016)` Source Application Entity Title is deliberately NOT the example: it is one of the
|
|
973
|
+
* typed fields, so it never reaches this array.
|
|
924
974
|
*/
|
|
925
975
|
interface FileMetaRawElement {
|
|
926
976
|
/** 8-char uppercase hex tag, e.g. `"00020100"`. */
|
|
@@ -2448,15 +2498,29 @@ interface DeidentifiedAttribute {
|
|
|
2448
2498
|
* (PS3.15 §E.1 "all instances"; §E.3.5 is the standard's own precedent for
|
|
2449
2499
|
* removing identifying information embedded inside a string attribute).
|
|
2450
2500
|
*
|
|
2451
|
-
* `tag` and `vr` are the carrier's own and are structural. **`hidden`
|
|
2452
|
-
* and
|
|
2453
|
-
*
|
|
2454
|
-
*
|
|
2455
|
-
*
|
|
2456
|
-
* `
|
|
2457
|
-
*
|
|
2458
|
-
*
|
|
2459
|
-
*
|
|
2501
|
+
* `tag` and `vr` are the carrier's own and are structural. **`hidden` was not,
|
|
2502
|
+
* and it is bound now.** Every tag in an embedded run is composed from four
|
|
2503
|
+
* bytes that were sitting *inside* the carrier's value - that is the whole
|
|
2504
|
+
* reason this type exists - and a run needs only ONE actionable attribute to be
|
|
2505
|
+
* reported, so through `0.0.13` the rest of the run was listed beside it.
|
|
2506
|
+
* Measured: a `CS` carrier over-declaring across a fabricated `"SMIT"` header
|
|
2507
|
+
* beside a genuine `(0010,0020)` reported `hidden: ["4D535449", "00100020"]`,
|
|
2508
|
+
* and `4D535449` is `"SMIT"` in wire order.
|
|
2509
|
+
*
|
|
2510
|
+
* **An entry is now one of the 652 literal rows of PS3.15 Table E.1-1 that this
|
|
2511
|
+
* run's options left actionable.** That is a **membership** bound rather than a
|
|
2512
|
+
* shape one - the posture this package already takes for a VR and for a Private
|
|
2513
|
+
* Creator - so what survives names a published table entry rather than a
|
|
2514
|
+
* document byte, the same trade rendering a VR makes with the 34. **A
|
|
2515
|
+
* repeating-group mask hit is NOT in that set and is excluded**: `(50xx,xxxx)`
|
|
2516
|
+
* Curve Data leaves the whole 16-bit element number free, so a mask match proves
|
|
2517
|
+
* a rule exists without making the membership finite. A graded pass caught a
|
|
2518
|
+
* draft of this filter that admitted it.
|
|
2519
|
+
*
|
|
2520
|
+
* **🛑 THAT IS NOT AN ALL-CLEAR OVER THIS TYPE.** `contextPath` below is
|
|
2521
|
+
* unbound and unchanged, `hidden` is uncapped, and
|
|
2522
|
+
* {@link DeidentifyReport} names the report's other value-bearing fields. A
|
|
2523
|
+
* `DeidentifyReport` is still not safe to log whole.
|
|
2460
2524
|
*
|
|
2461
2525
|
* @example
|
|
2462
2526
|
* ```ts
|
|
@@ -2472,7 +2536,18 @@ interface EmbeddedAttributeFinding {
|
|
|
2472
2536
|
readonly tag: Tag;
|
|
2473
2537
|
/** The carrier's VR. Always one of the string VRs; binary VRs are not scanned. */
|
|
2474
2538
|
readonly vr: VR;
|
|
2475
|
-
/**
|
|
2539
|
+
/**
|
|
2540
|
+
* The tags found inside the carrier's value **that this run acts on and that a
|
|
2541
|
+
* published table names**, in wire order. **Not every tag in the run** - see
|
|
2542
|
+
* this type's own remarks.
|
|
2543
|
+
*
|
|
2544
|
+
* **🩺 IT MAY BE EMPTY, AND EMPTY DOES NOT MEAN "NOTHING WAS HIDDEN HERE".**
|
|
2545
|
+
* A run whose only actionable members are private attributes, Curve Data or
|
|
2546
|
+
* Overlay elements reports a finding with no tags: the carrier was still
|
|
2547
|
+
* emptied, and the accompanying `DICOM_DEIDENT_EMBEDDED_ATTRIBUTE_REMOVED`
|
|
2548
|
+
* warning still counts the whole run. The presence of the finding is the fact;
|
|
2549
|
+
* this list is the part of it that can be named.
|
|
2550
|
+
*/
|
|
2476
2551
|
readonly hidden: readonly Tag[];
|
|
2477
2552
|
/**
|
|
2478
2553
|
* Tag/index chain when the carrier is inside a sequence item; omitted at the
|
|
@@ -2649,12 +2724,21 @@ interface UndefinedVrFinding {
|
|
|
2649
2724
|
*
|
|
2650
2725
|
* **An input-derived count, and on this finding specifically that is not a
|
|
2651
2726
|
* formality.** For the sibling findings the length came from a header the
|
|
2652
|
-
* sender wrote; here the
|
|
2653
|
-
* the tag bytes. What is published is the *number* they decode to,
|
|
2654
|
-
*
|
|
2655
|
-
*
|
|
2656
|
-
*
|
|
2657
|
-
*
|
|
2727
|
+
* sender wrote; here the four length bytes can themselves be value bytes, like
|
|
2728
|
+
* the tag bytes. What is published is the *number* they decode to, and one
|
|
2729
|
+
* `readUInt32LE` puts the bytes back: a fabricated header reading `"SO\0\0"`
|
|
2730
|
+
* publishes `20307`, two letters of a surname. Do not describe this field as
|
|
2731
|
+
* "structural, never a value" the way its siblings are described.
|
|
2732
|
+
*
|
|
2733
|
+
* **🩺 IT IS NO LONGER "the same footing as every `{n}` in the warning
|
|
2734
|
+
* registry", AND THAT SENTENCE WAS THE ONE THIS FIELD SHIPPED WITH.**
|
|
2735
|
+
* `DICOM_DEIDENT_UNDEFINED_VR_NOT_AUDITABLE` rendered exactly this number and
|
|
2736
|
+
* does not any more - it is bound out of `undefinedVrNotAuditable`'s
|
|
2737
|
+
* signature. So this field is now a **model field**, on the same standing
|
|
2738
|
+
* exception as `removedPrivateTags`, `unauditableSequences[].tag`, `uidMap`
|
|
2739
|
+
* and `contextPath`: narrowing it is a product call, because a bound empties
|
|
2740
|
+
* it on every well-formed file, where it is exactly the audit number the field
|
|
2741
|
+
* exists to carry. Deliberately unchanged; see this type's own summary.
|
|
2658
2742
|
*/
|
|
2659
2743
|
readonly byteLength: number;
|
|
2660
2744
|
/**
|
|
@@ -2697,13 +2781,18 @@ interface UndefinedVrFinding {
|
|
|
2697
2781
|
* and still answers it whenever the fabricated VR is outside the 34 PS3.5
|
|
2698
2782
|
* §6.2 defines. It cannot when the fabricated VR is one of them, because those
|
|
2699
2783
|
* two files are byte-identical.
|
|
2700
|
-
* - **`
|
|
2701
|
-
*
|
|
2702
|
-
*
|
|
2703
|
-
*
|
|
2704
|
-
*
|
|
2705
|
-
*
|
|
2706
|
-
*
|
|
2784
|
+
* - **`undefinedVrElements[].byteLength` and
|
|
2785
|
+
* `unauditableSequences[].byteLength`** - the declared Value Length read off
|
|
2786
|
+
* the element header, so on a fabricated header it is four document bytes
|
|
2787
|
+
* wearing a decimal: `"SO\0\0"` publishes `20307`, two letters of a surname,
|
|
2788
|
+
* put back with one `readUInt32LE`. **They JOINED this list rather than
|
|
2789
|
+
* always having been on it.** Through `0.0.14` the two
|
|
2790
|
+
* `DICOM_DEIDENT_*_NOT_AUDITABLE` **messages** rendered the same number;
|
|
2791
|
+
* binding it out of those factory signatures left these model fields as its
|
|
2792
|
+
* only publisher, which is a smaller surface and not a closed one. Narrowing
|
|
2793
|
+
* them is a product call rather than a defect fix: a bound empties the field
|
|
2794
|
+
* on every well-formed file, where the number is exactly the audit
|
|
2795
|
+
* information it exists to carry.
|
|
2707
2796
|
* - **`contextPath`, on all four findings that carry one** - see
|
|
2708
2797
|
* {@link DeidentifiedAttribute.contextPath}, which holds the measurement. The
|
|
2709
2798
|
* segment tags come off the wire with no table behind them, so a fabricated
|
|
@@ -2714,8 +2803,18 @@ interface UndefinedVrFinding {
|
|
|
2714
2803
|
* same file the de-identified object itself re-emits the fabricated header, so
|
|
2715
2804
|
* redacting this field does not make the object safe.**
|
|
2716
2805
|
*
|
|
2806
|
+
* `embeddedAttributes[].hidden` **left that list** in
|
|
2807
|
+
* `DICOM-DIAGNOSTIC-PHI-RESIDUALS` - an entry is now a literal PS3.15 Table
|
|
2808
|
+
* E.1-1 row, so it is not value-bearing. Its own disclosure had been reworded
|
|
2809
|
+
* twice by then, and this repo deletes a disclosure at that point rather than
|
|
2810
|
+
* writing a third; what is true of the field is stated once, on
|
|
2811
|
+
* {@link EmbeddedAttributeFinding}. The field is **still uncapped**.
|
|
2812
|
+
*
|
|
2717
2813
|
* So "the report is safe to log apart from `uidMap`" is **not** an accurate
|
|
2718
2814
|
* description of this type, and was corrected rather than kept convenient.
|
|
2815
|
+
* **This is the only copy of that list.** Two others lived in module docstrings,
|
|
2816
|
+
* still naming `hidden` after it left and never naming `contextPath` at all; a
|
|
2817
|
+
* graded pass found them and they were deleted rather than resynced.
|
|
2719
2818
|
*
|
|
2720
2819
|
* @example
|
|
2721
2820
|
* ```ts
|
|
@@ -2994,9 +3093,8 @@ declare class DeidentifyError extends Error {
|
|
|
2994
3093
|
* action map ({@link annexE}). It is a **pure** function: the input {@link Dataset}
|
|
2995
3094
|
* is never mutated; a fresh `Dataset` (with a rebuilt element map and File Meta)
|
|
2996
3095
|
* is returned alongside a {@link DeidentifyReport} whose non-value-free fields
|
|
2997
|
-
* are named on that type
|
|
2998
|
-
*
|
|
2999
|
-
* there, never a count quoted elsewhere.
|
|
3096
|
+
* are named on that type. **The list is deliberately not copied here** - see
|
|
3097
|
+
* `./index.ts` for what a third copy of it cost.
|
|
3000
3098
|
*
|
|
3001
3099
|
* **What it does**
|
|
3002
3100
|
* - Resolves each attribute's action (basic profile, overridden by an active
|
package/dist/index.d.ts
CHANGED
|
@@ -114,6 +114,18 @@ interface UidEntry {
|
|
|
114
114
|
* throw `TypeError` in strict mode (which all of `@cosyte/dicom`'s emitted code
|
|
115
115
|
* runs under, given `"use strict"` is implicit for ES modules).
|
|
116
116
|
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```ts
|
|
119
|
+
* import { Dictionary } from "@cosyte/dicom";
|
|
120
|
+
*
|
|
121
|
+
* // Tag or keyword, either way round, and `undefined` rather than a throw on a miss.
|
|
122
|
+
* Dictionary.lookup("00100020")?.name; // "Patient ID"
|
|
123
|
+
* Dictionary.byKeyword("Modality")?.tag; // "00080060"
|
|
124
|
+
*
|
|
125
|
+
* // UIDs resolve to their registered name, so nobody hard-codes a SOP Class table.
|
|
126
|
+
* Dictionary.uid("1.2.840.10008.5.1.4.1.1.2")?.name; // "CT Image Storage"
|
|
127
|
+
* ```
|
|
128
|
+
*
|
|
117
129
|
* @module
|
|
118
130
|
*/
|
|
119
131
|
|
|
@@ -317,8 +329,31 @@ interface ParseOptions {
|
|
|
317
329
|
*
|
|
318
330
|
* 🛑 **THE ESCALATED DIAGNOSTIC CARRIES SOURCE BYTES THAT THE WARNING DOES
|
|
319
331
|
* NOT.** A `DicomParseWarning.message` is a frozen registry string with only
|
|
320
|
-
* structural tokens filled in
|
|
321
|
-
* `
|
|
332
|
+
* structural tokens filled in: `{tag}` renders only a tag PS3.6's element
|
|
333
|
+
* registry carries a literal row for, `{vr}` only one of the 34 VRs PS3.5
|
|
334
|
+
* section 6.2 defines, and a raw length or byte value a header carries is
|
|
335
|
+
* bound out of the factory signature rather than rendered. That now holds on
|
|
336
|
+
* the `deidentify()` codes too:
|
|
337
|
+
* `DICOM_DEIDENT_UNDEFINED_VR_NOT_AUDITABLE` and
|
|
338
|
+
* `DICOM_DEIDENT_SEQUENCE_NOT_AUDITABLE` rendered `Element.rawBytes.length`
|
|
339
|
+
* through `0.0.14`, which equals the declared Value Length and was reachable
|
|
340
|
+
* from a fabricated header, and both slots are gone. So is
|
|
341
|
+
* `DICOM_ITEM_CROSSES_SEQUENCE_END`'s remaining-bytes count, because **a raw
|
|
342
|
+
* number shifted by a constant the reader can compute is that raw number**: it
|
|
343
|
+
* was the enclosing sequence's declared Value Length less the bytes of that
|
|
344
|
+
* sequence already consumed. **The exceptions are named in one place that is
|
|
345
|
+
* not a record of a past change, and are deliberately not restated here** -
|
|
346
|
+
* the `WARNING_MESSAGES` docblock in `./warnings.ts`, which this JSDoc used to
|
|
347
|
+
* carry a copy of.
|
|
348
|
+
* **This is a statement about `w.message` and about nothing else**: the two
|
|
349
|
+
* byte counts still exist on `report.undefinedVrElements[].byteLength` and
|
|
350
|
+
* `report.unauditableSequences[].byteLength`, model fields on a type whose own
|
|
351
|
+
* docs say it is not a value-free surface. **No
|
|
352
|
+
* safe-to-log verdict is stated here** - that sentence was corrected twice and
|
|
353
|
+
* is deleted rather than tried a third time; the mechanism is above and the
|
|
354
|
+
* treatment is in the package's troubleshooting docs. The `DicomParseError`
|
|
355
|
+
* this option raises in its place is a different and larger surface: it also
|
|
356
|
+
* carries `snippet`,
|
|
322
357
|
* **16 raw bytes, unredacted** (D-10), read at the warning's own `byteOffset`.
|
|
323
358
|
* A message-only PHI review of the lenient path therefore does not transfer to
|
|
324
359
|
* the strict one. Log `err.code`, `err.byteOffset` and `err.message`; treat
|
|
@@ -921,6 +956,21 @@ declare class Element {
|
|
|
921
956
|
* `(0002,0102)` Private Information - is captured here as raw bytes (the
|
|
922
957
|
* on-wire value, even-length per PS3.5 §6.2) rather than dropped. `value` is a
|
|
923
958
|
* defensive copy, so the view never aliases the parsed input buffer.
|
|
959
|
+
*
|
|
960
|
+
* @example
|
|
961
|
+
* ```ts
|
|
962
|
+
* import { parseDicom } from "@cosyte/dicom";
|
|
963
|
+
* const ds = parseDicom(buf);
|
|
964
|
+
* // Anything the typed FileMeta fields do not model, in ascending tag order.
|
|
965
|
+
* for (const raw of ds.fileMeta?.extraElements ?? []) {
|
|
966
|
+
* raw.tag; // e.g. "00020017" Sending Application Entity Title
|
|
967
|
+
* raw.vr; // the VR the source wrote (File Meta is always Explicit VR LE)
|
|
968
|
+
* raw.value.length; // even, per PS3.5 2026c section 7.1.1
|
|
969
|
+
* }
|
|
970
|
+
* ```
|
|
971
|
+
*
|
|
972
|
+
* `(0002,0016)` Source Application Entity Title is deliberately NOT the example: it is one of the
|
|
973
|
+
* typed fields, so it never reaches this array.
|
|
924
974
|
*/
|
|
925
975
|
interface FileMetaRawElement {
|
|
926
976
|
/** 8-char uppercase hex tag, e.g. `"00020100"`. */
|
|
@@ -2448,15 +2498,29 @@ interface DeidentifiedAttribute {
|
|
|
2448
2498
|
* (PS3.15 §E.1 "all instances"; §E.3.5 is the standard's own precedent for
|
|
2449
2499
|
* removing identifying information embedded inside a string attribute).
|
|
2450
2500
|
*
|
|
2451
|
-
* `tag` and `vr` are the carrier's own and are structural. **`hidden`
|
|
2452
|
-
* and
|
|
2453
|
-
*
|
|
2454
|
-
*
|
|
2455
|
-
*
|
|
2456
|
-
* `
|
|
2457
|
-
*
|
|
2458
|
-
*
|
|
2459
|
-
*
|
|
2501
|
+
* `tag` and `vr` are the carrier's own and are structural. **`hidden` was not,
|
|
2502
|
+
* and it is bound now.** Every tag in an embedded run is composed from four
|
|
2503
|
+
* bytes that were sitting *inside* the carrier's value - that is the whole
|
|
2504
|
+
* reason this type exists - and a run needs only ONE actionable attribute to be
|
|
2505
|
+
* reported, so through `0.0.13` the rest of the run was listed beside it.
|
|
2506
|
+
* Measured: a `CS` carrier over-declaring across a fabricated `"SMIT"` header
|
|
2507
|
+
* beside a genuine `(0010,0020)` reported `hidden: ["4D535449", "00100020"]`,
|
|
2508
|
+
* and `4D535449` is `"SMIT"` in wire order.
|
|
2509
|
+
*
|
|
2510
|
+
* **An entry is now one of the 652 literal rows of PS3.15 Table E.1-1 that this
|
|
2511
|
+
* run's options left actionable.** That is a **membership** bound rather than a
|
|
2512
|
+
* shape one - the posture this package already takes for a VR and for a Private
|
|
2513
|
+
* Creator - so what survives names a published table entry rather than a
|
|
2514
|
+
* document byte, the same trade rendering a VR makes with the 34. **A
|
|
2515
|
+
* repeating-group mask hit is NOT in that set and is excluded**: `(50xx,xxxx)`
|
|
2516
|
+
* Curve Data leaves the whole 16-bit element number free, so a mask match proves
|
|
2517
|
+
* a rule exists without making the membership finite. A graded pass caught a
|
|
2518
|
+
* draft of this filter that admitted it.
|
|
2519
|
+
*
|
|
2520
|
+
* **🛑 THAT IS NOT AN ALL-CLEAR OVER THIS TYPE.** `contextPath` below is
|
|
2521
|
+
* unbound and unchanged, `hidden` is uncapped, and
|
|
2522
|
+
* {@link DeidentifyReport} names the report's other value-bearing fields. A
|
|
2523
|
+
* `DeidentifyReport` is still not safe to log whole.
|
|
2460
2524
|
*
|
|
2461
2525
|
* @example
|
|
2462
2526
|
* ```ts
|
|
@@ -2472,7 +2536,18 @@ interface EmbeddedAttributeFinding {
|
|
|
2472
2536
|
readonly tag: Tag;
|
|
2473
2537
|
/** The carrier's VR. Always one of the string VRs; binary VRs are not scanned. */
|
|
2474
2538
|
readonly vr: VR;
|
|
2475
|
-
/**
|
|
2539
|
+
/**
|
|
2540
|
+
* The tags found inside the carrier's value **that this run acts on and that a
|
|
2541
|
+
* published table names**, in wire order. **Not every tag in the run** - see
|
|
2542
|
+
* this type's own remarks.
|
|
2543
|
+
*
|
|
2544
|
+
* **🩺 IT MAY BE EMPTY, AND EMPTY DOES NOT MEAN "NOTHING WAS HIDDEN HERE".**
|
|
2545
|
+
* A run whose only actionable members are private attributes, Curve Data or
|
|
2546
|
+
* Overlay elements reports a finding with no tags: the carrier was still
|
|
2547
|
+
* emptied, and the accompanying `DICOM_DEIDENT_EMBEDDED_ATTRIBUTE_REMOVED`
|
|
2548
|
+
* warning still counts the whole run. The presence of the finding is the fact;
|
|
2549
|
+
* this list is the part of it that can be named.
|
|
2550
|
+
*/
|
|
2476
2551
|
readonly hidden: readonly Tag[];
|
|
2477
2552
|
/**
|
|
2478
2553
|
* Tag/index chain when the carrier is inside a sequence item; omitted at the
|
|
@@ -2649,12 +2724,21 @@ interface UndefinedVrFinding {
|
|
|
2649
2724
|
*
|
|
2650
2725
|
* **An input-derived count, and on this finding specifically that is not a
|
|
2651
2726
|
* formality.** For the sibling findings the length came from a header the
|
|
2652
|
-
* sender wrote; here the
|
|
2653
|
-
* the tag bytes. What is published is the *number* they decode to,
|
|
2654
|
-
*
|
|
2655
|
-
*
|
|
2656
|
-
*
|
|
2657
|
-
*
|
|
2727
|
+
* sender wrote; here the four length bytes can themselves be value bytes, like
|
|
2728
|
+
* the tag bytes. What is published is the *number* they decode to, and one
|
|
2729
|
+
* `readUInt32LE` puts the bytes back: a fabricated header reading `"SO\0\0"`
|
|
2730
|
+
* publishes `20307`, two letters of a surname. Do not describe this field as
|
|
2731
|
+
* "structural, never a value" the way its siblings are described.
|
|
2732
|
+
*
|
|
2733
|
+
* **🩺 IT IS NO LONGER "the same footing as every `{n}` in the warning
|
|
2734
|
+
* registry", AND THAT SENTENCE WAS THE ONE THIS FIELD SHIPPED WITH.**
|
|
2735
|
+
* `DICOM_DEIDENT_UNDEFINED_VR_NOT_AUDITABLE` rendered exactly this number and
|
|
2736
|
+
* does not any more - it is bound out of `undefinedVrNotAuditable`'s
|
|
2737
|
+
* signature. So this field is now a **model field**, on the same standing
|
|
2738
|
+
* exception as `removedPrivateTags`, `unauditableSequences[].tag`, `uidMap`
|
|
2739
|
+
* and `contextPath`: narrowing it is a product call, because a bound empties
|
|
2740
|
+
* it on every well-formed file, where it is exactly the audit number the field
|
|
2741
|
+
* exists to carry. Deliberately unchanged; see this type's own summary.
|
|
2658
2742
|
*/
|
|
2659
2743
|
readonly byteLength: number;
|
|
2660
2744
|
/**
|
|
@@ -2697,13 +2781,18 @@ interface UndefinedVrFinding {
|
|
|
2697
2781
|
* and still answers it whenever the fabricated VR is outside the 34 PS3.5
|
|
2698
2782
|
* §6.2 defines. It cannot when the fabricated VR is one of them, because those
|
|
2699
2783
|
* two files are byte-identical.
|
|
2700
|
-
* - **`
|
|
2701
|
-
*
|
|
2702
|
-
*
|
|
2703
|
-
*
|
|
2704
|
-
*
|
|
2705
|
-
*
|
|
2706
|
-
*
|
|
2784
|
+
* - **`undefinedVrElements[].byteLength` and
|
|
2785
|
+
* `unauditableSequences[].byteLength`** - the declared Value Length read off
|
|
2786
|
+
* the element header, so on a fabricated header it is four document bytes
|
|
2787
|
+
* wearing a decimal: `"SO\0\0"` publishes `20307`, two letters of a surname,
|
|
2788
|
+
* put back with one `readUInt32LE`. **They JOINED this list rather than
|
|
2789
|
+
* always having been on it.** Through `0.0.14` the two
|
|
2790
|
+
* `DICOM_DEIDENT_*_NOT_AUDITABLE` **messages** rendered the same number;
|
|
2791
|
+
* binding it out of those factory signatures left these model fields as its
|
|
2792
|
+
* only publisher, which is a smaller surface and not a closed one. Narrowing
|
|
2793
|
+
* them is a product call rather than a defect fix: a bound empties the field
|
|
2794
|
+
* on every well-formed file, where the number is exactly the audit
|
|
2795
|
+
* information it exists to carry.
|
|
2707
2796
|
* - **`contextPath`, on all four findings that carry one** - see
|
|
2708
2797
|
* {@link DeidentifiedAttribute.contextPath}, which holds the measurement. The
|
|
2709
2798
|
* segment tags come off the wire with no table behind them, so a fabricated
|
|
@@ -2714,8 +2803,18 @@ interface UndefinedVrFinding {
|
|
|
2714
2803
|
* same file the de-identified object itself re-emits the fabricated header, so
|
|
2715
2804
|
* redacting this field does not make the object safe.**
|
|
2716
2805
|
*
|
|
2806
|
+
* `embeddedAttributes[].hidden` **left that list** in
|
|
2807
|
+
* `DICOM-DIAGNOSTIC-PHI-RESIDUALS` - an entry is now a literal PS3.15 Table
|
|
2808
|
+
* E.1-1 row, so it is not value-bearing. Its own disclosure had been reworded
|
|
2809
|
+
* twice by then, and this repo deletes a disclosure at that point rather than
|
|
2810
|
+
* writing a third; what is true of the field is stated once, on
|
|
2811
|
+
* {@link EmbeddedAttributeFinding}. The field is **still uncapped**.
|
|
2812
|
+
*
|
|
2717
2813
|
* So "the report is safe to log apart from `uidMap`" is **not** an accurate
|
|
2718
2814
|
* description of this type, and was corrected rather than kept convenient.
|
|
2815
|
+
* **This is the only copy of that list.** Two others lived in module docstrings,
|
|
2816
|
+
* still naming `hidden` after it left and never naming `contextPath` at all; a
|
|
2817
|
+
* graded pass found them and they were deleted rather than resynced.
|
|
2719
2818
|
*
|
|
2720
2819
|
* @example
|
|
2721
2820
|
* ```ts
|
|
@@ -2994,9 +3093,8 @@ declare class DeidentifyError extends Error {
|
|
|
2994
3093
|
* action map ({@link annexE}). It is a **pure** function: the input {@link Dataset}
|
|
2995
3094
|
* is never mutated; a fresh `Dataset` (with a rebuilt element map and File Meta)
|
|
2996
3095
|
* is returned alongside a {@link DeidentifyReport} whose non-value-free fields
|
|
2997
|
-
* are named on that type
|
|
2998
|
-
*
|
|
2999
|
-
* there, never a count quoted elsewhere.
|
|
3096
|
+
* are named on that type. **The list is deliberately not copied here** - see
|
|
3097
|
+
* `./index.ts` for what a third copy of it cost.
|
|
3000
3098
|
*
|
|
3001
3099
|
* **What it does**
|
|
3002
3100
|
* - Resolves each attribute's action (basic profile, overridden by an active
|