@teselagen/file-utils 0.0.3 → 0.2.1
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/.eslintrc.json +18 -0
- package/CHANGELOG.md +26 -0
- package/jest.config.js +10 -0
- package/package.json +3 -5
- package/project.json +51 -0
- package/{index.js → src/file-utils.js} +141 -91
- package/src/file-utils.spec.js +6 -0
- package/src/index.js +1 -0
- package/tsconfig.json +23 -0
- package/tsconfig.lib.json +16 -0
- package/tsconfig.spec.json +14 -0
package/.eslintrc.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": ["../../.eslintrc.json"],
|
|
3
|
+
"ignorePatterns": ["!**/*"],
|
|
4
|
+
"overrides": [
|
|
5
|
+
{
|
|
6
|
+
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
|
7
|
+
"rules": {}
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"files": ["*.ts", "*.tsx"],
|
|
11
|
+
"rules": {}
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"files": ["*.js", "*.jsx"],
|
|
15
|
+
"rules": {}
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
|
|
4
|
+
|
|
5
|
+
## [0.2.0](https://github.com/TeselaGen/tg-oss/compare/file-utils-0.1.0...file-utils-0.2.0) (2023-05-30)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* more work on packaging up files ([67c8a69](https://github.com/TeselaGen/tg-oss/commit/67c8a6983b2ca772cc72700b4bf344b4adccf26d))
|
|
11
|
+
|
|
12
|
+
## [0.2.0](https://github.com/TeselaGen/tg-oss/compare/file-utils-0.1.0...file-utils-0.2.0) (2023-05-30)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* more work on packaging up files ([67c8a69](https://github.com/TeselaGen/tg-oss/commit/67c8a6983b2ca772cc72700b4bf344b4adccf26d))
|
|
18
|
+
|
|
19
|
+
## 0.1.0 (2023-05-30)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Features
|
|
23
|
+
|
|
24
|
+
* more work adding more repos ([f320d76](https://github.com/TeselaGen/tg-oss/commit/f320d76a7a2e0db34d68d1a51803efa24f6831df))
|
|
25
|
+
* wip adding a bunch of repos to tg-oss ([6040094](https://github.com/TeselaGen/tg-oss/commit/60400941f0d7f72c02bf19b90896d9a35d32634d))
|
|
26
|
+
* wip setting up nx ([24a1952](https://github.com/TeselaGen/tg-oss/commit/24a1952fdbadc2c733223109d620cbc508c94a28))
|
package/jest.config.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
module.exports = {
|
|
3
|
+
displayName: 'file-utils',
|
|
4
|
+
preset: '../../jest.preset.js',
|
|
5
|
+
transform: {
|
|
6
|
+
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
|
|
7
|
+
},
|
|
8
|
+
moduleFileExtensions: ['ts', 'js', 'html'],
|
|
9
|
+
coverageDirectory: '../../coverage/packages/file-utils',
|
|
10
|
+
};
|
package/package.json
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teselagen/file-utils",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"type": "
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"type": "commonjs",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"bluebird": "^3.7.2",
|
|
7
7
|
"jszip": "^3.10.1",
|
|
8
8
|
"lodash": "^4.17.21",
|
|
9
9
|
"papaparse": "^5.4.1"
|
|
10
|
-
}
|
|
11
|
-
"module": "index.js",
|
|
12
|
-
"main": "index.js"
|
|
10
|
+
}
|
|
13
11
|
}
|
package/project.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "file-utils",
|
|
3
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
+
"sourceRoot": "packages/file-utils/src",
|
|
5
|
+
"projectType": "library",
|
|
6
|
+
"targets": {
|
|
7
|
+
"version": {
|
|
8
|
+
"executor": "@jscutlery/semver:version",
|
|
9
|
+
"options": {
|
|
10
|
+
"preset": "conventional"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"build": {
|
|
14
|
+
"executor": "@nx/esbuild:esbuild",
|
|
15
|
+
"outputs": ["{options.outputPath}"],
|
|
16
|
+
"options": {
|
|
17
|
+
"outputPath": "dist/packages/file-utils",
|
|
18
|
+
"main": "packages/file-utils/src/index.js",
|
|
19
|
+
"tsConfig": "packages/file-utils/tsconfig.lib.json",
|
|
20
|
+
"assets": ["packages/file-utils/*.md"],
|
|
21
|
+
"generatePackageJson": true
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"publish": {
|
|
25
|
+
"command": "node tools/scripts/publish.mjs file-utils {args.ver} {args.tag}",
|
|
26
|
+
"dependsOn": ["build"]
|
|
27
|
+
},
|
|
28
|
+
"lint": {
|
|
29
|
+
"executor": "@nx/linter:eslint",
|
|
30
|
+
"outputs": ["{options.outputFile}"],
|
|
31
|
+
"options": {
|
|
32
|
+
"lintFilePatterns": ["packages/file-utils/**/*.js"]
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"test": {
|
|
36
|
+
"executor": "@nx/jest:jest",
|
|
37
|
+
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
|
38
|
+
"options": {
|
|
39
|
+
"jestConfig": "packages/file-utils/jest.config.js",
|
|
40
|
+
"passWithNoTests": true
|
|
41
|
+
},
|
|
42
|
+
"configurations": {
|
|
43
|
+
"ci": {
|
|
44
|
+
"ci": true,
|
|
45
|
+
"codeCoverage": true
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"tags": []
|
|
51
|
+
}
|
|
@@ -1,40 +1,45 @@
|
|
|
1
|
-
|
|
1
|
+
/* Copyright (C) 2018 TeselaGen Biotechnology, Inc. */
|
|
2
2
|
import { camelCase, flatMap, remove, startsWith, snakeCase } from "lodash";
|
|
3
3
|
import { loadAsync } from "jszip";
|
|
4
|
-
import
|
|
4
|
+
import Promise from "bluebird";
|
|
5
5
|
import { parse, unparse } from "papaparse";
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
const logDebug = (...args) => {
|
|
7
8
|
if (process.env.DEBUG_CSV_PARSING) {
|
|
9
|
+
// eslint-disable-next-line no-console
|
|
8
10
|
console.log(...args);
|
|
9
11
|
}
|
|
10
12
|
};
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
|
|
14
|
+
export const allowedCsvFileTypes = [".csv", ".txt", ".xlsx"];
|
|
15
|
+
|
|
16
|
+
export const isZipFile = file => {
|
|
13
17
|
const type = file.mimetype || file.type;
|
|
14
18
|
return type === "application/zip" || type === "application/x-zip-compressed";
|
|
15
19
|
};
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
|
|
21
|
+
export const getExt = file => file.name.split(".").pop();
|
|
22
|
+
export const isExcelFile = file => getExt(file) === "xlsx";
|
|
23
|
+
export const isCsvFile = file => getExt(file) === "csv";
|
|
24
|
+
export const isTextFile = file => ["text", "txt"].includes(getExt(file));
|
|
25
|
+
|
|
26
|
+
export const isCsvOrExcelFile = file => isCsvFile(file) || isExcelFile(file);
|
|
27
|
+
|
|
28
|
+
export const extractZipFiles = async allFiles => {
|
|
29
|
+
if (!Array.isArray(allFiles)) allFiles = [allFiles];
|
|
30
|
+
// make a copy so we don't mutate the form value
|
|
24
31
|
allFiles = [...allFiles];
|
|
25
32
|
const zipFiles = remove(allFiles, isZipFile);
|
|
26
|
-
if (!zipFiles.length)
|
|
27
|
-
return allFiles;
|
|
33
|
+
if (!zipFiles.length) return allFiles;
|
|
28
34
|
const zipFilesArray = Array.isArray(zipFiles) ? zipFiles : [zipFiles];
|
|
29
|
-
const parsedZips = await
|
|
30
|
-
|
|
31
|
-
(file) => loadAsync(file instanceof Blob ? file : file.originFileObj)
|
|
35
|
+
const parsedZips = await Promise.map(zipFilesArray, file =>
|
|
36
|
+
loadAsync(file instanceof Blob ? file : file.originFileObj)
|
|
32
37
|
);
|
|
33
|
-
const zippedFiles = flatMap(
|
|
34
|
-
|
|
35
|
-
(zip) => Object.keys(zip.files).map((key) => zip.files[key])
|
|
38
|
+
const zippedFiles = flatMap(parsedZips, zip =>
|
|
39
|
+
Object.keys(zip.files).map(key => zip.files[key])
|
|
36
40
|
);
|
|
37
|
-
const unzippedFiles = await
|
|
41
|
+
const unzippedFiles = await Promise.map(zippedFiles, file => {
|
|
42
|
+
// converts the compressed file to a string of its contents
|
|
38
43
|
return file.async("blob").then(function(fileData) {
|
|
39
44
|
const newFileObj = new File([fileData], file.name);
|
|
40
45
|
return {
|
|
@@ -47,32 +52,38 @@ var extractZipFiles = async (allFiles) => {
|
|
|
47
52
|
if (unzippedFiles.length) {
|
|
48
53
|
return allFiles.concat(
|
|
49
54
|
unzippedFiles.filter(
|
|
50
|
-
({ name, originFileObj }) =>
|
|
55
|
+
({ name, originFileObj }) =>
|
|
56
|
+
!name.includes("__MACOSX") &&
|
|
57
|
+
!name.includes(".DS_Store") &&
|
|
58
|
+
originFileObj.size !== 0
|
|
51
59
|
)
|
|
52
60
|
);
|
|
53
61
|
} else {
|
|
54
62
|
return allFiles;
|
|
55
63
|
}
|
|
56
64
|
};
|
|
57
|
-
|
|
65
|
+
|
|
66
|
+
const defaultCsvParserOptions = {
|
|
58
67
|
header: true,
|
|
59
68
|
skipEmptyLines: "greedy",
|
|
60
69
|
trimHeaders: true
|
|
61
70
|
};
|
|
62
|
-
|
|
71
|
+
export const setupCsvParserOptions = (parserOptions = {}) => {
|
|
63
72
|
const {
|
|
64
73
|
camelCaseHeaders = false,
|
|
65
74
|
lowerCaseHeaders = false,
|
|
66
75
|
...rest
|
|
67
76
|
} = parserOptions;
|
|
77
|
+
|
|
68
78
|
const papaParseOpts = { ...rest };
|
|
69
79
|
if (camelCaseHeaders) {
|
|
70
80
|
logDebug("[CSV-PARSER] camelCasing headers");
|
|
71
|
-
papaParseOpts.transformHeader =
|
|
81
|
+
papaParseOpts.transformHeader = header => {
|
|
72
82
|
let transHeader = header;
|
|
73
83
|
if (!startsWith(header.trim(), "ext-")) {
|
|
74
84
|
transHeader = camelCase(header);
|
|
75
85
|
}
|
|
86
|
+
|
|
76
87
|
if (transHeader) {
|
|
77
88
|
logDebug(
|
|
78
89
|
`[CSV-PARSER] Transformed header from: ${header} to: ${transHeader}`
|
|
@@ -81,14 +92,16 @@ var setupCsvParserOptions = (parserOptions = {}) => {
|
|
|
81
92
|
} else {
|
|
82
93
|
logDebug(`[CSV-PARSER] Not transforming header: ${header}`);
|
|
83
94
|
}
|
|
95
|
+
|
|
84
96
|
return transHeader;
|
|
85
97
|
};
|
|
86
98
|
} else if (lowerCaseHeaders) {
|
|
87
|
-
papaParseOpts.transformHeader =
|
|
99
|
+
papaParseOpts.transformHeader = header => {
|
|
88
100
|
let transHeader = header;
|
|
89
101
|
if (!startsWith(header, "ext-")) {
|
|
90
102
|
transHeader = header.toLowerCase();
|
|
91
103
|
}
|
|
104
|
+
|
|
92
105
|
if (transHeader) {
|
|
93
106
|
logDebug(
|
|
94
107
|
`[CSV-PARSER] Transformed header from: ${header} to: ${transHeader}`
|
|
@@ -97,30 +110,35 @@ var setupCsvParserOptions = (parserOptions = {}) => {
|
|
|
97
110
|
} else {
|
|
98
111
|
logDebug(`[CSV-PARSER] Not transforming header: ${header}`);
|
|
99
112
|
}
|
|
113
|
+
|
|
100
114
|
return transHeader;
|
|
101
115
|
};
|
|
102
116
|
}
|
|
117
|
+
|
|
103
118
|
return papaParseOpts;
|
|
104
119
|
};
|
|
105
|
-
|
|
106
|
-
|
|
120
|
+
|
|
121
|
+
const normalizeCsvHeaderHelper = h => snakeCase(h.toUpperCase()).toUpperCase();
|
|
122
|
+
|
|
123
|
+
export function normalizeCsvHeader(header) {
|
|
107
124
|
if (header.startsWith("ext-") || header.startsWith("EXT-")) {
|
|
108
125
|
return header;
|
|
109
126
|
}
|
|
110
127
|
return normalizeCsvHeaderHelper(header);
|
|
111
128
|
}
|
|
112
|
-
|
|
113
|
-
|
|
129
|
+
|
|
130
|
+
export const parseCsvFile = (csvFile, parserOptions = {}) => {
|
|
131
|
+
return new Promise((resolve, reject) => {
|
|
114
132
|
const opts = {
|
|
115
133
|
...defaultCsvParserOptions,
|
|
116
134
|
...setupCsvParserOptions(parserOptions),
|
|
117
|
-
complete:
|
|
135
|
+
complete: results => {
|
|
118
136
|
if (results && results.errors && results.errors.length) {
|
|
119
137
|
return reject("Error in csv: " + JSON.stringify(results.errors));
|
|
120
138
|
}
|
|
121
139
|
resolve(results);
|
|
122
140
|
},
|
|
123
|
-
error:
|
|
141
|
+
error: error => {
|
|
124
142
|
reject(error);
|
|
125
143
|
}
|
|
126
144
|
};
|
|
@@ -128,11 +146,28 @@ var parseCsvFile = (csvFile, parserOptions = {}) => {
|
|
|
128
146
|
parse(csvFile.originFileObj, opts);
|
|
129
147
|
});
|
|
130
148
|
};
|
|
131
|
-
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Gets a properly formatted json object into s csv string
|
|
152
|
+
* https://www.papaparse.com/docs#json-to-csv
|
|
153
|
+
* const options = {
|
|
154
|
+
quotes: false, //or array of booleans
|
|
155
|
+
quoteChar: '"',
|
|
156
|
+
escapeChar: '"',
|
|
157
|
+
delimiter: ",",
|
|
158
|
+
header: true,
|
|
159
|
+
newline: "\r\n",
|
|
160
|
+
skipEmptyLines: false, //other option is 'greedy', meaning skip delimiters, quotes, and whitespace.
|
|
161
|
+
columns: null //or array of strings
|
|
162
|
+
}
|
|
163
|
+
* @returns csv as string
|
|
164
|
+
*/
|
|
165
|
+
export const jsonToCsv = (jsonData, options = {}) => {
|
|
132
166
|
const csv = unparse(jsonData, options);
|
|
133
167
|
return csv;
|
|
134
168
|
};
|
|
135
|
-
|
|
169
|
+
|
|
170
|
+
export const parseCsvString = (csvString, parserOptions = {}) => {
|
|
136
171
|
const opts = {
|
|
137
172
|
...defaultCsvParserOptions,
|
|
138
173
|
...setupCsvParserOptions(parserOptions)
|
|
@@ -140,25 +175,27 @@ var parseCsvString = (csvString, parserOptions = {}) => {
|
|
|
140
175
|
logDebug(`[CSV-PARSER] parseCsvString opts:`, opts);
|
|
141
176
|
return parse(csvString, opts);
|
|
142
177
|
};
|
|
143
|
-
|
|
178
|
+
|
|
179
|
+
export async function parseCsvOrExcelFile(
|
|
180
|
+
fileOrFiles,
|
|
181
|
+
{ csvParserOptions } = {}
|
|
182
|
+
) {
|
|
144
183
|
let csvFile, excelFile, txtFile;
|
|
145
184
|
if (Array.isArray(fileOrFiles)) {
|
|
146
185
|
csvFile = fileOrFiles.find(isCsvFile);
|
|
147
186
|
excelFile = fileOrFiles.find(isExcelFile);
|
|
148
187
|
txtFile = fileOrFiles.find(isTextFile);
|
|
149
188
|
} else {
|
|
150
|
-
if (isExcelFile(fileOrFiles))
|
|
151
|
-
|
|
152
|
-
else if (
|
|
153
|
-
csvFile = fileOrFiles;
|
|
154
|
-
else if (isTextFile(fileOrFiles))
|
|
155
|
-
txtFile = fileOrFiles;
|
|
189
|
+
if (isExcelFile(fileOrFiles)) excelFile = fileOrFiles;
|
|
190
|
+
else if (isCsvFile(fileOrFiles)) csvFile = fileOrFiles;
|
|
191
|
+
else if (isTextFile(fileOrFiles)) txtFile = fileOrFiles;
|
|
156
192
|
}
|
|
157
193
|
if (!csvFile && !excelFile && !txtFile) {
|
|
158
194
|
throw new Error("No csv or excel files found");
|
|
159
195
|
}
|
|
160
|
-
|
|
161
|
-
|
|
196
|
+
|
|
197
|
+
if (!csvFile && !excelFile) csvFile = txtFile;
|
|
198
|
+
|
|
162
199
|
if (!csvFile && excelFile && window.parseExcelToCsv) {
|
|
163
200
|
csvFile = await window.parseExcelToCsv(
|
|
164
201
|
excelFile.originFileObj || excelFile
|
|
@@ -173,8 +210,13 @@ async function parseCsvOrExcelFile(fileOrFiles, { csvParserOptions } = {}) {
|
|
|
173
210
|
parsedCsv.originalFile = csvFile;
|
|
174
211
|
return parsedCsv;
|
|
175
212
|
}
|
|
176
|
-
|
|
177
|
-
|
|
213
|
+
|
|
214
|
+
export const validateCSVRequiredHeaders = (
|
|
215
|
+
fields,
|
|
216
|
+
requiredHeaders,
|
|
217
|
+
filename
|
|
218
|
+
) => {
|
|
219
|
+
const missingRequiredHeaders = requiredHeaders.filter(field => {
|
|
178
220
|
return !fields.includes(field);
|
|
179
221
|
});
|
|
180
222
|
if (missingRequiredHeaders.length) {
|
|
@@ -184,64 +226,91 @@ var validateCSVRequiredHeaders = (fields, requiredHeaders, filename) => {
|
|
|
184
226
|
)})`;
|
|
185
227
|
}
|
|
186
228
|
};
|
|
187
|
-
|
|
188
|
-
|
|
229
|
+
|
|
230
|
+
export const validateCSVRow = (row, requiredHeaders, index) => {
|
|
231
|
+
const missingRequiredFields = requiredHeaders.filter(field => !row[field]);
|
|
189
232
|
if (missingRequiredFields.length) {
|
|
190
233
|
if (missingRequiredFields.length === 1) {
|
|
191
|
-
return `Row ${index + 1} is missing the required field "${
|
|
234
|
+
return `Row ${index + 1} is missing the required field "${
|
|
235
|
+
missingRequiredFields[0]
|
|
236
|
+
}"`;
|
|
192
237
|
} else {
|
|
193
|
-
return `Row ${index +
|
|
238
|
+
return `Row ${index +
|
|
239
|
+
1} is missing these required fields: ${missingRequiredFields.join(
|
|
194
240
|
", "
|
|
195
241
|
)}`;
|
|
196
242
|
}
|
|
197
243
|
}
|
|
198
244
|
};
|
|
199
|
-
|
|
200
|
-
|
|
245
|
+
|
|
246
|
+
export const cleanCommaSeparatedCell = cellData =>
|
|
247
|
+
(cellData || "")
|
|
248
|
+
.split(",")
|
|
249
|
+
.map(n => n.trim())
|
|
250
|
+
.filter(n => n);
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Because the csv rows might not have the same header keys in some cases (extended properties)
|
|
254
|
+
* this function will make sure that each row will have all headers so that the export
|
|
255
|
+
* does not drop fields
|
|
256
|
+
* @param {*} rows
|
|
257
|
+
*/
|
|
258
|
+
export const cleanCsvExport = rows => {
|
|
201
259
|
const allHeaders = [];
|
|
202
|
-
rows.forEach(
|
|
203
|
-
Object.keys(row).forEach(
|
|
260
|
+
rows.forEach(row => {
|
|
261
|
+
Object.keys(row).forEach(header => {
|
|
204
262
|
if (!allHeaders.includes(header)) {
|
|
205
263
|
allHeaders.push(header);
|
|
206
264
|
}
|
|
207
265
|
});
|
|
208
266
|
});
|
|
209
|
-
rows.forEach(
|
|
210
|
-
allHeaders.forEach(
|
|
267
|
+
rows.forEach(row => {
|
|
268
|
+
allHeaders.forEach(header => {
|
|
211
269
|
row[header] = row[header] || "";
|
|
212
270
|
});
|
|
213
271
|
});
|
|
214
272
|
return rows;
|
|
215
273
|
};
|
|
216
|
-
|
|
274
|
+
|
|
275
|
+
export const filterFilesInZip = async (file, accepted) => {
|
|
217
276
|
const zipExtracted = await extractZipFiles(file);
|
|
218
277
|
const acceptedFiles = [];
|
|
219
278
|
for (const extFile of zipExtracted) {
|
|
220
279
|
const extension = "." + getExt(extFile);
|
|
221
|
-
if (accepted.some(
|
|
280
|
+
if (accepted.some(ext => ext === extension)) {
|
|
222
281
|
acceptedFiles.push(extFile);
|
|
223
282
|
}
|
|
224
283
|
}
|
|
284
|
+
|
|
225
285
|
if (acceptedFiles.length && acceptedFiles.length < zipExtracted.length)
|
|
226
286
|
window.toastr.warning("Some files don't have the proper file extension.");
|
|
287
|
+
|
|
227
288
|
if (!acceptedFiles.length)
|
|
228
289
|
window.toastr.warning("No files with the proper extension were found.");
|
|
290
|
+
|
|
229
291
|
return acceptedFiles;
|
|
230
292
|
};
|
|
231
|
-
|
|
293
|
+
|
|
294
|
+
export function removeExt(filename) {
|
|
232
295
|
if (filename && filename.includes(".")) {
|
|
233
|
-
return filename
|
|
296
|
+
return filename
|
|
297
|
+
.split(".")
|
|
298
|
+
.slice(0, -1)
|
|
299
|
+
.join(".");
|
|
234
300
|
} else {
|
|
235
301
|
return filename;
|
|
236
302
|
}
|
|
237
303
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
304
|
+
|
|
305
|
+
export async function uploadAndProcessFiles(files = []) {
|
|
306
|
+
if (!files.length) return null;
|
|
307
|
+
|
|
241
308
|
const formData = new FormData();
|
|
242
309
|
files.forEach(({ originFileObj }) => formData.append("file", originFileObj));
|
|
310
|
+
|
|
243
311
|
const response = await window.api.post("/user_uploads/", formData);
|
|
244
|
-
|
|
312
|
+
|
|
313
|
+
return response.data.map(d => ({
|
|
245
314
|
encoding: d.encoding,
|
|
246
315
|
mimetype: d.mimetype,
|
|
247
316
|
originalname: d.originalname,
|
|
@@ -249,7 +318,8 @@ async function uploadAndProcessFiles(files = []) {
|
|
|
249
318
|
size: d.size
|
|
250
319
|
}));
|
|
251
320
|
}
|
|
252
|
-
|
|
321
|
+
|
|
322
|
+
export async function encodeFilesForRequest(files) {
|
|
253
323
|
const encodedFiles = [];
|
|
254
324
|
for (const file of files) {
|
|
255
325
|
const encoded = await fileToBase64(file.originalFileObj);
|
|
@@ -262,36 +332,16 @@ async function encodeFilesForRequest(files) {
|
|
|
262
332
|
}
|
|
263
333
|
return encodedFiles;
|
|
264
334
|
}
|
|
265
|
-
|
|
266
|
-
|
|
335
|
+
|
|
336
|
+
const fileToBase64 = file => {
|
|
337
|
+
return new Promise(resolve => {
|
|
267
338
|
const reader = new FileReader();
|
|
339
|
+
// Read file content on file loaded event
|
|
268
340
|
reader.onload = function(event) {
|
|
269
341
|
resolve(event.target.result);
|
|
270
342
|
};
|
|
343
|
+
|
|
344
|
+
// Convert data to base64
|
|
271
345
|
reader.readAsDataURL(file);
|
|
272
346
|
});
|
|
273
347
|
};
|
|
274
|
-
export {
|
|
275
|
-
allowedCsvFileTypes,
|
|
276
|
-
cleanCommaSeparatedCell,
|
|
277
|
-
cleanCsvExport,
|
|
278
|
-
encodeFilesForRequest,
|
|
279
|
-
extractZipFiles,
|
|
280
|
-
filterFilesInZip,
|
|
281
|
-
getExt,
|
|
282
|
-
isCsvFile,
|
|
283
|
-
isCsvOrExcelFile,
|
|
284
|
-
isExcelFile,
|
|
285
|
-
isTextFile,
|
|
286
|
-
isZipFile,
|
|
287
|
-
jsonToCsv,
|
|
288
|
-
normalizeCsvHeader,
|
|
289
|
-
parseCsvFile,
|
|
290
|
-
parseCsvOrExcelFile,
|
|
291
|
-
parseCsvString,
|
|
292
|
-
removeExt,
|
|
293
|
-
setupCsvParserOptions,
|
|
294
|
-
uploadAndProcessFiles,
|
|
295
|
-
validateCSVRequiredHeaders,
|
|
296
|
-
validateCSVRow
|
|
297
|
-
};
|
package/src/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './file-utils';
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"allowJs": true,
|
|
6
|
+
"forceConsistentCasingInFileNames": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noImplicitOverride": true,
|
|
9
|
+
"noPropertyAccessFromIndexSignature": true,
|
|
10
|
+
"noImplicitReturns": true,
|
|
11
|
+
"noFallthroughCasesInSwitch": true
|
|
12
|
+
},
|
|
13
|
+
"files": [],
|
|
14
|
+
"include": [],
|
|
15
|
+
"references": [
|
|
16
|
+
{
|
|
17
|
+
"path": "./tsconfig.lib.json"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"path": "./tsconfig.spec.json"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "../../dist/out-tsc",
|
|
5
|
+
"declaration": true,
|
|
6
|
+
"types": ["node"]
|
|
7
|
+
},
|
|
8
|
+
"include": ["src/**/*.ts", "src/**/*.js"],
|
|
9
|
+
"exclude": [
|
|
10
|
+
"jest.config.ts",
|
|
11
|
+
"src/**/*.spec.ts",
|
|
12
|
+
"src/**/*.test.ts",
|
|
13
|
+
"src/**/*.spec.js",
|
|
14
|
+
"src/**/*.test.js"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "../../dist/out-tsc",
|
|
5
|
+
"module": "commonjs",
|
|
6
|
+
"types": ["jest", "node"]
|
|
7
|
+
},
|
|
8
|
+
"include": [
|
|
9
|
+
"jest.config.ts",
|
|
10
|
+
"src/**/*.test.ts",
|
|
11
|
+
"src/**/*.spec.ts",
|
|
12
|
+
"src/**/*.d.ts"
|
|
13
|
+
]
|
|
14
|
+
}
|