dicom-synth 0.1.0 → 1.0.0

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/dist/esm/index.js CHANGED
@@ -1,3 +1,43 @@
1
+ // src/negativeCases/index.ts
2
+ import { mkdirSync, writeFileSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+ function writeFakeDicomSignatureFile(filePath) {
5
+ const buf = Buffer.alloc(200, 0);
6
+ buf.write("XXXX", 128, 4, "ascii");
7
+ mkdirSync(resolve(filePath, ".."), { recursive: true });
8
+ writeFileSync(filePath, buf);
9
+ }
10
+ function writeNonDicomFile(filePath, content = "not dicom") {
11
+ mkdirSync(resolve(filePath, ".."), { recursive: true });
12
+ writeFileSync(filePath, content);
13
+ }
14
+
15
+ // src/nonStandardDicom/dicomdir.ts
16
+ import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "node:fs";
17
+ import { resolve as resolve2 } from "node:path";
18
+ var DICOMDIR_SOP_CLASS_UID = "1.2.840.10008.1.3.10";
19
+ function buildDicomdirBuffer() {
20
+ const uid = DICOMDIR_SOP_CLASS_UID;
21
+ const buf = Buffer.alloc(256, 0);
22
+ buf.write("DICM", 128, 4, "ascii");
23
+ let off = 132;
24
+ buf.writeUInt16LE(2, off);
25
+ off += 2;
26
+ buf.writeUInt16LE(2, off);
27
+ off += 2;
28
+ buf.write("UI", off, 2, "ascii");
29
+ off += 2;
30
+ buf.writeUInt16LE(uid.length, off);
31
+ off += 2;
32
+ buf.write(uid, off, uid.length, "ascii");
33
+ off += uid.length;
34
+ return buf.subarray(0, off);
35
+ }
36
+ function writeDicomdirFile(filePath) {
37
+ mkdirSync2(resolve2(filePath, ".."), { recursive: true });
38
+ writeFileSync2(filePath, buildDicomdirBuffer());
39
+ }
40
+
1
41
  // src/public-fixtures/catalog.ts
2
42
  import { readFileSync } from "node:fs";
3
43
  import { dirname, join } from "node:path";
@@ -31,7 +71,7 @@ function loadCaseById(casesJsonPath, id) {
31
71
 
32
72
  // src/public-fixtures/fetch.ts
33
73
  import { createHash } from "node:crypto";
34
- import { existsSync, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "node:fs";
74
+ import { existsSync, mkdirSync as mkdirSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "node:fs";
35
75
  import { homedir } from "node:os";
36
76
  import { join as join2 } from "node:path";
37
77
  var DEFAULT_CACHE_ROOT = join2(homedir(), ".cache", "dicom-synth-testcases");
@@ -58,7 +98,7 @@ async function fetchPublicCaseToCache(record, cacheRoot = DEFAULT_CACHE_ROOT) {
58
98
  verifySha256(buf2, record.sha256);
59
99
  return dest;
60
100
  }
61
- mkdirSync(join2(cacheRoot, record.sha256), { recursive: true });
101
+ mkdirSync3(join2(cacheRoot, record.sha256), { recursive: true });
62
102
  const res = await fetch(record.source.url);
63
103
  if (!res.ok) {
64
104
  throw new Error(
@@ -67,13 +107,13 @@ async function fetchPublicCaseToCache(record, cacheRoot = DEFAULT_CACHE_ROOT) {
67
107
  }
68
108
  const buf = Buffer.from(await res.arrayBuffer());
69
109
  verifySha256(buf, record.sha256);
70
- writeFileSync(dest, buf);
110
+ writeFileSync3(dest, buf);
71
111
  return dest;
72
112
  }
73
113
 
74
114
  // src/syntheticFixtures/generator.ts
75
- import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "node:fs";
76
- import { resolve } from "node:path";
115
+ import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "node:fs";
116
+ import { resolve as resolve3 } from "node:path";
77
117
 
78
118
  // src/loadDcmjs.ts
79
119
  import dcmjsDefaultImport, * as dcmjsNamespace from "dcmjs";
@@ -183,13 +223,38 @@ var SYNTHETIC_FIXTURES = [
183
223
  description: "Valid UIDs plus empty Laterality and zero PatientWeight"
184
224
  }
185
225
  ];
226
+ function writeMinimalDicomFile(filePath, tags) {
227
+ const patientId = tags?.patientId ?? "TEST-PATIENT-001";
228
+ const patientName = tags?.patientName ?? "TEST^PATIENT";
229
+ const sopUID = tags?.sopInstanceUid ?? "1.2.3.4.5.6.7.8.9.0.1";
230
+ const dataset = {
231
+ PatientName: patientName,
232
+ PatientID: patientId,
233
+ Modality: "CT",
234
+ SOPClassUID: CT_SOP_CLASS,
235
+ SOPInstanceUID: sopUID,
236
+ SeriesInstanceUID: "1.2.3.4.5.6.7.8",
237
+ StudyInstanceUID: "1.2.3.4.5.6.7",
238
+ SeriesNumber: "1",
239
+ Rows: 1,
240
+ Columns: 1,
241
+ BitsAllocated: 16,
242
+ PixelRepresentation: 0,
243
+ PixelData: new Uint8Array([0, 0]).buffer
244
+ };
245
+ const dicomDict = new dcmjs.data.DicomDict({});
246
+ dicomDict.dict = dcmjs.data.DicomMetaDictionary.denaturalizeDataset(dataset);
247
+ const buffer = Buffer.from(dicomDict.write({ allowInvalidVRLength: true }));
248
+ mkdirSync4(resolve3(filePath, ".."), { recursive: true });
249
+ writeFileSync4(filePath, buffer);
250
+ }
186
251
  function writeSyntheticFixturesToDir(outDir) {
187
- const root = resolve(outDir);
188
- mkdirSync2(root, { recursive: true });
252
+ const root = resolve3(outDir);
253
+ mkdirSync4(root, { recursive: true });
189
254
  const written = [];
190
255
  for (const { filename, variant } of SYNTHETIC_FIXTURES) {
191
- const path = resolve(root, filename);
192
- writeFileSync2(path, buildSyntheticCtBuffer(variant));
256
+ const path = resolve3(root, filename);
257
+ writeFileSync4(path, buildSyntheticCtBuffer(variant));
193
258
  written.push(path);
194
259
  }
195
260
  return written;
@@ -197,6 +262,7 @@ function writeSyntheticFixturesToDir(outDir) {
197
262
  export {
198
263
  SYNTHETIC_FIXTURES,
199
264
  buildDicomDict,
265
+ buildDicomdirBuffer,
200
266
  buildSyntheticCtBuffer,
201
267
  caseCachePath,
202
268
  defaultPublicCasesPath,
@@ -205,5 +271,9 @@ export {
205
271
  loadCasesFromJson,
206
272
  loadDefaultCases,
207
273
  verifySha256,
274
+ writeDicomdirFile,
275
+ writeFakeDicomSignatureFile,
276
+ writeMinimalDicomFile,
277
+ writeNonDicomFile,
208
278
  writeSyntheticFixturesToDir
209
279
  };
@@ -0,0 +1,17 @@
1
+ // src/negativeCases/index.ts
2
+ import { mkdirSync, writeFileSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+ function writeFakeDicomSignatureFile(filePath) {
5
+ const buf = Buffer.alloc(200, 0);
6
+ buf.write("XXXX", 128, 4, "ascii");
7
+ mkdirSync(resolve(filePath, ".."), { recursive: true });
8
+ writeFileSync(filePath, buf);
9
+ }
10
+ function writeNonDicomFile(filePath, content = "not dicom") {
11
+ mkdirSync(resolve(filePath, ".."), { recursive: true });
12
+ writeFileSync(filePath, content);
13
+ }
14
+ export {
15
+ writeFakeDicomSignatureFile,
16
+ writeNonDicomFile
17
+ };
@@ -0,0 +1,30 @@
1
+ // src/nonStandardDicom/dicomdir.ts
2
+ import { mkdirSync, writeFileSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+ var DICOMDIR_SOP_CLASS_UID = "1.2.840.10008.1.3.10";
5
+ function buildDicomdirBuffer() {
6
+ const uid = DICOMDIR_SOP_CLASS_UID;
7
+ const buf = Buffer.alloc(256, 0);
8
+ buf.write("DICM", 128, 4, "ascii");
9
+ let off = 132;
10
+ buf.writeUInt16LE(2, off);
11
+ off += 2;
12
+ buf.writeUInt16LE(2, off);
13
+ off += 2;
14
+ buf.write("UI", off, 2, "ascii");
15
+ off += 2;
16
+ buf.writeUInt16LE(uid.length, off);
17
+ off += 2;
18
+ buf.write(uid, off, uid.length, "ascii");
19
+ off += uid.length;
20
+ return buf.subarray(0, off);
21
+ }
22
+ function writeDicomdirFile(filePath) {
23
+ mkdirSync(resolve(filePath, ".."), { recursive: true });
24
+ writeFileSync(filePath, buildDicomdirBuffer());
25
+ }
26
+ export {
27
+ DICOMDIR_SOP_CLASS_UID,
28
+ buildDicomdirBuffer,
29
+ writeDicomdirFile
30
+ };
@@ -110,6 +110,31 @@ var SYNTHETIC_FIXTURES = [
110
110
  description: "Valid UIDs plus empty Laterality and zero PatientWeight"
111
111
  }
112
112
  ];
113
+ function writeMinimalDicomFile(filePath, tags) {
114
+ const patientId = tags?.patientId ?? "TEST-PATIENT-001";
115
+ const patientName = tags?.patientName ?? "TEST^PATIENT";
116
+ const sopUID = tags?.sopInstanceUid ?? "1.2.3.4.5.6.7.8.9.0.1";
117
+ const dataset = {
118
+ PatientName: patientName,
119
+ PatientID: patientId,
120
+ Modality: "CT",
121
+ SOPClassUID: CT_SOP_CLASS,
122
+ SOPInstanceUID: sopUID,
123
+ SeriesInstanceUID: "1.2.3.4.5.6.7.8",
124
+ StudyInstanceUID: "1.2.3.4.5.6.7",
125
+ SeriesNumber: "1",
126
+ Rows: 1,
127
+ Columns: 1,
128
+ BitsAllocated: 16,
129
+ PixelRepresentation: 0,
130
+ PixelData: new Uint8Array([0, 0]).buffer
131
+ };
132
+ const dicomDict = new dcmjs.data.DicomDict({});
133
+ dicomDict.dict = dcmjs.data.DicomMetaDictionary.denaturalizeDataset(dataset);
134
+ const buffer = Buffer.from(dicomDict.write({ allowInvalidVRLength: true }));
135
+ mkdirSync(resolve(filePath, ".."), { recursive: true });
136
+ writeFileSync(filePath, buffer);
137
+ }
113
138
  function writeSyntheticFixturesToDir(outDir) {
114
139
  const root = resolve(outDir);
115
140
  mkdirSync(root, { recursive: true });
@@ -125,5 +150,6 @@ export {
125
150
  SYNTHETIC_FIXTURES,
126
151
  buildDicomDict,
127
152
  buildSyntheticCtBuffer,
153
+ writeMinimalDicomFile,
128
154
  writeSyntheticFixturesToDir
129
155
  };
@@ -1,3 +1,5 @@
1
+ export { writeFakeDicomSignatureFile, writeNonDicomFile, } from './negativeCases/index';
2
+ export { buildDicomdirBuffer, writeDicomdirFile, } from './nonStandardDicom/dicomdir';
1
3
  export { defaultPublicCasesPath, loadCaseById, loadCasesFromJson, loadDefaultCases, type PublicCaseRecord, type PublicCaseSource, } from './public-fixtures/catalog';
2
4
  export { caseCachePath, fetchPublicCaseToCache, verifySha256, } from './public-fixtures/fetch';
3
- export { buildDicomDict, buildSyntheticCtBuffer, SYNTHETIC_FIXTURES, type SyntheticCtVariant, writeSyntheticFixturesToDir, } from './syntheticFixtures/generator';
5
+ export { buildDicomDict, buildSyntheticCtBuffer, type MinimalDicomTags, SYNTHETIC_FIXTURES, type SyntheticCtVariant, writeMinimalDicomFile, writeSyntheticFixturesToDir, } from './syntheticFixtures/generator';
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Write a file large enough to pass size checks but with `XXXX` at
3
+ * offset 128 instead of the `DICM` magic bytes.
4
+ * The parent directory is created if it does not exist.
5
+ */
6
+ export declare function writeFakeDicomSignatureFile(filePath: string): void;
7
+ /**
8
+ * Write arbitrary non-DICOM content to `filePath`.
9
+ * The parent directory is created if it does not exist.
10
+ */
11
+ export declare function writeNonDicomFile(filePath: string, content?: string): void;
@@ -0,0 +1,15 @@
1
+ export declare const DICOMDIR_SOP_CLASS_UID = "1.2.840.10008.1.3.10";
2
+ /**
3
+ * Build a minimal DICOM Part 10 buffer whose MediaStorageSOPClassUID
4
+ * identifies it as a DICOMDIR (1.2.840.10008.1.3.10).
5
+ *
6
+ * The file has a valid DICM signature and a single meta tag (0002,0002)
7
+ * so it passes signature checks but is detectable by SOP class UID.
8
+ * dcmjs cannot write DICOMDIR, so this uses a raw byte layout.
9
+ */
10
+ export declare function buildDicomdirBuffer(): Buffer;
11
+ /**
12
+ * Write a minimal DICOMDIR-signature file to `filePath`.
13
+ * The parent directory is created if it does not exist.
14
+ */
15
+ export declare function writeDicomdirFile(filePath: string): void;
@@ -7,5 +7,21 @@ export declare const SYNTHETIC_FIXTURES: {
7
7
  variant: SyntheticCtVariant;
8
8
  description: string;
9
9
  }[];
10
+ export type MinimalDicomTags = {
11
+ patientId?: string;
12
+ patientName?: string;
13
+ sopInstanceUid?: string;
14
+ };
15
+ /**
16
+ * Write a minimal CT DICOM file to `filePath`.
17
+ *
18
+ * The output is intentionally bare: it contains no Part 10 group-0002
19
+ * file-meta header (no MediaStorageSOPClassUID, TransferSyntaxUID, etc.).
20
+ * Use `buildDicomDict` / `buildSyntheticCtBuffer` when a conformant
21
+ * Part 10 file with a complete meta header is required.
22
+ *
23
+ * The parent directory is created if it does not exist.
24
+ */
25
+ export declare function writeMinimalDicomFile(filePath: string, tags?: MinimalDicomTags): void;
10
26
  /** Write all catalogue fixtures to a directory (created if missing). */
11
27
  export declare function writeSyntheticFixturesToDir(outDir: string): string[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dicom-synth",
3
- "version": "0.1.0",
3
+ "version": "1.0.0",
4
4
  "description": "Toolkit for synthetic DICOM fixtures and public fixture fetch/cache.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -1,72 +0,0 @@
1
- // src/publicCorpus.ts
2
- import { createHash } from "node:crypto";
3
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
- import { homedir } from "node:os";
5
- import { dirname, join } from "node:path";
6
- import { fileURLToPath } from "node:url";
7
- var DEFAULT_CACHE_ROOT = join(homedir(), ".cache", "dicom-synth-testcases");
8
- var bundledCatalogPath = join(
9
- dirname(fileURLToPath(import.meta.url)),
10
- "../data/public-cases.json"
11
- );
12
- function defaultPublicCasesPath() {
13
- return bundledCatalogPath;
14
- }
15
- function loadDefaultCases() {
16
- return loadCasesFromJson(defaultPublicCasesPath());
17
- }
18
- function loadCasesFromJson(casesJsonPath) {
19
- const j = JSON.parse(readFileSync(casesJsonPath, "utf8"));
20
- return j.cases;
21
- }
22
- function loadCaseById(casesJsonPath, id) {
23
- const found = loadCasesFromJson(casesJsonPath).find((r) => r.id === id);
24
- if (!found) {
25
- throw new Error(`Unknown case id "${id}" in ${casesJsonPath}`);
26
- }
27
- return found;
28
- }
29
- function caseCachePath(sha256, root = DEFAULT_CACHE_ROOT) {
30
- return join(root, sha256, "file.dcm");
31
- }
32
- function verifySha256(buffer, expected) {
33
- const h = createHash("sha256").update(buffer).digest("hex");
34
- if (h !== expected) {
35
- throw new Error(
36
- `SHA256 mismatch: expected ${expected}, got ${h}. Upstream may have changed; bump metadata after review.`
37
- );
38
- }
39
- }
40
- async function fetchPublicCaseToCache(record, cacheRoot = DEFAULT_CACHE_ROOT) {
41
- if (record.source.kind !== "url") {
42
- throw new Error(
43
- `Case ${record.id}: only url sources are supported (s3 requires credentials).`
44
- );
45
- }
46
- const dest = caseCachePath(record.sha256, cacheRoot);
47
- if (existsSync(dest)) {
48
- const buf2 = readFileSync(dest);
49
- verifySha256(buf2, record.sha256);
50
- return dest;
51
- }
52
- mkdirSync(join(cacheRoot, record.sha256), { recursive: true });
53
- const res = await fetch(record.source.url);
54
- if (!res.ok) {
55
- throw new Error(
56
- `Fetch failed ${res.status} ${res.statusText} for ${record.source.url}`
57
- );
58
- }
59
- const buf = Buffer.from(await res.arrayBuffer());
60
- verifySha256(buf, record.sha256);
61
- writeFileSync(dest, buf);
62
- return dest;
63
- }
64
- export {
65
- caseCachePath,
66
- defaultPublicCasesPath,
67
- fetchPublicCaseToCache,
68
- loadCaseById,
69
- loadCasesFromJson,
70
- loadDefaultCases,
71
- verifySha256
72
- };
@@ -1,109 +0,0 @@
1
- // src/synthetic.ts
2
- import { mkdirSync, writeFileSync } from "node:fs";
3
- import { resolve } from "node:path";
4
- import * as dcmjs from "dcmjs";
5
- var CT_SOP_CLASS = "1.2.840.10008.5.1.4.1.1.2";
6
- var VARIANT_INDEX = {
7
- "minimal-invalid-uid": 0,
8
- "valid-uid": 1,
9
- "vendor-warnings": 2
10
- };
11
- function uidFor(variant, role) {
12
- const i = VARIANT_INDEX[variant];
13
- if (variant === "minimal-invalid-uid") {
14
- return `2.25.100000000000000000000000000000.${role}.${i}`;
15
- }
16
- const uidRoots = [
17
- "1000000000000000000000000000000000001",
18
- "1000000000000000000000000000000000002",
19
- "1000000000000000000000000000000000003"
20
- ];
21
- const roleSuffix = role === "study" ? 1 : role === "series" ? 2 : 3;
22
- return `2.25.${uidRoots[i]}.${roleSuffix}`;
23
- }
24
- function naturalDataset(variant) {
25
- const studyUID = uidFor(variant, "study");
26
- const seriesUID = uidFor(variant, "series");
27
- const sopUID = uidFor(variant, "sop");
28
- const dataset = {
29
- PatientName: "SYNTH^SUBJECT",
30
- PatientID: "SYNTH_PID",
31
- Modality: "CT",
32
- SOPClassUID: CT_SOP_CLASS,
33
- SOPInstanceUID: sopUID,
34
- SeriesInstanceUID: seriesUID,
35
- StudyInstanceUID: studyUID,
36
- StudyDescription: "Synthetic study",
37
- SeriesDescription: "Synthetic series",
38
- Rows: 1,
39
- Columns: 1,
40
- BitsAllocated: 16,
41
- BitsStored: 16,
42
- HighBit: 15,
43
- SamplesPerPixel: 1,
44
- PhotometricInterpretation: "MONOCHROME2",
45
- PixelRepresentation: 0,
46
- PixelData: new Uint8Array([0, 0]).buffer
47
- };
48
- if (variant === "vendor-warnings") {
49
- dataset.Laterality = "";
50
- dataset.PatientWeight = "0";
51
- }
52
- return dataset;
53
- }
54
- function buildDicomDict(variant) {
55
- const meta = {
56
- FileMetaInformationVersion: new Uint8Array([0, 1]).buffer,
57
- MediaStorageSOPClassUID: CT_SOP_CLASS,
58
- MediaStorageSOPInstanceUID: uidFor(variant, "sop"),
59
- TransferSyntaxUID: "1.2.840.10008.1.2.1",
60
- ImplementationClassUID: "1.2.3.4",
61
- ImplementationVersionName: "SYNTH"
62
- };
63
- const dicomDict = new dcmjs.data.DicomDict(
64
- dcmjs.data.DicomMetaDictionary.denaturalizeDataset(meta)
65
- );
66
- dicomDict.dict = dcmjs.data.DicomMetaDictionary.denaturalizeDataset(
67
- naturalDataset(variant)
68
- );
69
- return dicomDict;
70
- }
71
- function buildSyntheticCtBuffer(variant) {
72
- return Buffer.from(
73
- buildDicomDict(variant).write({ allowInvalidVRLength: true })
74
- );
75
- }
76
- var SYNTHETIC_FIXTURES = [
77
- {
78
- filename: "minimal-ct-0.dcm",
79
- variant: "minimal-invalid-uid",
80
- description: "Minimal CT with text in UIDs (many dciodvfy errors)"
81
- },
82
- {
83
- filename: "valid-uid-ct-0.dcm",
84
- variant: "valid-uid",
85
- description: "Minimal CT with numeric UIDs only (missing-module noise)"
86
- },
87
- {
88
- filename: "vendor-warnings-ct-0.dcm",
89
- variant: "vendor-warnings",
90
- description: "Valid UIDs plus empty Laterality and zero PatientWeight"
91
- }
92
- ];
93
- function writeSyntheticFixturesToDir(outDir) {
94
- const root = resolve(outDir);
95
- mkdirSync(root, { recursive: true });
96
- const written = [];
97
- for (const { filename, variant } of SYNTHETIC_FIXTURES) {
98
- const path = resolve(root, filename);
99
- writeFileSync(path, buildSyntheticCtBuffer(variant));
100
- written.push(path);
101
- }
102
- return written;
103
- }
104
- export {
105
- SYNTHETIC_FIXTURES,
106
- buildDicomDict,
107
- buildSyntheticCtBuffer,
108
- writeSyntheticFixturesToDir
109
- };
@@ -1,25 +0,0 @@
1
- export type PublicCaseSource = {
2
- kind: 'url';
3
- url: string;
4
- } | {
5
- kind: 's3';
6
- bucket: string;
7
- key: string;
8
- version_id?: string;
9
- };
10
- export type PublicCaseRecord = {
11
- id: string;
12
- violation_class: string;
13
- source: PublicCaseSource;
14
- sha256: string;
15
- notes?: string;
16
- dciodvfy_skip?: boolean;
17
- };
18
- /** Path to bundled `public-cases.json` (works from `src/` and `dist/esm/`). */
19
- export declare function defaultPublicCasesPath(): string;
20
- export declare function loadDefaultCases(): PublicCaseRecord[];
21
- export declare function loadCasesFromJson(casesJsonPath: string): PublicCaseRecord[];
22
- export declare function loadCaseById(casesJsonPath: string, id: string): PublicCaseRecord;
23
- export declare function caseCachePath(sha256: string, root?: string): string;
24
- export declare function verifySha256(buffer: Buffer, expected: string): void;
25
- export declare function fetchPublicCaseToCache(record: PublicCaseRecord, cacheRoot?: string): Promise<string>;
@@ -1,11 +0,0 @@
1
- import * as dcmjs from 'dcmjs';
2
- export type SyntheticCtVariant = 'minimal-invalid-uid' | 'valid-uid' | 'vendor-warnings';
3
- export declare function buildDicomDict(variant: SyntheticCtVariant): dcmjs.data.DicomDict;
4
- export declare function buildSyntheticCtBuffer(variant: SyntheticCtVariant): Buffer;
5
- export declare const SYNTHETIC_FIXTURES: {
6
- filename: string;
7
- variant: SyntheticCtVariant;
8
- description: string;
9
- }[];
10
- /** Write all catalogue fixtures to a directory (created if missing). */
11
- export declare function writeSyntheticFixturesToDir(outDir: string): string[];