dicom-curate 0.2.0 → 0.4.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/README.md CHANGED
@@ -77,11 +77,11 @@ const columnMappings = extractColumnMappings([
77
77
  { subjectID: 'SubjectID2', blindedID: 'BlindedID2' },
78
78
  ])
79
79
 
80
- curateOne(
80
+ curateOne({
81
81
  fileInfo, // path, name, size, kind, blob
82
- undefined,
83
- { curationSpec, columnMappings },
84
- )
82
+ mappingOptions: { curationSpec, columnMappings },
83
+ })
84
+
85
85
 
86
86
  // Cache clean-up responsibility, e.g. for consistent UID mapping in `retainUIDsOption: 'Off'` is with caller
87
87
  clearCaches()
@@ -6,7 +6,12 @@ self.addEventListener('message', (event) => {
6
6
  const { serializedMappingOptions } = event.data;
7
7
  const mappingOptions = deserializeMappingOptions(serializedMappingOptions);
8
8
  try {
9
- curateOne(event.data.fileInfo, event.data.outputDirectory, mappingOptions).then((mapResults) => {
9
+ curateOne({
10
+ fileInfo: event.data.fileInfo,
11
+ fileIndex: event.data.fileIndex,
12
+ outputDirectory: event.data.outputDirectory,
13
+ mappingOptions,
14
+ }).then((mapResults) => {
10
15
  // Send finished message for completion
11
16
  self.postMessage({
12
17
  response: 'finished',
@@ -14,7 +14,7 @@ import deidentifyPS315E, { defaultPs315Options } from './deidentifyPS315E.js';
14
14
  import getParser from './getParser.js';
15
15
  import { specVersion } from './config/specVersion.js';
16
16
  import { get as _get } from 'lodash';
17
- export default function collectMappings(inputFilePath, dicomData, mappingOptions) {
17
+ export default function collectMappings(inputFilePath, inputFileIndex, dicomData, mappingOptions) {
18
18
  var _a;
19
19
  const mapResults = {
20
20
  // original UID for this dicomData
@@ -33,13 +33,15 @@ export default function collectMappings(inputFilePath, dicomData, mappingOptions
33
33
  let finalSpec = {
34
34
  dicomPS315EOptions: defaultPs315Options,
35
35
  inputPathPattern: '',
36
- modifications: () => ({
37
- dicomHeader: {},
38
- outputFilePathComponents: [
39
- parser.getDicom('SeriesInstanceUID'),
40
- parser.getFilePathComp(parser.FILENAME),
41
- ],
42
- }),
36
+ modifications(parser) {
37
+ return {
38
+ dicomHeader: {},
39
+ outputFilePathComponents: [
40
+ parser.protectUid(parser.getDicom('SeriesInstanceUID')),
41
+ parser.getFilePathComp(parser.FILENAME),
42
+ ],
43
+ };
44
+ },
43
45
  validation: () => ({ errors: [] }),
44
46
  };
45
47
  const _b = mappingOptions.curationSpec(), { modifications, validation } = _b, restSpec = __rest(_b, ["modifications", "validation"]);
@@ -54,8 +56,13 @@ export default function collectMappings(inputFilePath, dicomData, mappingOptions
54
56
  if (!mappingOptions.skipValidation) {
55
57
  finalSpec.validation = validation;
56
58
  }
59
+ // protect filename if we de-identify
60
+ const finalFilePath = finalSpec.dicomPS315EOptions === 'Off'
61
+ ? inputFilePath
62
+ : inputFilePath.slice(0, inputFilePath.lastIndexOf('/') + 1) +
63
+ `${String(inputFileIndex + 1).padStart(5, '0')}.dcm`;
57
64
  // create a parser object to be used in the eval'ed mappingFunctions
58
- const parser = getParser(finalSpec.inputPathPattern, inputFilePath, naturalData, mappingOptions.columnMappings, finalSpec.additionalData);
65
+ const parser = getParser(finalSpec.inputPathPattern, finalFilePath, naturalData, finalSpec.dicomPS315EOptions, mappingOptions.columnMappings, finalSpec.additionalData);
59
66
  let modificationMap = finalSpec.modifications(parser);
60
67
  // List all validation errors
61
68
  mapResults.errors = finalSpec
@@ -2,11 +2,11 @@ import * as dcmjs from 'dcmjs';
2
2
  import collectMappings from './collectMappings.js';
3
3
  import mapMetaheader from './mapMetaheader.js';
4
4
  import { set as _set, unset as _unset, cloneDeep as _cloneDeep } from 'lodash';
5
- export default function curateDict(inputFilePath, dicomData, mappingOptions) {
5
+ export default function curateDict(inputFilePath, inputFileIndex, dicomData, mappingOptions) {
6
6
  //
7
7
  // Collect the mappings and apply them to the data
8
8
  //
9
- const [naturalData, mapResults] = collectMappings(inputFilePath, dicomData, mappingOptions);
9
+ const [naturalData, mapResults] = collectMappings(inputFilePath, inputFileIndex, dicomData, mappingOptions);
10
10
  for (let tagPath in mapResults.mappings) {
11
11
  const [, operation, , mappedValue] = mapResults.mappings[tagPath];
12
12
  switch (operation) {
@@ -10,8 +10,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  import * as dcmjs from 'dcmjs';
11
11
  import createNestedDirectories from './createNestedDirectories.js';
12
12
  import curateDict from './curateDict.js';
13
- export function curateOne(fileInfo, outputDirectory, mappingOptions) {
14
- return __awaiter(this, void 0, void 0, function* () {
13
+ export function curateOne(_a) {
14
+ return __awaiter(this, arguments, void 0, function* ({ fileInfo, fileIndex = 0, outputDirectory, mappingOptions, }) {
15
15
  //
16
16
  // First, read the dicom instance data from the file handle or blob
17
17
  //
@@ -36,7 +36,7 @@ export function curateOne(fileInfo, outputDirectory, mappingOptions) {
36
36
  };
37
37
  return mapResults;
38
38
  }
39
- const { dicomData: mappedDicomData, mapResults: clonedMapResults } = curateDict(`${fileInfo.path}/${fileInfo.name}`, dicomData, mappingOptions);
39
+ const { dicomData: mappedDicomData, mapResults: clonedMapResults } = curateDict(`${fileInfo.path}/${fileInfo.name}`, fileIndex, dicomData, mappingOptions);
40
40
  if (!mappingOptions.skipWrite) {
41
41
  // Finally, write the results
42
42
  const dirPath = clonedMapResults.outputFilePath
@@ -33,6 +33,9 @@ function temporalVr(vr) {
33
33
  function removeRetiredPrefix(name) {
34
34
  return name.startsWith('RETIRED_') ? name.slice(8) : name;
35
35
  }
36
+ export function protectUid(uid, retainUIDsOption) {
37
+ return retainUIDsOption === 'Hashed' ? hashUid(uid) : replaceUid(uid);
38
+ }
36
39
  const elementNamesToAlwaysKeepSet = new Set(elementNamesToAlwaysKeep);
37
40
  // Special conditions for some PS3.15 E1.1 elements.
38
41
  const ps315EElements = rawPs315EElements.map((elm) => {
@@ -235,7 +238,7 @@ export default function deidentifyPS315E({ naturalData, dicomPS315EOptions, date
235
238
  // UID is not a known class UID.
236
239
  !(uid in uidRegistryPS3_06_A1)) {
237
240
  // UIDs that need to be mapped
238
- const mappedUID = retainUIDsOption === 'Hashed' ? hashUid(uid) : replaceUid(uid);
241
+ const mappedUID = protectUid(uid, retainUIDsOption);
239
242
  mapResults.mappings[attrPath] = [
240
243
  uid,
241
244
  'replace',
@@ -1,4 +1,5 @@
1
1
  import * as dcmjs from 'dcmjs';
2
+ import { protectUid as rawProtectUid } from './deidentifyPS315E.js';
2
3
  import { getCsvMapping } from './csvMapping.js';
3
4
  import { UniqueNumbers } from './UniqueNumbers.js';
4
5
  export const FILEBASENAME = Symbol('fileBasename');
@@ -25,7 +26,15 @@ const { isUniqueInGroup, clearUniqueInGroupCache } = (function () {
25
26
  };
26
27
  })();
27
28
  export { clearUniqueNumberCache, clearUniqueInGroupCache };
28
- export default function getParser(inputPathPattern, inputFilePath, naturalData, columnMappings, additionalData) {
29
+ export default function getParser(inputPathPattern, inputFilePath, naturalData, dicomPS315EOptions, columnMappings, additionalData) {
30
+ function protectUid(uid) {
31
+ let protectedUid = uid;
32
+ if (dicomPS315EOptions !== 'Off') {
33
+ const { retainUIDsOption } = dicomPS315EOptions;
34
+ protectedUid = rawProtectUid(uid, retainUIDsOption);
35
+ }
36
+ return protectedUid;
37
+ }
29
38
  function getDicom(attrName) {
30
39
  if (attrName in dcmjs.data.DicomMetaDictionary.dictionary) {
31
40
  // if in hex like "(0008,0100)", convert to text key
@@ -92,6 +101,7 @@ export default function getParser(inputPathPattern, inputFilePath, naturalData,
92
101
  getMapping,
93
102
  getDicom,
94
103
  missingDicom,
104
+ protectUid,
95
105
  // TODO: Phase this out in favor of ISO8601 duration handling.
96
106
  // Example of this logic:
97
107
  // ContentDate:
package/dist/esm/index.js CHANGED
@@ -51,7 +51,8 @@ function initializeFileListWorker() {
51
51
  fileListWorker.addEventListener('message', (event) => {
52
52
  switch (event.data.response) {
53
53
  case 'file':
54
- filesToProcess.push(event.data.fileInfo);
54
+ const { fileIndex, fileInfo } = event.data;
55
+ filesToProcess.push({ fileIndex, fileInfo });
55
56
  // Could do some throttling:
56
57
  // if (filesToProcess.length > 10) {
57
58
  // fileListWorker.postMessage({ request: 'stop' })
@@ -63,6 +64,7 @@ function initializeFileListWorker() {
63
64
  directoryScanFinished = true;
64
65
  break;
65
66
  default:
67
+ // @ts-expect-error: response is string here, not never
66
68
  console.error(`Unknown response from worker ${event.data.response}`);
67
69
  }
68
70
  dispatchMappingJobs();
@@ -96,14 +98,12 @@ function initializeMappingWorkers() {
96
98
  mapResultsList.push(event.data.mapResults);
97
99
  workersActive -= 1;
98
100
  // Report progress
99
- if (progressCallback) {
100
- progressCallback({
101
- response: 'progress',
102
- mapResults: event.data.mapResults,
103
- processedFiles: mapResultsList.length,
104
- totalFiles: filesToProcess.length + mapResultsList.length + workersActive,
105
- });
106
- }
101
+ progressCallback({
102
+ response: 'progress',
103
+ mapResults: event.data.mapResults,
104
+ processedFiles: mapResultsList.length,
105
+ totalFiles: filesToProcess.length + mapResultsList.length + workersActive,
106
+ });
107
107
  dispatchMappingJobs();
108
108
  if (mapResultsList.length % 100 === 0) {
109
109
  console.log(`Finished mapping ${mapResultsList.length} files`);
@@ -119,7 +119,7 @@ function initializeMappingWorkers() {
119
119
  }
120
120
  function dispatchMappingJobs() {
121
121
  while (filesToProcess.length > 0 && availableMappingWorkers.length > 0) {
122
- const fileInfo = filesToProcess.pop();
122
+ const { fileInfo, fileIndex } = filesToProcess.pop();
123
123
  const mappingWorker = availableMappingWorkers.pop();
124
124
  const _a =
125
125
  // Not partial anymore.
@@ -127,6 +127,7 @@ function dispatchMappingJobs() {
127
127
  mappingWorker.postMessage({
128
128
  request: 'apply',
129
129
  fileInfo,
130
+ fileIndex,
130
131
  outputDirectory,
131
132
  serializedMappingOptions: serializeMappingOptions(mappingOptions),
132
133
  });
@@ -142,6 +143,12 @@ function dispatchMappingJobs() {
142
143
  clearCaches();
143
144
  console.log(`Finished mapping ${mapResultsList.length} files`);
144
145
  console.log('job is finished');
146
+ progressCallback({
147
+ response: 'done',
148
+ mapResultsList: mapResultsList,
149
+ processedFiles: mapResultsList.length,
150
+ totalFiles: mapResultsList.length,
151
+ });
145
152
  }
146
153
  }
147
154
  function collectMappingOptions(organizeOptions) {
@@ -182,7 +189,7 @@ function collectMappingOptions(organizeOptions) {
182
189
  });
183
190
  }
184
191
  function queueFilesForMapping(organizeOptions) {
185
- organizeOptions.inputFiles.forEach((inputFile) => {
192
+ organizeOptions.inputFiles.forEach((inputFile, fileIndex) => {
186
193
  const fileInfo = {
187
194
  path: '',
188
195
  name: inputFile.name,
@@ -190,38 +197,51 @@ function queueFilesForMapping(organizeOptions) {
190
197
  kind: 'blob',
191
198
  blob: inputFile,
192
199
  };
193
- filesToProcess.push(fileInfo);
200
+ filesToProcess.push({ fileInfo, fileIndex });
194
201
  dispatchMappingJobs();
195
202
  });
196
203
  }
197
204
  let progressCallback;
198
205
  function curateMany(organizeOptions, onProgress) {
199
206
  return __awaiter(this, void 0, void 0, function* () {
200
- progressCallback = onProgress;
201
- // create the mapping workers
202
- initializeMappingWorkers();
203
- // Set global mappingWorkerOptions
204
- mappingWorkerOptions = (yield collectMappingOptions(organizeOptions));
205
- //
206
- // If the request provides a directory, then use the worker
207
- // to recursively convert to fileSystemHandles.
208
- // If the request provides a list of File objects,
209
- // send them to the mapping workers directly.
210
- //
211
- if (organizeOptions.inputType === 'directory') {
212
- const fileListWorker = initializeFileListWorker();
213
- fileListWorker.postMessage({
214
- request: 'scan',
215
- directoryHandle: organizeOptions.inputDirectory,
216
- });
217
- }
218
- else if (organizeOptions.inputType === 'files') {
219
- queueFilesForMapping(organizeOptions);
220
- }
221
- else {
222
- console.error('`inputType` should be "directory" or "files"');
223
- }
224
- dispatchMappingJobs();
207
+ return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
208
+ // Resolve promise if progressCallback gets called with 'done'
209
+ progressCallback = (msg) => {
210
+ onProgress === null || onProgress === void 0 ? void 0 : onProgress(msg);
211
+ if (msg.response === 'done') {
212
+ resolve(msg);
213
+ }
214
+ };
215
+ try {
216
+ // create the mapping workers
217
+ initializeMappingWorkers();
218
+ // Set global mappingWorkerOptions
219
+ mappingWorkerOptions = (yield collectMappingOptions(organizeOptions));
220
+ //
221
+ // If the request provides a directory, then use the worker
222
+ // to recursively convert to fileSystemHandles.
223
+ // If the request provides a list of File objects,
224
+ // send them to the mapping workers directly.
225
+ //
226
+ if (organizeOptions.inputType === 'directory') {
227
+ const fileListWorker = initializeFileListWorker();
228
+ fileListWorker.postMessage({
229
+ request: 'scan',
230
+ directoryHandle: organizeOptions.inputDirectory,
231
+ });
232
+ }
233
+ else if (organizeOptions.inputType === 'files') {
234
+ queueFilesForMapping(organizeOptions);
235
+ }
236
+ else {
237
+ console.error('`inputType` should be "directory" or "files"');
238
+ }
239
+ dispatchMappingJobs();
240
+ }
241
+ catch (error) {
242
+ reject(error);
243
+ }
244
+ }));
225
245
  });
226
246
  }
227
247
  export { curateMany, curateOne, extractColumnMappings, clearCaches };
@@ -34,27 +34,14 @@ function scanDirectory(dir) {
34
34
  function traverse(dir, prefix) {
35
35
  return __awaiter(this, void 0, void 0, function* () {
36
36
  var _a, e_1, _b, _c;
37
+ // First, collect sorted dir entries
38
+ const entries = [];
37
39
  try {
38
40
  for (var _d = true, _e = __asyncValues(dir.values()), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
39
41
  _c = _f.value;
40
42
  _d = false;
41
43
  const entry = _c;
42
- if (entry.kind === 'file' && keepScanning) {
43
- const file = yield entry.getFile();
44
- self.postMessage({
45
- response: 'file',
46
- fileInfo: {
47
- path: prefix,
48
- name: entry.name,
49
- size: file.size,
50
- kind: 'handle',
51
- fileHandle: entry,
52
- },
53
- });
54
- }
55
- else if (entry.kind === 'directory' && keepScanning) {
56
- yield traverse(entry, prefix + '/' + entry.name);
57
- }
44
+ entries.push(entry);
58
45
  }
59
46
  }
60
47
  catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -64,6 +51,28 @@ function scanDirectory(dir) {
64
51
  }
65
52
  finally { if (e_1) throw e_1.error; }
66
53
  }
54
+ entries.sort((a, b) => a.name.localeCompare(b.name));
55
+ // Assign sorted index to files
56
+ let fileIndex = 0;
57
+ for (const entry of entries) {
58
+ if (entry.kind === 'file' && keepScanning) {
59
+ const file = yield entry.getFile();
60
+ self.postMessage({
61
+ response: 'file',
62
+ fileIndex: fileIndex++,
63
+ fileInfo: {
64
+ path: prefix,
65
+ name: entry.name,
66
+ size: file.size,
67
+ kind: 'handle',
68
+ fileHandle: entry,
69
+ },
70
+ });
71
+ }
72
+ else if (entry.kind === 'directory' && keepScanning) {
73
+ yield traverse(entry, prefix + '/' + entry.name);
74
+ }
75
+ }
67
76
  });
68
77
  }
69
78
  yield traverse(dir, dir.name);
@@ -1 +1,8 @@
1
- export {};
1
+ import type { TFileInfo, TSerializedMappingOptions } from './types';
2
+ export type MappingRequest = {
3
+ request: 'apply';
4
+ fileInfo: TFileInfo;
5
+ fileIndex: number;
6
+ outputDirectory?: FileSystemDirectoryHandle;
7
+ serializedMappingOptions: TSerializedMappingOptions;
8
+ };
@@ -1,3 +1,3 @@
1
1
  import type { TMappingOptions, TMapResults } from './types';
2
2
  import type { TDicomData, TNaturalData } from 'dcmjs';
3
- export default function collectMappings(inputFilePath: string, dicomData: TDicomData, mappingOptions: TMappingOptions): [TNaturalData, TMapResults];
3
+ export default function collectMappings(inputFilePath: string, inputFileIndex: number, dicomData: TDicomData, mappingOptions: TMappingOptions): [TNaturalData, TMapResults];
@@ -1,7 +1,7 @@
1
1
  import * as dcmjs from 'dcmjs';
2
2
  import type { TDicomData } from 'dcmjs';
3
3
  import type { TMappingOptions } from './types';
4
- export default function curateDict(inputFilePath: string, dicomData: TDicomData, mappingOptions: TMappingOptions): {
4
+ export default function curateDict(inputFilePath: string, inputFileIndex: number, dicomData: TDicomData, mappingOptions: TMappingOptions): {
5
5
  dicomData: dcmjs.data.DicomDict;
6
6
  mapResults: import("./types").TMapResults;
7
7
  };
@@ -1,4 +1,10 @@
1
1
  import type { TFileInfo, TMappingOptions, TMapResults } from './types';
2
- export declare function curateOne(fileInfo: TFileInfo, outputDirectory: FileSystemDirectoryHandle | undefined, mappingOptions: TMappingOptions): Promise<Omit<Partial<TMapResults>, 'anomalies'> & {
2
+ export type TCurateOneArgs = {
3
+ fileInfo: TFileInfo;
4
+ fileIndex?: number;
5
+ outputDirectory: FileSystemDirectoryHandle | undefined;
6
+ mappingOptions: TMappingOptions;
7
+ };
8
+ export declare function curateOne({ fileInfo, fileIndex, outputDirectory, mappingOptions, }: TCurateOneArgs): Promise<Omit<Partial<TMapResults>, 'anomalies'> & {
3
9
  anomalies: TMapResults['anomalies'];
4
10
  }>;
@@ -1,5 +1,6 @@
1
1
  import type { TNaturalData } from 'dcmjs';
2
2
  import type { Iso8601Duration, TPs315Options, TMapResults } from './types';
3
+ export declare function protectUid(uid: string, retainUIDsOption: string): string;
3
4
  export default function deidentifyPS315E({ naturalData, dicomPS315EOptions, dateOffset, mapResults, }: {
4
5
  naturalData: TNaturalData;
5
6
  dicomPS315EOptions: TPs315Options;
@@ -6,4 +6,4 @@ export declare const FILENAME: symbol;
6
6
  declare const clearUniqueNumberCache: () => void;
7
7
  declare const clearUniqueInGroupCache: () => void;
8
8
  export { clearUniqueNumberCache, clearUniqueInGroupCache };
9
- export default function getParser(inputPathPattern: string, inputFilePath: string, naturalData: TNaturalData, columnMappings?: TColumnMappings, additionalData?: TCurationSpecification['additionalData']): TParser;
9
+ export default function getParser(inputPathPattern: string, inputFilePath: string, naturalData: TNaturalData, dicomPS315EOptions: TCurationSpecification['dicomPS315EOptions'], columnMappings?: TColumnMappings, additionalData?: TCurationSpecification['additionalData']): TParser;
@@ -1,12 +1,13 @@
1
1
  import { extractColumnMappings } from './csvMapping';
2
2
  import { clearCaches } from './clearCaches';
3
3
  import { curateOne } from './curateOne';
4
- import type { OrganizeOptions, TProgressMessage } from './types';
4
+ import type { OrganizeOptions, TProgressMessage, TProgressMessageDone } from './types';
5
5
  export type ProgressCallback = (message: TProgressMessage) => void;
6
6
  export type { TPs315Options, TMapResults, TProgressMessage, OrganizeOptions, TCurationSpecification, } from './types';
7
+ export { TCurateOneArgs } from './curateOne';
7
8
  export { specVersion } from './config/specVersion';
8
9
  export { sample2PassCurationSpecification as sampleSpecification } from './config/sample2PassCurationSpecification';
9
10
  export { csvTextToRows } from './csvMapping';
10
11
  export type { Row } from './csvMapping';
11
- declare function curateMany(organizeOptions: OrganizeOptions, onProgress?: ProgressCallback): Promise<void>;
12
+ declare function curateMany(organizeOptions: OrganizeOptions, onProgress?: ProgressCallback): Promise<TProgressMessageDone>;
12
13
  export { curateMany, curateOne, extractColumnMappings, clearCaches };
@@ -1 +1,9 @@
1
+ import type { TFileInfo } from './types';
1
2
  export {};
3
+ export type FileScanMsg = {
4
+ response: 'file';
5
+ fileIndex: number;
6
+ fileInfo: TFileInfo;
7
+ } | {
8
+ response: 'done';
9
+ };
@@ -1,7 +1,3 @@
1
- import { TMappingOptions } from './types';
2
- type TSerializedMappingOptions = Omit<TMappingOptions, 'curationSpec'> & {
3
- curationSpecStr: string;
4
- };
1
+ import { TMappingOptions, TSerializedMappingOptions } from './types';
5
2
  export declare function serializeMappingOptions(mappingOptions: TMappingOptions): TSerializedMappingOptions;
6
3
  export declare function deserializeMappingOptions(serializedMappingOptions: TSerializedMappingOptions): TMappingOptions;
7
- export {};
@@ -34,6 +34,9 @@ export type TMappingOptions = {
34
34
  skipValidation?: boolean;
35
35
  dateOffset?: Iso8601Duration;
36
36
  };
37
+ export type TSerializedMappingOptions = Omit<TMappingOptions, 'curationSpec'> & {
38
+ curationSpecStr: string;
39
+ };
37
40
  export type TFileInfo = {
38
41
  path: string;
39
42
  name: string;
@@ -92,6 +95,7 @@ export type TParser = {
92
95
  getMapping: ((value: string) => string | number) | undefined;
93
96
  getDicom: (attrName: string) => any;
94
97
  missingDicom: (attrName: string) => boolean;
98
+ protectUid: (uid: string) => string;
95
99
  addDays: (dicomDateString: string, offsetDays: number) => string;
96
100
  FILENAME: symbol;
97
101
  FILEBASENAME: symbol;
@@ -134,11 +138,18 @@ export type TCurationSpecification = {
134
138
  mapping: TMappedValues;
135
139
  } & (TMappingInputDirect | TMappingInputTwoPass);
136
140
  };
137
- export type TProgressMessage = {
138
- response: 'start' | 'progress' | 'finished' | 'error';
141
+ type TProgressMessageBase = {
139
142
  totalFiles?: number;
140
143
  processedFiles?: number;
144
+ };
145
+ type TProgressMessageProgress = TProgressMessageBase & {
146
+ response: 'progress';
141
147
  mapResults?: TMapResults;
142
148
  error?: Error;
143
149
  };
150
+ export type TProgressMessageDone = TProgressMessageBase & {
151
+ response: 'done';
152
+ mapResultsList: TMapResults[];
153
+ };
154
+ export type TProgressMessage = TProgressMessageProgress | TProgressMessageDone;
144
155
  export {};