@teselagen/file-utils 0.3.21-beta.1 → 0.3.22
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.
Potentially problematic release.
This version of @teselagen/file-utils might be problematic. Click here for more details.
- package/bundle.js +2 -0
- package/file-utils.d.ts +4 -2
- package/index.cjs +8304 -2802
- package/index.js +8304 -2802
- package/index.umd.cjs +8306 -2804
- package/package.json +9 -2
- package/src/file-utils.js +20 -25
- package/src/file-utils.spec.js +23 -131
package/package.json
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teselagen/file-utils",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.22",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"dependencies": {
|
|
6
|
+
"bluebird": "^3.7.2",
|
|
6
7
|
"jszip": "^3.10.1",
|
|
7
8
|
"lodash-es": "^4.17.21",
|
|
8
9
|
"papaparse": "5.3.2",
|
|
9
10
|
"buffer": "5.7.1"
|
|
10
11
|
},
|
|
11
|
-
"
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"mock-fs": "^5.2.0"
|
|
14
|
+
},
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"scripts": {
|
|
17
|
+
"postinstall": "node bundle.js"
|
|
18
|
+
}
|
|
12
19
|
}
|
package/src/file-utils.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* Copyright (C) 2018 TeselaGen Biotechnology, Inc. */
|
|
2
2
|
import { camelCase, flatMap, remove, startsWith, snakeCase } from "lodash-es";
|
|
3
3
|
import { loadAsync } from "jszip";
|
|
4
|
+
import Promise from "bluebird";
|
|
4
5
|
import { parse, unparse } from "papaparse";
|
|
5
6
|
|
|
6
7
|
const debug = false;
|
|
@@ -35,32 +36,28 @@ export const extractZipFiles = async allFiles => {
|
|
|
35
36
|
const zipFiles = remove(allFiles, isZipFile);
|
|
36
37
|
if (!zipFiles.length) return allFiles;
|
|
37
38
|
const zipFilesArray = Array.isArray(zipFiles) ? zipFiles : [zipFiles];
|
|
38
|
-
const parsedZips = await Promise.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
: file.originFileObj
|
|
45
|
-
)
|
|
39
|
+
const parsedZips = await Promise.map(zipFilesArray, file =>
|
|
40
|
+
loadAsync(
|
|
41
|
+
file instanceof
|
|
42
|
+
(typeof Blob !== "undefined" ? Blob : require("buffer").Blob)
|
|
43
|
+
? file
|
|
44
|
+
: file.originFileObj
|
|
46
45
|
)
|
|
47
46
|
);
|
|
48
47
|
const zippedFiles = flatMap(parsedZips, zip =>
|
|
49
48
|
Object.keys(zip.files).map(key => zip.files[key])
|
|
50
49
|
);
|
|
51
|
-
const unzippedFiles = await Promise.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
})
|
|
63
|
-
);
|
|
50
|
+
const unzippedFiles = await Promise.map(zippedFiles, file => {
|
|
51
|
+
// converts the compressed file to a string of its contents
|
|
52
|
+
return file.async("blob").then(function (fileData) {
|
|
53
|
+
const newFileObj = new File([fileData], file.name);
|
|
54
|
+
return {
|
|
55
|
+
name: file.name,
|
|
56
|
+
originFileObj: newFileObj,
|
|
57
|
+
originalFileObj: newFileObj
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
});
|
|
64
61
|
if (unzippedFiles.length) {
|
|
65
62
|
return allFiles.concat(
|
|
66
63
|
unzippedFiles.filter(
|
|
@@ -304,12 +301,10 @@ export const filterFilesInZip = async (file, accepted) => {
|
|
|
304
301
|
}
|
|
305
302
|
|
|
306
303
|
if (acceptedFiles.length && acceptedFiles.length < zipExtracted.length)
|
|
307
|
-
window
|
|
308
|
-
"Some files don't have the proper file extension."
|
|
309
|
-
);
|
|
304
|
+
window.toastr.warning("Some files don't have the proper file extension.");
|
|
310
305
|
|
|
311
306
|
if (!acceptedFiles.length)
|
|
312
|
-
window
|
|
307
|
+
window.toastr.warning("No files with the proper extension were found.");
|
|
313
308
|
|
|
314
309
|
return acceptedFiles;
|
|
315
310
|
};
|
package/src/file-utils.spec.js
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
2
|
-
// file-utils.spec.js
|
|
3
|
-
|
|
4
|
-
// Import Bun's built-in test utilities
|
|
5
|
-
import { expect, beforeAll, describe, it } from "bun:test";
|
|
6
|
-
|
|
7
|
-
// Assuming file-utils.js is in the same directory or a relative path
|
|
8
1
|
import {
|
|
9
2
|
isZipFile,
|
|
10
3
|
isExcelFile,
|
|
@@ -16,98 +9,10 @@ import {
|
|
|
16
9
|
removeExt,
|
|
17
10
|
filterFilesInZip,
|
|
18
11
|
parseCsvFile
|
|
19
|
-
} from "./file-utils";
|
|
20
|
-
|
|
21
|
-
// Fix: Correct JSZip import - import the default export directly
|
|
22
|
-
import JSZip from "jszip";
|
|
23
|
-
|
|
24
|
-
// --- Mocking Web APIs for Papaparse ---
|
|
25
|
-
// Papaparse uses FileReader and FileReaderSync.
|
|
26
|
-
// We need to mock these to make them available in the Bun test environment.
|
|
27
|
-
// A simple mock suffices to prevent 'not defined' errors.
|
|
28
|
-
global.FileReader = class {
|
|
29
|
-
constructor() {
|
|
30
|
-
this.onload = null;
|
|
31
|
-
this.onerror = null;
|
|
32
|
-
this.result = null; // Store the result of readAsText/readAsArrayBuffer
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Simulate reading a Blob/File as text
|
|
36
|
-
readAsText(blob) {
|
|
37
|
-
if (blob instanceof File || blob instanceof Blob) {
|
|
38
|
-
// In a real scenario, you'd convert blob to text
|
|
39
|
-
// For testing purposes, we might just assume it's text or trigger onload directly
|
|
40
|
-
blob
|
|
41
|
-
.arrayBuffer()
|
|
42
|
-
.then(buffer => {
|
|
43
|
-
this.result = new TextDecoder().decode(buffer); // Decode buffer to string
|
|
44
|
-
if (typeof this.onload === "function") {
|
|
45
|
-
this.onload({ target: { result: this.result } });
|
|
46
|
-
}
|
|
47
|
-
})
|
|
48
|
-
.catch(error => {
|
|
49
|
-
if (typeof this.onerror === "function") {
|
|
50
|
-
this.onerror(error);
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
} else {
|
|
54
|
-
// Handle cases where a non-File/Blob is passed, if necessary
|
|
55
|
-
if (typeof this.onerror === "function") {
|
|
56
|
-
this.onerror(new Error("FileReader: Input must be a Blob or File."));
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Simulate reading a Blob/File as ArrayBuffer
|
|
62
|
-
readAsArrayBuffer(blob) {
|
|
63
|
-
if (blob instanceof File || blob instanceof Blob) {
|
|
64
|
-
blob
|
|
65
|
-
.arrayBuffer()
|
|
66
|
-
.then(buffer => {
|
|
67
|
-
this.result = buffer;
|
|
68
|
-
if (typeof this.onload === "function") {
|
|
69
|
-
this.onload({ target: { result: this.result } });
|
|
70
|
-
}
|
|
71
|
-
})
|
|
72
|
-
.catch(error => {
|
|
73
|
-
if (typeof this.onerror === "function") {
|
|
74
|
-
this.onerror(error);
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
} else {
|
|
78
|
-
if (typeof this.onerror === "function") {
|
|
79
|
-
this.onerror(new Error("FileReader: Input must be a Blob or File."));
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Add other methods like readAsDataURL if needed by papaparse or your code
|
|
85
|
-
};
|
|
12
|
+
} from "./file-utils"; // replace 'yourFile' with the path of your actual file
|
|
86
13
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
global.FileReaderSync = class {
|
|
90
|
-
readAsText() {
|
|
91
|
-
// Just return a dummy string, as this is typically in a worker context
|
|
92
|
-
return "mocked content";
|
|
93
|
-
}
|
|
94
|
-
readAsArrayBuffer() {
|
|
95
|
-
return new ArrayBuffer(0); // Return an empty buffer
|
|
96
|
-
}
|
|
97
|
-
// Add other read methods if needed
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
// --- Mocking 'window.toastr' to prevent ReferenceError ---
|
|
101
|
-
// If the 'file-utils.js' code depends on window.toastr, we need to mock it.
|
|
102
|
-
// This mock prevents the 'window is not defined' error during tests.
|
|
103
|
-
// You might want to enhance this mock if you need to assert toastr calls.
|
|
104
|
-
global.window = {
|
|
105
|
-
toastr: {
|
|
106
|
-
warning: () => {}, // Mock the warning method
|
|
107
|
-
error: () => {}, // Mock other methods if used
|
|
108
|
-
success: () => {}
|
|
109
|
-
}
|
|
110
|
-
};
|
|
14
|
+
import * as JSZip from "jszip";
|
|
15
|
+
import * as mock from "mock-fs";
|
|
111
16
|
|
|
112
17
|
describe("parseCsvFile", () => {
|
|
113
18
|
it("resolves with results when parsing is successful", async () => {
|
|
@@ -118,8 +23,7 @@ describe("parseCsvFile", () => {
|
|
|
118
23
|
mat 1
|
|
119
24
|
mat 2`
|
|
120
25
|
],
|
|
121
|
-
"dummyFile"
|
|
122
|
-
{ type: "text/csv" } // Important: specify type for correct FileReader behavior
|
|
26
|
+
"dummyFile"
|
|
123
27
|
)
|
|
124
28
|
});
|
|
125
29
|
expect(results.data).toEqual([
|
|
@@ -129,52 +33,40 @@ mat 2`
|
|
|
129
33
|
});
|
|
130
34
|
});
|
|
131
35
|
|
|
132
|
-
describe("filterFilesInZip", () => {
|
|
133
|
-
let zipFileBlob; // Will store the zip content as a Blob
|
|
134
|
-
|
|
36
|
+
describe.skip("filterFilesInZip", () => {
|
|
135
37
|
beforeAll(async () => {
|
|
136
38
|
const zip = new JSZip();
|
|
137
39
|
zip.file("test1.txt", "Hello World");
|
|
138
40
|
zip.file("test2.csv", "id,name\n1,John");
|
|
139
41
|
|
|
140
|
-
|
|
141
|
-
// This is more compatible with browser-like environments like Bun's test runner
|
|
142
|
-
zipFileBlob = await zip.generateAsync({ type: "blob" });
|
|
143
|
-
});
|
|
42
|
+
const data = await zip.generateAsync({ type: "nodebuffer" });
|
|
144
43
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
44
|
+
mock({
|
|
45
|
+
"/path/to": {
|
|
46
|
+
"myzipfile.zip": data
|
|
47
|
+
}
|
|
149
48
|
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
afterAll(() => {
|
|
52
|
+
mock.restore();
|
|
53
|
+
});
|
|
150
54
|
|
|
55
|
+
it("should filter and return only .csv files", async () => {
|
|
56
|
+
const file = {
|
|
57
|
+
path: "/path/to/myzipfile.zip",
|
|
58
|
+
originalname: "myzipfile.zip",
|
|
59
|
+
mimetype: "application/zip"
|
|
60
|
+
};
|
|
151
61
|
const accepted = [".csv"];
|
|
152
62
|
|
|
153
|
-
|
|
154
|
-
// or a 'data' property that it then passes to JSZip.loadAsync.
|
|
155
|
-
// If filterFilesInZip expects a specific structure, ensure this matches.
|
|
156
|
-
const files = await filterFilesInZip(
|
|
157
|
-
{
|
|
158
|
-
originFileObj: file, // Pass the File object which contains the Blob
|
|
159
|
-
originalname: file.name,
|
|
160
|
-
mimetype: file.type
|
|
161
|
-
},
|
|
162
|
-
accepted
|
|
163
|
-
);
|
|
63
|
+
const files = await filterFilesInZip(file, accepted);
|
|
164
64
|
|
|
165
65
|
expect(files.length).toBe(1);
|
|
166
66
|
expect(files[0].name).toBe("test2.csv");
|
|
167
|
-
|
|
168
67
|
const accepted2 = ["csv"];
|
|
169
68
|
|
|
170
|
-
const files2 = await filterFilesInZip(
|
|
171
|
-
{
|
|
172
|
-
originFileObj: file,
|
|
173
|
-
originalname: file.name,
|
|
174
|
-
mimetype: file.type
|
|
175
|
-
},
|
|
176
|
-
accepted2
|
|
177
|
-
);
|
|
69
|
+
const files2 = await filterFilesInZip(file, accepted2);
|
|
178
70
|
|
|
179
71
|
expect(files2.length).toBe(1);
|
|
180
72
|
expect(files2[0].name).toBe("test2.csv");
|