diff --git a/.github/workflows/cd.release.yml b/.github/workflows/cd.release.yml index 86f92f1..eb1d0db 100755 --- a/.github/workflows/cd.release.yml +++ b/.github/workflows/cd.release.yml @@ -22,7 +22,7 @@ jobs: if: ${{ steps.release.outputs.release_created }} - uses: actions/setup-node@v1 with: - node-version: 12 + node-version: 18 registry-url: 'https://registry.npmjs.org' if: ${{ steps.release.outputs.release_created }} # if you are using Yarn, substitute the command below with `yarn install --frozen-lockfile` diff --git a/.github/workflows/ci.coverage.yml b/.github/workflows/ci.coverage.yml index aad1f23..93194e7 100755 --- a/.github/workflows/ci.coverage.yml +++ b/.github/workflows/ci.coverage.yml @@ -11,10 +11,10 @@ jobs: - uses: actions/checkout@v1 - - name: Use Node.js 10.x + - name: Use Node.js 18.x uses: actions/setup-node@v1 with: - node-version: 10.x + node-version: 18 - name: npm install, npm test, npm run coverage run: | diff --git a/.github/workflows/ci.test.yml b/.github/workflows/ci.test.yml index 7b920cf..0113aee 100755 --- a/.github/workflows/ci.test.yml +++ b/.github/workflows/ci.test.yml @@ -14,7 +14,7 @@ jobs: fail-fast: false matrix: os: [windows-latest, ubuntu-latest, macos-latest] - node-version: [10.x, 12.x, 14.x] + node-version: [16.x, 18.x, 20.x] steps: - uses: actions/checkout@v2 diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..4fd0219 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +engine-strict=true \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index ec44183..083fed6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "oslllo-potrace": "^2.0.1", "oslllo-svg2": "^2.0.2", "oslllo-validator": "^3.1.0", + "piscina": "^4.1.0", "yargs": "^16.2.0" }, "bin": { @@ -32,8 +33,16 @@ "mocha-lcov-reporter": "^1.3.0", "nyc": "^15.1.0", "stopwatch-node": "^1.1.0" + }, + "engines": { + "node": ">=16.0.0" } }, + "node_modules/@assemblyscript/loader": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", + "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==" + }, "node_modules/@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", @@ -1694,9 +1703,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001367", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001367.tgz", - "integrity": "sha512-XDgbeOHfifWV3GEES2B8rtsrADx4Jf+juKX2SICJcaUhjYBO3bR96kvEIHa15VU6ohtOhBZuPGGYGbXMRn0NCw==", + "version": "1.0.30001534", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001534.tgz", + "integrity": "sha512-vlPVrhsCS7XaSh2VvWluIQEzVhefrUQcEsQWSS5A5V+dM07uv1qHeQzAOTGIMy9i3e9bH15+muvI/UHojVgS/Q==", "dev": true, "funding": [ { @@ -1706,6 +1715,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ] }, @@ -2356,6 +2369,11 @@ "node": ">=0.10.0" } }, + "node_modules/eventemitter-asyncresource": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", + "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==" + }, "node_modules/exif-parser": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz", @@ -2809,6 +2827,21 @@ "node": ">=8" } }, + "node_modules/hdr-histogram-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", + "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", + "dependencies": { + "@assemblyscript/loader": "^0.10.1", + "base64-js": "^1.2.0", + "pako": "^1.0.3" + } + }, + "node_modules/hdr-histogram-percentiles-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", + "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==" + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -3771,6 +3804,37 @@ "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==", "dev": true }, + "node_modules/nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "!win32" + ], + "dependencies": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" + } + }, + "node_modules/node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "optional": true + }, + "node_modules/node-gyp-build": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.1.tgz", + "integrity": "sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==", + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -4264,6 +4328,19 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/piscina": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.1.0.tgz", + "integrity": "sha512-sjbLMi3sokkie+qmtZpkfMCUJTpbxJm/wvaPzU28vmYSsTSW8xk9JcFUsbqGJdtPpIQ9tuj+iDcTtgZjwnOSig==", + "dependencies": { + "eventemitter-asyncresource": "^1.0.0", + "hdr-histogram-js": "^2.0.1", + "hdr-histogram-percentiles-obj": "^3.0.0" + }, + "optionalDependencies": { + "nice-napi": "^1.0.2" + } + }, "node_modules/pixelmatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz", @@ -5357,6 +5434,11 @@ } }, "dependencies": { + "@assemblyscript/loader": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", + "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==" + }, "@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", @@ -6554,9 +6636,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001367", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001367.tgz", - "integrity": "sha512-XDgbeOHfifWV3GEES2B8rtsrADx4Jf+juKX2SICJcaUhjYBO3bR96kvEIHa15VU6ohtOhBZuPGGYGbXMRn0NCw==", + "version": "1.0.30001534", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001534.tgz", + "integrity": "sha512-vlPVrhsCS7XaSh2VvWluIQEzVhefrUQcEsQWSS5A5V+dM07uv1qHeQzAOTGIMy9i3e9bH15+muvI/UHojVgS/Q==", "dev": true }, "caseless": { @@ -7054,6 +7136,11 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, + "eventemitter-asyncresource": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", + "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==" + }, "exif-parser": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz", @@ -7387,6 +7474,21 @@ } } }, + "hdr-histogram-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", + "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", + "requires": { + "@assemblyscript/loader": "^0.10.1", + "base64-js": "^1.2.0", + "pako": "^1.0.3" + } + }, + "hdr-histogram-percentiles-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", + "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==" + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -8127,6 +8229,28 @@ "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==", "dev": true }, + "nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "optional": true, + "requires": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" + } + }, + "node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "optional": true + }, + "node-gyp-build": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.1.tgz", + "integrity": "sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==", + "optional": true + }, "node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -8519,6 +8643,17 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" }, + "piscina": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.1.0.tgz", + "integrity": "sha512-sjbLMi3sokkie+qmtZpkfMCUJTpbxJm/wvaPzU28vmYSsTSW8xk9JcFUsbqGJdtPpIQ9tuj+iDcTtgZjwnOSig==", + "requires": { + "eventemitter-asyncresource": "^1.0.0", + "hdr-histogram-js": "^2.0.1", + "hdr-histogram-percentiles-obj": "^3.0.0", + "nice-napi": "^1.0.2" + } + }, "pixelmatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz", diff --git a/package.json b/package.json index 52e20e6..6d01bbd 100644 --- a/package.json +++ b/package.json @@ -10,11 +10,11 @@ ], "scripts": { "debug": "node scripts/debug.js", - "lint": "node_modules/.bin/eslint -- src test ./", - "lint:fix": "node_modules/.bin/eslint --fix src test ./", + "lint": "eslint -- src test ./", + "lint:fix": "eslint --fix src test ./", "test:only": "nyc mocha test/main.test.js && mocha test/output.test.js", "test": "nyc mocha test/main.test.js && mocha test/output.test.js && npm run lint", - "coverage": "node_modules/.bin/nyc report --reporter=lcovonly" + "coverage": "nyc report --reporter=lcovonly" }, "repository": { "type": "git", @@ -48,6 +48,7 @@ "oslllo-potrace": "^2.0.1", "oslllo-svg2": "^2.0.2", "oslllo-validator": "^3.1.0", + "piscina": "^4.1.0", "yargs": "^16.2.0" }, "devDependencies": { @@ -62,5 +63,8 @@ "mocha-lcov-reporter": "^1.3.0", "nyc": "^15.1.0", "stopwatch-node": "^1.1.0" + }, + "engines": { + "node": ">=16.0.0" } } diff --git a/src/processor.js b/src/processor.js index b72a4a2..211b4f5 100755 --- a/src/processor.js +++ b/src/processor.js @@ -1,10 +1,13 @@ "use strict"; -const fs = require("fs"); const path = require("path"); -const Svg = require("./svg"); const is = require("oslllo-validator"); const Progress = require("./progress"); +const Piscina = require("piscina"); + +const workerPool = new Piscina({ + filename: path.resolve(__dirname, "tracer.js") +}); const Processor = function (fixer) { this.fixer = fixer; @@ -34,14 +37,23 @@ Processor.prototype = { try { this.setup(); var svgs = this.source; + + const resolution = this.fixer.options.get("traceResolution"); + svgs = svgs.map((source) => { var destination = path.join(this.destination, path.basename(source)); - return { source, destination }; + return { source, destination, resolution }; }); - for (var i = 0; i < svgs.length; i++) { - await this.instance(svgs[i]); - } + + const workerPromises = svgs.map(async (svg) => { + await workerPool.run(svg); + // eslint-disable-next-line no-empty-function + this.tick(() => {}); + }); + + await Promise.all(workerPromises); + this.teardown(); resolve(this.fixer); } catch (err) { @@ -68,19 +80,6 @@ Processor.prototype = { this.progress.stop(); } }, - instance: function ({ source, destination }) { - return new Promise(async (resolve, reject) => { - try { - var resolution = this.fixer.options.get("traceResolution"); - var svg = new Svg(source, resolution); - var fixed = await svg.process(); - fs.writeFileSync(destination, fixed); - this.tick(() => resolve()); - } catch (err) { - reject(err); - } - }); - }, }; module.exports = Processor; diff --git a/src/tracer.js b/src/tracer.js new file mode 100644 index 0000000..30b7dd9 --- /dev/null +++ b/src/tracer.js @@ -0,0 +1,10 @@ +"use strict"; + +const fs = require("fs/promises"); +const Svg = require("./svg"); + +module.exports = async ({ source, destination, resolution }) => { + const svg = new Svg(source, resolution); + const fixed = await svg.process(); + await fs.writeFile(destination, fixed); +}; diff --git a/test/src/test.cli.js b/test/src/test.cli.js index 838f9be..d257e35 100755 --- a/test/src/test.cli.js +++ b/test/src/test.cli.js @@ -5,7 +5,7 @@ const { emptyDir, isEmptyDir } = require("."); const { exec } = require("child_process"); const { assert, path2 } = require("./helper"); -const timeout = 20000; +const timeout = 30000; var destination = "temp"; if (!fs.existsSync(destination)) {