From 3ff4528e509eb1232a0b6a1a9ef8596383e776f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Mond=C3=A9jar?= Date: Wed, 11 May 2022 11:14:47 -0500 Subject: [PATCH] Rewrite the whole project with Typescript (#93) * Rewrite whole project with Typescript * Update linting * Minor change * Update CI * Fix error message * Minor change * Stricter typing in benchmarks script * Minor changes --- .github/workflows/ci.yml | 2 - .husky/pre-commit | 2 +- dist/{cjs.js => wrapper.js} | 0 examples/common.js | 2 +- examples/esm.mjs | 3 + examples/esm/index.js | 3 - examples/esm/package.json | 3 - jest.config.js => jest.config.ts | 5 +- package-lock.json | 354 ++++++++++++++++++++++----- package.json | 34 +-- scripts/benchmark.js | 90 ------- scripts/benchmark.ts | 91 +++++++ scripts/build-cjs-wrapper.ts | 6 + scripts/build-cjs.js | 4 - scripts/si-benchmark.ts | 12 + scripts/simple-icons-benchmark.js | 22 -- src/cli.js | 5 +- tests/{bbox.test.js => bbox.test.ts} | 27 +- tests/cli.test.js | 61 ----- tests/cli.test.ts | 39 +++ tests/examples.test.ts | 26 ++ tests/utils/syscall.ts | 38 +++ tsconfig.json | 2 +- 23 files changed, 541 insertions(+), 290 deletions(-) rename dist/{cjs.js => wrapper.js} (100%) create mode 100644 examples/esm.mjs delete mode 100644 examples/esm/index.js delete mode 100644 examples/esm/package.json rename jest.config.js => jest.config.ts (50%) delete mode 100644 scripts/benchmark.js create mode 100644 scripts/benchmark.ts create mode 100644 scripts/build-cjs-wrapper.ts delete mode 100644 scripts/build-cjs.js create mode 100644 scripts/si-benchmark.ts delete mode 100644 scripts/simple-icons-benchmark.js rename tests/{bbox.test.js => bbox.test.ts} (97%) delete mode 100644 tests/cli.test.js create mode 100644 tests/cli.test.ts create mode 100644 tests/examples.test.ts create mode 100644 tests/utils/syscall.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a5e8df8..f8265ea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,8 +49,6 @@ jobs: run: npm ci - name: Lint run: npm run lint - - name: Check format - run: npm run format:check npm: if: startsWith(github.ref, 'refs/tags/') diff --git a/.husky/pre-commit b/.husky/pre-commit index 0f97fbe..4b0dd56 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -3,5 +3,5 @@ set -e -run-s build examples test +run-s build test git add . diff --git a/dist/cjs.js b/dist/wrapper.js similarity index 100% rename from dist/cjs.js rename to dist/wrapper.js diff --git a/examples/common.js b/examples/common.js index 9ad2dd3..2a4defd 100644 --- a/examples/common.js +++ b/examples/common.js @@ -1,3 +1,3 @@ -const svgPathBbox = require("../dist/cjs"); +const svgPathBbox = require("../dist/wrapper.js"); console.log(svgPathBbox("M0 0H3V6Z")); diff --git a/examples/esm.mjs b/examples/esm.mjs new file mode 100644 index 0000000..babcd5b --- /dev/null +++ b/examples/esm.mjs @@ -0,0 +1,3 @@ +import svgPathBbox from "../dist/wrapper.js"; + +console.log(svgPathBbox("M0 0H3V6Z")); diff --git a/examples/esm/index.js b/examples/esm/index.js deleted file mode 100644 index 66eb9b0..0000000 --- a/examples/esm/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import svgPathBbox from "../../dist/cjs.js"; - -console.log(svgPathBbox("M0 0H3V6Z")); diff --git a/examples/esm/package.json b/examples/esm/package.json deleted file mode 100644 index 3dbc1ca..0000000 --- a/examples/esm/package.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "type": "module" -} diff --git a/jest.config.js b/jest.config.ts similarity index 50% rename from jest.config.js rename to jest.config.ts index ea5817b..4328de4 100644 --- a/jest.config.js +++ b/jest.config.ts @@ -1,5 +1,6 @@ -module.exports = { - testEnvironment: "node", +export default { + preset: "ts-jest", collectCoverage: true, coverageDirectory: "/tests/coverage", + collectCoverageFrom: ["src/*.ts"], }; diff --git a/package-lock.json b/package-lock.json index dcd5e8a..02c72ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,20 +1,22 @@ { "name": "svg-path-bbox", - "version": "1.1.0", + "version": "1.2.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "svg-path-bbox", - "version": "1.1.0", + "version": "1.2.0", "license": "BSD-3-Clause", "dependencies": { "svgpath": "^2.2.0" }, "bin": { - "svg-path-bbox": "src/cli.js" + "svg-path-bbox": "src/cli.cjs" }, "devDependencies": { + "@types/jest": "27.5.0", + "@types/svg-path-bounding-box": "1.0.0", "@typescript-eslint/eslint-plugin": "5.22.0", "@typescript-eslint/parser": "5.22.0", "coveralls": "3.1.1", @@ -27,9 +29,9 @@ "npm-run-all": "4.1.5", "prettier": "2.6.2", "rimraf": "3.0.2", - "shelljs": "0.8.5", "simple-icons": "6.20.0", "svg-path-bounding-box": "1.0.4", + "ts-jest": "28.0.2", "ts-node": "10.7.0", "typescript": "4.6.4" }, @@ -1145,6 +1147,96 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/jest": { + "version": "27.5.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.0.tgz", + "integrity": "sha512-9RBFx7r4k+msyj/arpfaa0WOOEcaAZNmN+j80KFbFCoSqCJGHTz7YMAMGQW9Xmqm5w6l5c25vbSjMwlikJi5+g==", + "dev": true, + "dependencies": { + "jest-matcher-utils": "^27.0.0", + "pretty-format": "^27.0.0" + } + }, + "node_modules/@types/jest/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@types/jest/node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@types/jest/node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@types/jest/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, "node_modules/@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -1169,6 +1261,12 @@ "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, + "node_modules/@types/svg-path-bounding-box": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/svg-path-bounding-box/-/svg-path-bounding-box-1.0.0.tgz", + "integrity": "sha512-pDbxXXNzSC6kPMUVzUA173XlHJFW16R7Cr4rvNS6iG7ZFMHbZVf+0+pKA9FI1K48YwyY8mc/CN0p4rub/+Ro5Q==", + "dev": true + }, "node_modules/@types/yargs": { "version": "17.0.10", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", @@ -1698,6 +1796,18 @@ "url": "https://opencollective.com/browserslist" } }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/bser": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", @@ -3151,15 +3261,6 @@ "node": ">= 0.4" } }, - "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -4282,6 +4383,12 @@ "node": ">=8" } }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -5018,18 +5125,6 @@ "node": ">=4" } }, - "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true, - "dependencies": { - "resolve": "^1.1.6" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/regexp.prototype.flags": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", @@ -5268,23 +5363,6 @@ "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==", "dev": true }, - "node_modules/shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", - "dev": true, - "dependencies": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - }, - "bin": { - "shjs": "bin/shjs" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -5695,6 +5773,49 @@ "node": ">=0.8" } }, + "node_modules/ts-jest": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.2.tgz", + "integrity": "sha512-IOZMb3D0gx6IHO9ywPgiQxJ3Zl4ECylEFwoVpENB55aTn5sdO0Ptyx/7noNBxAaUff708RqQL4XBNxxOVjY0vQ==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^28.0.0", + "json5": "2.x", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "^20.x" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@types/jest": "^27.0.0", + "babel-jest": "^28.0.0", + "jest": "^28.0.0", + "typescript": ">=4.3" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@types/jest": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, "node_modules/ts-node": { "version": "10.7.0", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz", @@ -6058,6 +6179,15 @@ "node": ">=12" } }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/yargs/node_modules/yargs-parser": { "version": "21.0.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", @@ -6960,6 +7090,77 @@ "@types/istanbul-lib-report": "*" } }, + "@types/jest": { + "version": "27.5.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.0.tgz", + "integrity": "sha512-9RBFx7r4k+msyj/arpfaa0WOOEcaAZNmN+j80KFbFCoSqCJGHTz7YMAMGQW9Xmqm5w6l5c25vbSjMwlikJi5+g==", + "dev": true, + "requires": { + "jest-matcher-utils": "^27.0.0", + "pretty-format": "^27.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "dev": true + }, + "jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true + }, + "jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + } + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + } + } + }, "@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -6984,6 +7185,12 @@ "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, + "@types/svg-path-bounding-box": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/svg-path-bounding-box/-/svg-path-bounding-box-1.0.0.tgz", + "integrity": "sha512-pDbxXXNzSC6kPMUVzUA173XlHJFW16R7Cr4rvNS6iG7ZFMHbZVf+0+pKA9FI1K48YwyY8mc/CN0p4rub/+Ro5Q==", + "dev": true + }, "@types/yargs": { "version": "17.0.10", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", @@ -7346,6 +7553,15 @@ "picocolors": "^1.0.0" } }, + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "requires": { + "fast-json-stable-stringify": "2.x" + } + }, "bser": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", @@ -8432,12 +8648,6 @@ "side-channel": "^1.0.4" } }, - "interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true - }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -9283,6 +9493,12 @@ "p-locate": "^4.1.0" } }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -9827,15 +10043,6 @@ } } }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true, - "requires": { - "resolve": "^1.1.6" - } - }, "regexp.prototype.flags": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", @@ -9992,17 +10199,6 @@ "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==", "dev": true }, - "shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", - "dev": true, - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - } - }, "side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -10321,6 +10517,22 @@ "punycode": "^2.1.1" } }, + "ts-jest": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.2.tgz", + "integrity": "sha512-IOZMb3D0gx6IHO9ywPgiQxJ3Zl4ECylEFwoVpENB55aTn5sdO0Ptyx/7noNBxAaUff708RqQL4XBNxxOVjY0vQ==", + "dev": true, + "requires": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^28.0.0", + "json5": "2.x", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "^20.x" + } + }, "ts-node": { "version": "10.7.0", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz", @@ -10595,6 +10807,12 @@ } } }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true + }, "yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/package.json b/package.json index 08bdc28..6417daa 100644 --- a/package.json +++ b/package.json @@ -7,28 +7,30 @@ "path", "bbox" ], - "main": "dist/cjs.js", - "browser": "dist/cjs.js", - "module": "dist/cjs.js", + "main": "dist/wrapper.js", + "browser": "dist/wrapper.js", + "module": "dist/index.js", "types": "dist/index.d.ts", + "type": "commonjs", "bin": { - "svg-path-bbox": "src/cli.js" + "svg-path-bbox": "src/cli.cjs" }, "scripts": { "coveralls": "cat ./tests/coverage/lcov.info | coveralls", - "prebuild": "run-s lint:fix format", - "build": "run-s build:ts build:cjs", + "prebuild": "run-s lint:fix dist:prepare", + "build": "run-p build:ts build:cjs:wrapper", "build:ts": "tsc", - "build:cjs": "node scripts/build-cjs.js", - "examples": "run-s example:cjs example:esm example:ts", + "build:cjs:wrapper": "ts-node scripts/build-cjs-wrapper.ts", + "examples": "run-s example:*", "example:cjs": "node examples/common.js", - "example:esm": "node examples/esm/index.js", - "example:ts": "cd examples && ts-node typescript.ts", - "lint": "eslint '{src,examples}/*.ts'", + "example:esm": "node examples/esm.mjs", + "example:ts": "ts-node examples/typescript.ts", + "lint": "eslint src/index.ts tests scripts examples/typescript.ts", "lint:fix": "npm run lint -- --fix", - "format": "prettier -w .", - "format:check": "prettier .", - "test": "jest tests", + "dist:prepare": "run-s dist:clean dist:create", + "dist:create": "mkdir dist", + "dist:clean": "rimraf dist", + "test": "jest", "prepare": "is-ci || husky install" }, "author": { @@ -41,6 +43,8 @@ "svgpath": "^2.2.0" }, "devDependencies": { + "@types/jest": "27.5.0", + "@types/svg-path-bounding-box": "1.0.0", "@typescript-eslint/eslint-plugin": "5.22.0", "@typescript-eslint/parser": "5.22.0", "coveralls": "3.1.1", @@ -52,8 +56,10 @@ "jest": "28.0.3", "npm-run-all": "4.1.5", "prettier": "2.6.2", + "rimraf": "3.0.2", "simple-icons": "6.20.0", "svg-path-bounding-box": "1.0.4", + "ts-jest": "28.0.2", "ts-node": "10.7.0", "typescript": "4.6.4" }, diff --git a/scripts/benchmark.js b/scripts/benchmark.js deleted file mode 100644 index b132013..0000000 --- a/scripts/benchmark.js +++ /dev/null @@ -1,90 +0,0 @@ -"use strict"; - -const svgPathBbox = require("../dist"); -const svgPathBoundingBox = require("svg-path-bounding-box"); - -const LIBRARIES = { - "svg-path-bbox": { - func: svgPathBbox, - }, - "svg-path-bounding-box": { - func: svgPathBoundingBox, - resultParser(result) { - return [result.minX, result.minY, result.maxX, result.maxY]; - }, - }, -}; - -const PATHS = [ - "M0 0L10 10 20 0Z", - "M100,250 c0,-150 300,-150 300,0", - "M 10 20 C 50 -15 90 45 10 80 L 60 80", -]; - -const EPOCHS = [10000, 100000]; - -const runLibrariesBenchmarkComparison = function (paths, epochs) { - const _paths = []; - if (typeof paths === "object") { - for (const key in paths) { - _paths.push([paths[key], key]); - } - } else { - for (let _p = 0; _p < paths.length; _p++) { - _paths.push([paths[_p], null]); - } - } - - for (let p = 0; p < _paths.length; p++) { - for (let e = 0; e < epochs.length; e++) { - const path = _paths[p]; - let pathType = path[0].replace(/[0-9\-.\s,]/g, ""); - pathType = - pathType.length > 25 ? `${pathType.substring(0, 25)}...` : pathType; - const pathSub = - path[0].length > 25 ? `${path[0].substring(0, 25)}...` : path; - - if (_paths[p][1]) { - process.stdout.write(`${_paths[p][1]} - `); - } - - console.log(`${pathSub} (type ${pathType}) [${epochs[e]} epochs]`); - for (const library in LIBRARIES) { - console.time(library); - const func = LIBRARIES[library]["func"]; - let _errorRaised = false, - result; - for (let r = 0; r < epochs[e]; r++) { - try { - result = func(path[0]); - } catch (Error) { - if (!_errorRaised) { - console.error(`Error computing bbox with library ${library}:`); - console.error(Error); - } - _errorRaised = true; - } - } - if (LIBRARIES[library]["resultParser"]) { - result = LIBRARIES[library]["resultParser"](result); - } - process.stdout.write(" "); - console.timeEnd(library); - if (result) { - console.log(" + result:", result); - } - } - console.log(); - } - } -}; - -const main = function () { - runLibrariesBenchmarkComparison(PATHS, EPOCHS); -}; - -if (require.main === module) { - main(); -} else { - module.exports = runLibrariesBenchmarkComparison; -} diff --git a/scripts/benchmark.ts b/scripts/benchmark.ts new file mode 100644 index 0000000..7a34fe9 --- /dev/null +++ b/scripts/benchmark.ts @@ -0,0 +1,91 @@ +import svgPathBbox from "../src"; +import * as svgPathBoundingBox from "svg-path-bounding-box"; +import type { BBox } from "../src"; +import type { BoundingBoxView } from "svg-path-bounding-box"; + +type Library = "svg-path-bbox" | "svg-path-bounding-box"; +type LibraryAdapter = { + func: typeof svgPathBbox | typeof svgPathBoundingBox; + resultParser?: (result: BoundingBoxView) => BBox; +}; + +/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ +const LIBRARIES: { + [key in Library]: LibraryAdapter; +} = { + "svg-path-bbox": { + func: svgPathBbox, + }, + "svg-path-bounding-box": { + func: svgPathBoundingBox, + resultParser(result) { + return [result.minX, result.minY, result.maxX, result.maxY]; + }, + }, +}; + +const PATHS = [ + "M0 0L10 10 20 0Z", + "M100,250 c0,-150 300,-150 300,0", + "M 10 20 C 50 -15 90 45 10 80 L 60 80", +]; + +const EPOCHS = [10000, 100000]; + +const runLibrariesBenchmark = ( + paths: [string | null, string][], + epochs: number[] +) => { + for (const [key, path] of paths) { + for (const e of epochs) { + let pathType = path.replace(/[0-9\-.\s,]/g, ""); + pathType = + pathType.length > 25 ? `${pathType.substring(0, 25)}...` : pathType; + const pathSummary = + path.length > 25 ? `${path.substring(0, 25)}...` : path; + + if (key) { + process.stdout.write(`${key} - `); + } + + console.log(`${pathSummary} (type ${pathType}) [${e} epochs]`); + for (const library in LIBRARIES) { + console.time(library); + const func = LIBRARIES[library]["func"]; + let _errorRaised = false, + result; + for (let r = 0; r < e; r++) { + try { + result = func(path); + } catch (Error) { + if (!_errorRaised) { + console.error(`Error computing bbox with library ${library}:`); + console.error(Error); + } + _errorRaised = true; + } + } + process.stdout.write(" "); + console.timeEnd(library); + + const resultParser = LIBRARIES[library].resultParser; + if (resultParser !== undefined) { + result = resultParser(result); + } + if (result) { + console.log(" + result:", result); + } + } + console.log(); + } + } +}; + +export default runLibrariesBenchmark; + +if (require.main === module) { + runLibrariesBenchmark( + PATHS.map((path) => [null, path]), + EPOCHS + ); +} diff --git a/scripts/build-cjs-wrapper.ts b/scripts/build-cjs-wrapper.ts new file mode 100644 index 0000000..8f94f7d --- /dev/null +++ b/scripts/build-cjs-wrapper.ts @@ -0,0 +1,6 @@ +import * as fs from "node:fs"; + +fs.writeFileSync( + "dist/wrapper.js", + 'module.exports = require("./index.js").default;' +); diff --git a/scripts/build-cjs.js b/scripts/build-cjs.js deleted file mode 100644 index 2138807..0000000 --- a/scripts/build-cjs.js +++ /dev/null @@ -1,4 +0,0 @@ -require("fs").writeFileSync( - "dist/cjs.js", - 'module.exports = require("./index.js").default;' -); diff --git a/scripts/si-benchmark.ts b/scripts/si-benchmark.ts new file mode 100644 index 0000000..874f8ac --- /dev/null +++ b/scripts/si-benchmark.ts @@ -0,0 +1,12 @@ +import * as icons from "simple-icons/icons"; + +import runLibrariesBenchmark from "./benchmark"; + +const EPOCHS = [1000]; + +if (require.main === module) { + runLibrariesBenchmark( + Object.values(icons).map((icon) => [icon.title, icon.path]), + EPOCHS + ); +} diff --git a/scripts/simple-icons-benchmark.js b/scripts/simple-icons-benchmark.js deleted file mode 100644 index 30a4a66..0000000 --- a/scripts/simple-icons-benchmark.js +++ /dev/null @@ -1,22 +0,0 @@ -"use strict"; - -const simpleIcons = require("simple-icons"); - -const runLibrariesBenchmarkComparison = require("./benchmark.js"); - -const EPOCHS = [1000]; - -const main = function () { - const paths = {}; - - for (const iconName in simpleIcons) { - const path = simpleIcons[iconName].path; - paths[iconName] = path; - } - - runLibrariesBenchmarkComparison(paths, EPOCHS); -}; - -if (require.main === module) { - main(); -} diff --git a/src/cli.js b/src/cli.js index 490f46a..13bb64a 100755 --- a/src/cli.js +++ b/src/cli.js @@ -22,7 +22,8 @@ if (require.main === module) { let sliceN = 1; if ( process.argv.indexOf(module.filename) > -1 || - require("path").basename(process.argv[1]) === "svg-path-bbox" + require("path").basename(process.argv[1]) === "svg-path-bbox" || + process.argv.indexOf(module.filename.slice(0, -3)) > -1 // rstrip '.js' ) { sliceN = 2; } @@ -41,7 +42,7 @@ if (require.main === module) { process.exit(1); } - const svgPathBbox = require("../dist/cjs"); + const svgPathBbox = require("../dist/wrapper"); for (let a = 0; a < args.length; a++) { console.log(svgPathBbox(args[a]).join(" ")); } diff --git a/tests/bbox.test.js b/tests/bbox.test.ts similarity index 97% rename from tests/bbox.test.js rename to tests/bbox.test.ts index c1dda25..71adb19 100644 --- a/tests/bbox.test.js +++ b/tests/bbox.test.ts @@ -1,8 +1,9 @@ -"use strict"; +import svgPathBbox from "../src"; +import type { BBox } from "../src"; -const svgPathBbox = require("../dist/cjs"); +type CasesTuple = [string, BBox][]; -const svgPathBboxLinealCases = [ +const svgPathBboxLinealCases: CasesTuple = [ // Mz ["M5 3z", [5, 3, 5, 3]], // Mz negative @@ -46,15 +47,12 @@ const svgPathBboxLinealCases = [ ]; describe("svgPathBbox(d) [Lineal cases]", () => { - test.each(svgPathBboxLinealCases)( - "svgPathBbox(%p, %p, %p) ⇢ %p", - (d, bbox) => { - expect(svgPathBbox(d)).toEqual(bbox); - } - ); + test.each(svgPathBboxLinealCases)("svgPathBbox(%p) ⇢ %p", (d, bbox) => { + expect(svgPathBbox(d)).toEqual(bbox); + }); }); -const svgPathBboxPathologicalCases = [ +const svgPathBboxPathologicalCases: CasesTuple = [ // Pathological tests (https://github.com/simple-icons/simple-icons/issues/3960) // These paths proves the bug existent in `svg-path-bounding-box` // that exists in `svg-path-bbox` before v0.1.1 @@ -162,10 +160,7 @@ const svgPathBboxPathologicalCases = [ ]; describe("svgPathBbox(d) [Pathological cases]", () => { - test.each(svgPathBboxPathologicalCases)( - "svgPathBbox(%p, %p, %p) ⇢ %p", - (d, bbox) => { - expect(svgPathBbox(d)).toEqual(bbox); - } - ); + test.each(svgPathBboxPathologicalCases)("svgPathBbox(%p) ⇢ %p", (d, bbox) => { + expect(svgPathBbox(d)).toEqual(bbox); + }); }); diff --git a/tests/cli.test.js b/tests/cli.test.js deleted file mode 100644 index d662750..0000000 --- a/tests/cli.test.js +++ /dev/null @@ -1,61 +0,0 @@ -"use strict"; - -const path = require("path"); -const { exec } = require("child_process"); -const packageJson = require("../package.json"); - -const cli = (args) => - new Promise((resolve) => { - const child = exec( - `node ${path.resolve(__dirname, "..", "src", "cli.js")}` + - ` ${args.join(" ")}` - ); - - const stdoutChunks = [], - stderrChunks = []; - let stdout, stderr; - child.on("exit", (code) => { - resolve({ code, stdout, stderr }); - }); - - child.stdout.on("data", (data) => { - stdoutChunks.push(data); - }); - child.stdout.on("end", () => { - stdout = stdoutChunks.join(""); - }); - - child.stderr.on("data", (data) => { - stderrChunks.push(data); - }); - child.stderr.on("end", () => { - stderr = stderrChunks.join(""); - }); - }); - -const cliParameterCases = [ - [['"M5 10c3 0 3 3 0 3z"'], 0, "5 10 7.25 13\n", ""], - [['"M5 10c3 0 3 3 0 3z"', '"M2 8m5 5z"'], 0, "5 10 7.25 13\n2 8 7 13\n", ""], - [ - [], - 1, - "", - "You must pass SVG paths enclosed between quotes as parameters.\n", - ], - [["--version"], 1, `^${packageJson.version}\n$`, ""], - [["-v"], 1, `^${packageJson.version}\n$`, ""], - [["--help"], 1, "", `^${packageJson.description}`], - [["-h"], 1, "", `^${packageJson.description}`], -]; - -describe("svg-path-bbox", () => { - test.each(cliParameterCases)( - "svg-path-bbox %p [CODE: %p | STDOUT: %p | STDERR: %p]", - async (parameters, code, stdout, stderr) => { - const proc = await cli(parameters); - expect(proc.code).toBe(code); - expect(new RegExp(stdout).test(proc.stdout)).toEqual(true); - expect(new RegExp(stderr).test(proc.stderr)).toEqual(true); - } - ); -}); diff --git a/tests/cli.test.ts b/tests/cli.test.ts new file mode 100644 index 0000000..8608926 --- /dev/null +++ b/tests/cli.test.ts @@ -0,0 +1,39 @@ +import * as fs from "node:fs"; +import * as path from "node:path"; + +import syscall from "./utils/syscall"; +import type { SysCallOutput, SysCallArgs } from "./utils/syscall"; + +const packageJson = JSON.parse(fs.readFileSync("package.json", "utf8")); + +const cliPath = path.resolve("src", "cli"); + +type CliCases = [SysCallArgs, 0 | 1, string, string][]; + +const cliParameterCases: CliCases = [ + [['"M5 10c3 0 3 3 0 3z"'], 0, "5 10 7.25 13\n", ""], + [['"M5 10c3 0 3 3 0 3z"', '"M2 8m5 5z"'], 0, "5 10 7.25 13\n2 8 7 13\n", ""], + [ + [], + 1, + "", + "You must pass SVG paths enclosed between quotes as parameters.\n", + ], + [["--version"], 1, `^${packageJson.version}\n$`, ""], + [["-v"], 1, `^${packageJson.version}\n$`, ""], + [["--help"], 1, "", `^${packageJson.description}`], + [["-h"], 1, "", `^${packageJson.description}`], +]; + +describe("svg-path-bbox", () => { + test.each(cliParameterCases)( + "svg-path-bbox %p [CODE: %p | STDOUT: %p | STDERR: %p]", + async (args, code, stdout, stderr) => { + args.unshift(cliPath); + const proc = (await syscall(args)) as SysCallOutput; + expect(proc.code).toBe(code); + expect(new RegExp(stdout).test(proc.stdout)).toEqual(true); + expect(new RegExp(stderr).test(proc.stderr)).toEqual(true); + } + ); +}); diff --git a/tests/examples.test.ts b/tests/examples.test.ts new file mode 100644 index 0000000..70c2c2e --- /dev/null +++ b/tests/examples.test.ts @@ -0,0 +1,26 @@ +import * as fs from "node:fs"; +import * as path from "node:path"; + +import syscall from "./utils/syscall"; +import type { SysCallOutput, SysCallProgram } from "./utils/syscall"; + +const examplesDirname = "examples"; +const expectedOutput = "[ 0, 0, 3, 6 ]\n"; + +type ExamplesCases = [string, SysCallProgram][]; + +const examplesCases: ExamplesCases = fs + .readdirSync(examplesDirname) + .map((fname) => [fname, fname.endsWith(".ts") ? "ts-node" : "node"]); + +describe("svg-path-bbox/examples", () => { + test.each(examplesCases)("svg-path-bbox %p [%p]", async (fname, program) => { + const proc = (await syscall( + [path.resolve(examplesDirname, fname)], + program + )) as SysCallOutput; + expect(proc.code).toBe(0); + expect(proc.stdout).toEqual(expectedOutput); + expect(proc.stderr).toEqual(""); + }); +}); diff --git a/tests/utils/syscall.ts b/tests/utils/syscall.ts new file mode 100644 index 0000000..70802a0 --- /dev/null +++ b/tests/utils/syscall.ts @@ -0,0 +1,38 @@ +import { exec } from "node:child_process"; + +export type SysCallArgs = string[]; +export type SysCallOutput = { code: number; stdout: string; stderr: string }; +export type SysCallProgram = "node" | "ts-node"; + +export default (args: SysCallArgs, program: SysCallProgram = "node") => + new Promise((resolve, reject) => { + const child = exec(`${program} ${args.join(" ")}`); + + const stdoutChunks: string[] = []; + const stderrChunks: string[] = []; + let stdout: string; + let stderr: string; + child.on("exit", (code: number) => { + resolve({ code, stdout, stderr }); + }); + + if (child.stdout === null) { + return reject("'stdout' object of ChildProcess is null"); + } + child.stdout.on("data", (data: string) => { + stdoutChunks.push(data); + }); + child.stdout.on("end", () => { + stdout = stdoutChunks.join(""); + }); + + if (child.stderr === null) { + return reject("'stderr' object of ChildProcess is null"); + } + child.stderr.on("data", (data: string) => { + stderrChunks.push(data); + }); + child.stderr.on("end", () => { + stderr = stderrChunks.join(""); + }); + }); diff --git a/tsconfig.json b/tsconfig.json index 7edf5b9..3f05a06 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { + "module": "commonjs", "moduleResolution": "node", "strict": true, - "module": "commonjs", "declaration": true, "outDir": "dist" },