Skip to content

Commit dfcb70d

Browse files
btargacBurak Targaç
and
Burak Targaç
authored
handle saving files without extensions (#54)
Co-authored-by: Burak Targaç <burak.targac@comeon.com>
1 parent d15dd2e commit dfcb70d

11 files changed

+10401
-6368
lines changed

.babelrc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
],
1212
"plugins": [
1313
["@babel/plugin-transform-runtime", { "corejs": 3 }],
14-
"@babel/plugin-proposal-nullish-coalescing-operator",
15-
"@babel/plugin-proposal-optional-chaining"
14+
"@babel/plugin-proposal-nullish-coalescing-operator"
1615
]
1716
}

.browserslistrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
electron >= 7.1.7
1+
electron >= 12.0.2

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ recursively till every item of the array is processed. For example downloading a
1212
[![Backers on Open Collective](https://opencollective.com/excel-parser-processor/backers/badge.svg)](#backers)
1313
[![Sponsors on Open Collective](https://opencollective.com/excel-parser-processor/sponsors/badge.svg)](#sponsors)
1414
[![Open Source Helpers](https://www.codetriage.com/btargac/excel-parser-processor/badges/users.svg)](https://www.codetriage.com/btargac/excel-parser-processor)
15+
[![CodeFactor][CodeFactor-image]][CodeFactor-url]
1516

1617
#### How to use
1718

@@ -116,3 +117,6 @@ MIT © [Burak Targaç](https://github.com/btargac)
116117

117118
[codecov-image]: https://codecov.io/gh/btargac/excel-parser-processor/branch/master/graph/badge.svg
118119
[codecov-url]: https://codecov.io/gh/btargac/excel-parser-processor
120+
121+
[CodeFactor-image]: https://www.codefactor.io/repository/github/btargac/excel-parser-processor/badge
122+
[CodeFactor-url]: https://www.codefactor.io/repository/github/btargac/excel-parser-processor

package-lock.json

Lines changed: 10292 additions & 6314 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "excel-parser-processor",
33
"productName": "Excel Parser Processor",
4-
"version": "1.2.0",
4+
"version": "1.3.0",
55
"description": "Does the tedious processing over all items of a given excel file by converting the rows to an array and process all items of that array recursively",
66
"main": "./dist/index.bundle.js",
77
"scripts": {
@@ -10,7 +10,7 @@
1010
"build": "npm-run-all build-main build-renderer",
1111
"generate-icons": "electron-icon-maker --input=./build-assets/icon.png --output=./build/",
1212
"start-renderer-dev": "cross-env NODE_ENV=development PROCESS_TYPE=renderer webpack --config webpack.dev.js",
13-
"start": "electron ./dist/index.bundle.js",
13+
"start": "electron --inspect ./dist/index.bundle.js",
1414
"test": "jest",
1515
"test-watch": "jest --coverage --watch",
1616
"pack": "electron-builder build --dir",
@@ -52,42 +52,42 @@
5252
},
5353
"homepage": "https://github.com/btargac/excel-parser-processor#readme",
5454
"devDependencies": {
55-
"@babel/core": "^7.7.7",
56-
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.7.4",
57-
"@babel/plugin-proposal-optional-chaining": "^7.7.5",
58-
"@babel/plugin-transform-runtime": "^7.7.6",
59-
"@babel/preset-env": "^7.7.7",
60-
"babel-jest": "^24.9.0",
61-
"babel-loader": "^8.0.6",
55+
"@babel/core": "^7.13.13",
56+
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.13.8",
57+
"@babel/plugin-transform-runtime": "^7.13.10",
58+
"@babel/preset-env": "^7.13.12",
59+
"babel-jest": "^26.6.3",
60+
"babel-loader": "^8.2.2",
6261
"clean-webpack-plugin": "^3.0.0",
63-
"copy-webpack-plugin": "^5.1.1",
64-
"cross-env": "^6.0.3",
65-
"css-loader": "^3.4.0",
66-
"electron": "^7.2.4",
67-
"electron-builder": "^21.2.0",
68-
"electron-icon-maker": "^0.0.4",
62+
"copy-webpack-plugin": "^8.1.0",
63+
"cross-env": "^7.0.3",
64+
"css-loader": "^5.2.0",
65+
"electron": "^12.0.0",
66+
"electron-builder": "^22.10.5",
67+
"electron-icon-maker": "^0.0.5",
6968
"html-webpack-exclude-assets-plugin": "^0.0.7",
70-
"html-webpack-plugin": "^3.2.0",
71-
"jest": "^24.9.0",
72-
"mini-css-extract-plugin": "^0.9.0",
73-
"node-sass": "^4.13.1",
69+
"html-webpack-plugin": "^5.3.1",
70+
"jest": "^26.6.3",
71+
"mini-css-extract-plugin": "^1.4.0",
72+
"node-sass": "^5.0.0",
7473
"npm-run-all": "^4.1.5",
75-
"sass-loader": "^8.0.0",
76-
"script-ext-html-webpack-plugin": "^2.1.4",
77-
"style-loader": "^1.1.2",
74+
"sass-loader": "^11.0.1",
75+
"script-ext-html-webpack-plugin": "^2.1.5",
76+
"style-loader": "^2.0.0",
7877
"uglifyjs-webpack-plugin": "^2.2.0",
79-
"webpack": "^4.41.5",
80-
"webpack-cli": "^3.3.10",
81-
"webpack-merge": "^4.2.2"
78+
"webpack": "^5.28.0",
79+
"webpack-cli": "^4.6.0",
80+
"webpack-merge": "^5.7.3"
8281
},
8382
"dependencies": {
84-
"@babel/runtime-corejs3": "^7.7.7",
83+
"@babel/runtime-corejs3": "^7.13.10",
8584
"@fortawesome/fontawesome": "^1.1.8",
8685
"@fortawesome/fontawesome-free-solid": "^5.0.13",
87-
"electron-fetch": "^1.4.0",
86+
"electron-fetch": "^1.7.3",
8887
"is-url": "^1.2.4",
89-
"jquery": "^3.5.0",
90-
"node-xlsx": "^0.15.0",
88+
"jquery": "^3.6.0",
89+
"mime-types": "^2.1.29",
90+
"node-xlsx": "^0.16.1",
9191
"normalize.css": "^8.0.1",
9292
"opencollective": "^1.0.3"
9393
},

src/utils/generateFileName.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const extensionRegex = /\.([a-zA-Z0-9]+)$/ig
2+
3+
export default (name, extension) => {
4+
const hasExtension = name.match(extensionRegex);
5+
6+
return hasExtension ? name: `${name}.${extension}`;
7+
}

src/utils/generateFileName.spec.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import generateFileName from './generateFileName';
2+
3+
test('generateFileName should be a function', () => {
4+
expect(typeof generateFileName).toBe('function');
5+
});
6+
7+
test('should generate the correct file name when file name is extension free', () => {
8+
const fileName = generateFileName('sample', 'jpg');
9+
10+
expect(fileName).toBe('sample.jpg');
11+
});
12+
13+
14+
test('should generate the correct file name when file name has an extension', () => {
15+
const fileName = generateFileName('sample.avif', 'avif');
16+
17+
expect(fileName).toBe('sample.avif');
18+
});
19+
20+
test('should generate the correct file name when file name is erroneous', () => {
21+
const fileName = generateFileName('sample.', 'gif');
22+
23+
expect(fileName).toBe('sample..gif');
24+
});

src/utils/processItems.js

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
import path from 'path';
22
import { createWriteStream, mkdir } from 'fs';
3+
import { pipeline } from 'stream';
4+
import { promisify } from 'util';
35
import fetch from 'electron-fetch';
46
import { URL } from 'url';
57
import xlsx from 'node-xlsx';
68
import isUrl from 'is-url';
9+
import mime from 'mime-types';
10+
11+
import generateFileName from './generateFileName';
12+
const streamPipeline = promisify(pipeline);
713

814
let initialItemsLength;
915
let processedItemsCount;
@@ -23,24 +29,39 @@ const processItem = async (item, outputPath) => {
2329
const url = new URL(itemUrl);
2430
const itemName = newName ? `${newName}${path.extname(url.pathname)}` : path.basename(url.pathname);
2531

26-
const response = await fetch(itemUrl);
32+
// usage of 'If-None-Match' header is just to force the server not to return an 304 since electron net does not
33+
// correctly return content-type headers when converting an 304 to 200 internally
34+
// see issues https://github.com/electron/electron/issues/27895, https://github.com/electron/electron/pull/21552
35+
// and https://github.com/electron/electron/issues/20631
36+
const response = await fetch(itemUrl, {headers: {'If-None-Match': null}});
2737

2838
if (response.ok) {
2939
if (subFolderName) {
3040
await mkdir(`${outputPath}/${subFolderName}`, { recursive: true }, () => {});
3141
}
3242

33-
const dest = createWriteStream(path.join(outputPath, subFolderName ? subFolderName : '', itemName));
34-
35-
response.body.pipe(dest);
43+
const contentType = response.headers.get('content-type');
44+
const extension = mime.extension(contentType);
45+
const fileName = generateFileName(itemName, extension);
46+
// file system flag 'wx' stands for:
47+
// Open file for writing. The file is created (if it does not exist), but fails if the path exists. (x causes to throw)
48+
const dest = createWriteStream(path.join(outputPath, subFolderName || '', fileName), {flags: 'wx'});
49+
50+
try {
51+
await streamPipeline(response.body, dest);
52+
} catch (error) {
53+
throw {
54+
statusText: error.message,
55+
itemInfo: error.path
56+
}
57+
}
3658
} else {
3759
throw {
3860
status: response.status,
3961
statusText: response.statusText,
4062
itemInfo: url.href
4163
}
4264
}
43-
4465
};
4566

4667
const processItems = async (rowItems, outputPath, win) => {
@@ -68,8 +89,7 @@ const processItems = async (rowItems, outputPath, win) => {
6889
});
6990
});
7091

71-
await Promise.all(requests)
72-
.catch(e => console.log(`Error processing for the batch ${i} - ${e}`));
92+
await Promise.allSettled(requests);
7393
}
7494

7595
const logFileStream = createWriteStream(path.join(

webpack.common.js

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const path = require('path');
22
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
3-
const CopyWebpackPlugin = require('copy-webpack-plugin');
3+
const CopyPlugin = require("copy-webpack-plugin");
44
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
55
const HtmlWebpackPlugin = require('html-webpack-plugin');
66
const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin');
@@ -31,18 +31,19 @@ const mainConfig = {
3131
},
3232
plugins: [
3333
cleanDist,
34-
new CopyWebpackPlugin([
35-
{
36-
from: './src/images/',
37-
to: 'images',
38-
toType: 'dir'
39-
},
40-
{
41-
from: './src/preload.js',
42-
to: 'preload.js',
43-
toType: 'file'
44-
}
45-
])
34+
new CopyPlugin({
35+
patterns: [
36+
{
37+
from: './src/images/',
38+
to: 'images'
39+
},
40+
{
41+
from: './src/preload.js',
42+
to: 'preload.js',
43+
toType: 'file'
44+
}
45+
],
46+
}),
4647
],
4748
module: {
4849
rules: [

webpack.dev.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const path = require('path');
2-
const merge = require('webpack-merge');
2+
const { merge } = require('webpack-merge');
33
const webpack = require('webpack');
44
const { mainConfig, rendererConfig } = require('./webpack.common.js');
55
const processType = process.env.PROCESS_TYPE;

webpack.prod.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const merge = require('webpack-merge');
1+
const { merge } = require('webpack-merge');
22
const { mainConfig, rendererConfig } = require('./webpack.common.js');
33
const processType = process.env.PROCESS_TYPE;
44

0 commit comments

Comments
 (0)