From 85b7e70c2c30af4418dacf64d1fc4e32c8ad3e8e Mon Sep 17 00:00:00 2001 From: tada5hi Date: Sat, 14 Jan 2023 13:36:28 +0100 Subject: [PATCH] feat: stricter file loader + enhanced cjs/esm build --- package-lock.json | 289 ++++++++++++++++++++++++++- package.json | 17 +- rollup.config.mjs | 79 +++++--- src/loader/file-type/json.ts | 8 +- src/loader/file-type/script/async.ts | 20 +- src/loader/file-type/script/sync.ts | 26 +-- src/loader/file-type/script/utils.ts | 24 +-- src/loader/module.ts | 12 +- src/loader/utils.ts | 2 +- src/locator/async.ts | 18 +- src/locator/sync.ts | 16 +- src/locator/type.ts | 2 +- src/locator/utils.ts | 28 +-- src/utils/error.ts | 4 +- test/unit/loader.spec.ts | 164 ++++++++------- tsconfig.json | 23 +-- 16 files changed, 501 insertions(+), 231 deletions(-) diff --git a/package-lock.json b/package-lock.json index de37ff55..57ff95d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "@commitlint/cz-commitlint": "^17.4.2", "@rollup/plugin-babel": "^6.0.3", "@rollup/plugin-node-resolve": "^15.0.0", + "@rollup/plugin-terser": "^0.3.0", "@semantic-release/changelog": "^6.0.2", "@semantic-release/commit-analyzer": "^9.0.2", "@semantic-release/git": "^10.0.1", @@ -29,6 +30,7 @@ "@semantic-release/npm": "^9.0.1", "@semantic-release/release-notes-generator": "^10.0.3", "@tada5hi/eslint-config-typescript": "^1.1.0", + "@tada5hi/tsconfig": "^0.1.0", "@types/glob": "^8.0.0", "@types/is-file-esm": "^1.0.0", "@types/jest": "^27.5.0", @@ -40,6 +42,8 @@ "eslint": "^8.31.0", "husky": "^8.0.3", "jest": "^27.5.1", + "magic-string": "^0.27.0", + "mlly": "^1.1.0", "rimraf": "^3.0.2", "rollup": "^3.10.0", "semantic-release": "^19.0.5", @@ -2895,6 +2899,30 @@ "node": ">=6.0.0" } }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.13", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", @@ -3176,6 +3204,28 @@ } } }, + "node_modules/@rollup/plugin-terser": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.3.0.tgz", + "integrity": "sha512-mYTkNW9KjOscS/3QWU5LfOKsR3/fAAVDaqcAe2TZ7ng6pN46f+C7FOZbITuIW/neA+PhcjoKl7yMyB3XcmA4gw==", + "dev": true, + "dependencies": { + "serialize-javascript": "^6.0.0", + "smob": "^0.0.6", + "terser": "^5.15.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.x || ^3.x" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, "node_modules/@rollup/pluginutils": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz", @@ -3464,6 +3514,12 @@ "eslint-import-resolver-typescript": "^3.5.2" } }, + "node_modules/@tada5hi/tsconfig": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@tada5hi/tsconfig/-/tsconfig-0.1.0.tgz", + "integrity": "sha512-XEntby2VnfQ5dD5KeLRyykdeiYTKp0GDxL3MuPVWosh52tUHrRbwWfyj5FHdR9a7BLBDCKmLCgxY+dWScOitmg==", + "dev": true + }, "node_modules/@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -3884,9 +3940,9 @@ "dev": true }, "node_modules/acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -4810,6 +4866,12 @@ "node": ">= 0.8" } }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, "node_modules/commitizen": { "version": "4.2.5", "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.2.5.tgz", @@ -8856,6 +8918,12 @@ "node": ">=6" } }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -9185,6 +9253,18 @@ "node": ">=10" } }, + "node_modules/magic-string": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.13" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -9462,6 +9542,18 @@ "node": ">= 6" } }, + "node_modules/mlly": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.1.0.tgz", + "integrity": "sha512-cwzBrBfwGC1gYJyfcy8TcZU1f+dbH/T+TuOhtYP2wLv/Fb51/uV7HJQfBPtEupZ2ORLRU1EKFS/QfS3eo9+kBQ==", + "dev": true, + "dependencies": { + "acorn": "^8.8.1", + "pathe": "^1.0.0", + "pkg-types": "^1.0.1", + "ufo": "^1.0.1" + } + }, "node_modules/modify-values": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", @@ -12571,6 +12663,12 @@ "node": ">=8" } }, + "node_modules/pathe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.0.0.tgz", + "integrity": "sha512-nPdMG0Pd09HuSsr7QOKUXO2Jr9eqaDiZvDwdyIhNG5SHYujkQHYKDfGQkulBxvbDHz8oHLsTgKN86LSwYzSHAg==", + "dev": true + }, "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -12708,6 +12806,17 @@ "node": ">=8" } }, + "node_modules/pkg-types": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.1.tgz", + "integrity": "sha512-jHv9HB+Ho7dj6ItwppRDDl0iZRYBD0jsakHXtFgoLr+cHSF6xC+QL54sJmWxyGxOLYSHm0afhXhXcQDQqH9z8g==", + "dev": true, + "dependencies": { + "jsonc-parser": "^3.2.0", + "mlly": "^1.0.0", + "pathe": "^1.0.0" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -12825,6 +12934,15 @@ "node": ">=8" } }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -13589,6 +13707,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -14143,6 +14270,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/terser": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz", + "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -14546,6 +14691,12 @@ "node": ">=4.2.0" } }, + "node_modules/ufo": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.0.1.tgz", + "integrity": "sha512-boAm74ubXHY7KJQZLlXrtMz52qFvpsbOxDcZOnw/Wf+LS4Mmyu7JxmzD4tDLtUQtmZECypJ0FrCz4QIe6dvKRA==", + "dev": true + }, "node_modules/uglify-js": { "version": "3.17.2", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.2.tgz", @@ -17093,6 +17244,29 @@ "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", "dev": true }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, "@jridgewell/sourcemap-codec": { "version": "1.4.13", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", @@ -17297,6 +17471,17 @@ "resolve": "^1.22.1" } }, + "@rollup/plugin-terser": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.3.0.tgz", + "integrity": "sha512-mYTkNW9KjOscS/3QWU5LfOKsR3/fAAVDaqcAe2TZ7ng6pN46f+C7FOZbITuIW/neA+PhcjoKl7yMyB3XcmA4gw==", + "dev": true, + "requires": { + "serialize-javascript": "^6.0.0", + "smob": "^0.0.6", + "terser": "^5.15.1" + } + }, "@rollup/pluginutils": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz", @@ -17518,6 +17703,12 @@ "eslint-import-resolver-typescript": "^3.5.2" } }, + "@tada5hi/tsconfig": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@tada5hi/tsconfig/-/tsconfig-0.1.0.tgz", + "integrity": "sha512-XEntby2VnfQ5dD5KeLRyykdeiYTKp0GDxL3MuPVWosh52tUHrRbwWfyj5FHdR9a7BLBDCKmLCgxY+dWScOitmg==", + "dev": true + }, "@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -17846,9 +18037,9 @@ "dev": true }, "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true }, "acorn-globals": { @@ -18532,6 +18723,12 @@ "delayed-stream": "~1.0.0" } }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, "commitizen": { "version": "4.2.5", "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.2.5.tgz", @@ -21582,6 +21779,12 @@ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true }, + "jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, "jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -21856,6 +22059,15 @@ "yallist": "^4.0.0" } }, + "magic-string": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "dev": true, + "requires": { + "@jridgewell/sourcemap-codec": "^1.4.13" + } + }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -22052,6 +22264,18 @@ "kind-of": "^6.0.3" } }, + "mlly": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.1.0.tgz", + "integrity": "sha512-cwzBrBfwGC1gYJyfcy8TcZU1f+dbH/T+TuOhtYP2wLv/Fb51/uV7HJQfBPtEupZ2ORLRU1EKFS/QfS3eo9+kBQ==", + "dev": true, + "requires": { + "acorn": "^8.8.1", + "pathe": "^1.0.0", + "pkg-types": "^1.0.1", + "ufo": "^1.0.1" + } + }, "modify-values": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", @@ -24249,6 +24473,12 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, + "pathe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.0.0.tgz", + "integrity": "sha512-nPdMG0Pd09HuSsr7QOKUXO2Jr9eqaDiZvDwdyIhNG5SHYujkQHYKDfGQkulBxvbDHz8oHLsTgKN86LSwYzSHAg==", + "dev": true + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -24349,6 +24579,17 @@ } } }, + "pkg-types": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.1.tgz", + "integrity": "sha512-jHv9HB+Ho7dj6ItwppRDDl0iZRYBD0jsakHXtFgoLr+cHSF6xC+QL54sJmWxyGxOLYSHm0afhXhXcQDQqH9z8g==", + "dev": true, + "requires": { + "jsonc-parser": "^3.2.0", + "mlly": "^1.0.0", + "pathe": "^1.0.0" + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -24426,6 +24667,15 @@ "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", "dev": true }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, "rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -25012,6 +25262,15 @@ "integrity": "sha512-6IiqeZNgq01qGf0TId0t3NvKzSvUsjcpdEO3AQNeIjR6A2+ckTnQlDpl4qu1bjRv0RzN3FP9hzFmws3lKqRWkA==", "dev": true }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -25446,6 +25705,18 @@ "supports-hyperlinks": "^2.0.0" } }, + "terser": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz", + "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + } + }, "test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -25740,6 +26011,12 @@ "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", "dev": true }, + "ufo": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.0.1.tgz", + "integrity": "sha512-boAm74ubXHY7KJQZLlXrtMz52qFvpsbOxDcZOnw/Wf+LS4Mmyu7JxmzD4tDLtUQtmZECypJ0FrCz4QIe6dvKRA==", + "dev": true + }, "uglify-js": { "version": "3.17.2", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.2.tgz", diff --git a/package.json b/package.json index 1ccfd1d5..58d8247f 100644 --- a/package.json +++ b/package.json @@ -11,9 +11,16 @@ "type": "git", "url": "https://github.com/tada5hi/locter.git" }, - "main": "dist/index.cjs.js", - "module": "dist/index.esm.js", - "types": "dist/types/index.d.ts", + "main": "dist/index.cjs", + "module": "dist/index.mjs", + "types": "dist/index.d.ts", + "exports": { + "./package.json": "./package.json", + ".": { + "require": "./dist/index.cjs", + "import": "./dist/index.mjs" + } + }, "files": [ "dist/" ], @@ -46,6 +53,7 @@ "@commitlint/cz-commitlint": "^17.4.2", "@rollup/plugin-babel": "^6.0.3", "@rollup/plugin-node-resolve": "^15.0.0", + "@rollup/plugin-terser": "^0.3.0", "@semantic-release/changelog": "^6.0.2", "@semantic-release/commit-analyzer": "^9.0.2", "@semantic-release/git": "^10.0.1", @@ -53,6 +61,7 @@ "@semantic-release/npm": "^9.0.1", "@semantic-release/release-notes-generator": "^10.0.3", "@tada5hi/eslint-config-typescript": "^1.1.0", + "@tada5hi/tsconfig": "^0.1.0", "@types/glob": "^8.0.0", "@types/is-file-esm": "^1.0.0", "@types/jest": "^27.5.0", @@ -64,6 +73,8 @@ "eslint": "^8.31.0", "husky": "^8.0.3", "jest": "^27.5.1", + "magic-string": "^0.27.0", + "mlly": "^1.1.0", "rimraf": "^3.0.2", "rollup": "^3.10.0", "semantic-release": "^19.0.5", diff --git a/rollup.config.mjs b/rollup.config.mjs index 6073a977..4464afaa 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -7,12 +7,42 @@ import resolve from '@rollup/plugin-node-resolve'; import babel from '@rollup/plugin-babel'; +import terser from '@rollup/plugin-terser'; import pkg from './package.json' assert { type: 'json' }; +import { findStaticImports } from 'mlly'; +import MagicString from 'magic-string'; const extensions = [ '.js', '.jsx', '.ts', '.tsx', ]; +const CJSyntaxRe = /__filename|__dirname|require\(|require\.resolve\(/; + +const CJSShim = ` +import __cjs_url__ from 'url'; +import __cjs_path__ from 'path'; +import __cjs_mod__ from 'module'; +const __filename = __cjs_url__.fileURLToPath(import.meta.url); +const __dirname = __cjs_path__.dirname(__filename); +const require = __cjs_mod__.createRequire(import.meta.url); +`; + +function transformCJSToESM(code) { + if (code.includes(CJSShim) || !CJSyntaxRe.test(code)) { + return null; + } + + const lastESMImport = findStaticImports(code).pop(); + const indexToAppend = lastESMImport ? lastESMImport.end : 0; + const s = new MagicString(code); + s.appendRight(indexToAppend, CJSShim); + + return { + code: s.toString(), + map: s.generateMap(), + }; +} + export default [ { input: './src/index.ts', @@ -35,46 +65,31 @@ export default [ include: [ 'src/**/*', ], - }) + }), + + { + renderChunk(code, _chunk, opts) { + if (opts.format === "es") { + return transformCJSToESM(code); + } + + return null; + } + }, + + terser() ], output: [ { file: pkg.module, format: 'esm', + sourcemap: true }, - ], - }, - { - input: './src/index.ts', - - // Specify here external modules which you don't want to include in your bundle (for instance: 'lodash', 'moment' etc.) - // https://rollupjs.org/guide/en/#external - external: [ - ...Object.keys(pkg.dependencies || {}), - ...Object.keys(pkg.peerDependencies || {}), - ], - - plugins: [ - // Allows node_modules resolution - resolve({ extensions }), - - // Compile TypeScript/JavaScript files - babel({ - extensions, - babelHelpers: 'bundled', - include: [ - 'src/**/*', - ], - plugins: [ - "dynamic-import-node" - ] - }) - ], - output: [ { file: pkg.main, - format: 'cjs' + format: 'cjs', + sourcemap: true } ], - }, + } ]; diff --git a/src/loader/file-type/json.ts b/src/loader/file-type/json.ts index dedc77e7..2d3b1bbf 100644 --- a/src/loader/file-type/json.ts +++ b/src/loader/file-type/json.ts @@ -5,13 +5,13 @@ * view the LICENSE file that was distributed with this source code. */ -import fs from 'fs'; -import path from 'path'; +import fs from 'node:fs'; +import path from 'node:path'; import { LocatorInfo } from '../../locator'; import { handleFileLoadError } from '../../utils'; import { buildLoaderFilePath } from '../utils'; -export async function loadJsonFile(input: LocatorInfo | string) : Promise { +export async function loadJsonFile(input: LocatorInfo | string) : Promise { let filePath : string; if (typeof input === 'string') { @@ -28,7 +28,7 @@ export async function loadJsonFile(input: LocatorInfo | string) : Promise { +) : Promise { let locatorInfo : LocatorInfo; if (typeof data === 'string') { @@ -83,16 +83,12 @@ export async function loadScriptFile( export async function loadScriptFileExport( data: LocatorInfo | string, filterFn?: LoaderFilterFn, -) : Promise { - try { - const output = await loadScriptFile(data); - if (typeof output === 'object') { - return getExportItem(output, filterFn); - } +) : Promise { + const output = await loadScriptFile(data); - return undefined; - } catch (e) { - /* istanbul ignore next */ - return handleFileLoadError(e); + if (typeof output === 'object' && !!output) { + return getExportItem(output, filterFn); } + + throw new BaseError('Cannot extract specific module export'); } diff --git a/src/loader/file-type/script/sync.ts b/src/loader/file-type/script/sync.ts index 09ecf1d7..687c04ca 100644 --- a/src/loader/file-type/script/sync.ts +++ b/src/loader/file-type/script/sync.ts @@ -8,7 +8,7 @@ import { BaseError } from 'ebec'; import { LoaderFilterFn, ScriptFileExportItem, ScriptFileLoadOptions } from './type'; import { getExportItem } from './utils'; -import { LocatorInfo, isLocatorInfo, pathToLocatorInfo } from '../../../locator'; +import { LocatorInfo, pathToLocatorInfo } from '../../../locator'; import { buildLoaderFilePath } from '../../utils'; import { handleFileLoadError, hasStringProperty, isObject, @@ -17,7 +17,7 @@ import { export function loadScriptFileSync( data: LocatorInfo | string, options?: ScriptFileLoadOptions, -) : unknown | undefined { +) : unknown { let locatorInfo : LocatorInfo; if (typeof data === 'string') { @@ -31,7 +31,7 @@ export function loadScriptFileSync( const filePath = buildLoaderFilePath(locatorInfo, options.withExtension); try { - // eslint-disable-next-line @typescript-eslint/no-var-requires, global-require,import/no-dynamic-require + // eslint-disable-next-line global-require,import/no-dynamic-require return require(filePath); } catch (e) { /* istanbul ignore next */ @@ -66,20 +66,12 @@ export function loadScriptFileSync( export function loadScriptFileExportSync( data: LocatorInfo | string, filterFn?: LoaderFilterFn, -) : ScriptFileExportItem | undefined { - const filePath = isLocatorInfo(data) ? - buildLoaderFilePath(data) : - data; +) : ScriptFileExportItem { + const output = loadScriptFileSync(data); - try { - const data = loadScriptFileSync(filePath); - - if (typeof data === 'object') { - return getExportItem(data, filterFn); - } - - return undefined; - } catch (e) { - return handleFileLoadError(e); + if (typeof output === 'object' && !!output) { + return getExportItem(output, filterFn); } + + throw new BaseError('Cannot extract specific module export'); } diff --git a/src/loader/file-type/script/utils.ts b/src/loader/file-type/script/utils.ts index 8c84f1d9..177f2586 100644 --- a/src/loader/file-type/script/utils.ts +++ b/src/loader/file-type/script/utils.ts @@ -5,30 +5,30 @@ * view the LICENSE file that was distributed with this source code. */ +import { BaseError } from 'ebec'; import { hasOwnProperty } from '../../../utils'; import { LoaderFilterFn, ScriptFileExportItem } from './type'; export function getExportItem( data: Record, - filterFn: LoaderFilterFn, -) : ScriptFileExportItem | undefined { + filterFn?: LoaderFilterFn, +) : ScriptFileExportItem { if (filterFn) { const keys = Object.keys(data); for (let i = 0; i < keys.length; i++) { - if (filterFn(keys[i], data[keys[i]])) { + if (filterFn(keys[i] as string, data[keys[i] as string])) { return { - key: keys[i], - value: data[keys[i]], + key: keys[i] as string, + value: data[keys[i] as string], }; } } - } else { - return { - key: 'default', - value: hasOwnProperty(data, 'default') ? data.default : data, - }; + + throw new BaseError('Cannot find specific module export.'); } - /* istanbul ignore next */ - return undefined; + return { + key: 'default', + value: hasOwnProperty(data, 'default') ? data.default : data, + }; } diff --git a/src/loader/module.ts b/src/loader/module.ts index e85cbf1c..d94b6fec 100644 --- a/src/loader/module.ts +++ b/src/loader/module.ts @@ -13,11 +13,7 @@ import { loadScriptFileSync, } from './file-type'; -export async function loadFile(input: LocatorInfo | string) : Promise { - if (!input) { - return undefined; - } - +export async function loadFile(input: LocatorInfo | string) : Promise { let info : LocatorInfo; if (typeof input === 'string') { info = pathToLocatorInfo(input); @@ -32,11 +28,7 @@ export async function loadFile(input: LocatorInfo | string) : Promise) : LocatorOptions { options = options || {}; @@ -23,30 +23,6 @@ export function buildLocatorOptions(options?: Partial) : Locator return options as LocatorOptions; } -/* istanbul ignore next */ -export function isLocatorInfo(data: unknown) : data is LocatorInfo { - if (typeof data !== 'object') { - return false; - } - - if ( - !hasOwnProperty(data, 'path') || - typeof data.path !== 'string' - ) { - return false; - } - - if ( - !hasOwnProperty(data, 'name') || - typeof data.name !== 'string' - ) { - return false; - } - - return !(!hasOwnProperty(data, 'extension') || - typeof data.extension !== 'string'); -} - export function pathToLocatorInfo( input: string, skipResolve?: boolean, diff --git a/src/utils/error.ts b/src/utils/error.ts index 6a1e8b9a..be0405ec 100644 --- a/src/utils/error.ts +++ b/src/utils/error.ts @@ -6,7 +6,7 @@ */ /* istanbul ignore next */ -export function handleFileLoadError(e: unknown) : undefined { +export function handleFileLoadError(e: unknown) : void { if (e instanceof Error) { throw e; } @@ -15,5 +15,5 @@ export function handleFileLoadError(e: unknown) : undefined { throw new Error(e); } - return undefined; + throw new Error('Cannot determine file loading error.'); } diff --git a/test/unit/loader.spec.ts b/test/unit/loader.spec.ts index 01405757..2ec9e1d1 100644 --- a/test/unit/loader.spec.ts +++ b/test/unit/loader.spec.ts @@ -15,7 +15,8 @@ import { loadScriptFileExportSync, loadScriptFileSync, locateFile, - locateFileSync + locateFileSync, + LocatorInfo } from "../../src"; const basePath = path.join(__dirname, '..', 'data'); @@ -23,107 +24,136 @@ const basePath = path.join(__dirname, '..', 'data'); describe('src/loader/**', () => { it('should load .js file', async () => { let locatorInfo = await locateFile( 'file.js', {path: [basePath]}); - let loaderContent : Record = await loadFile(locatorInfo); - expect(loaderContent).toBeDefined(); - expect(loaderContent.default).toBeDefined(); - expect(loaderContent.foo).toEqual('bar'); + expect(locatorInfo).toBeDefined(); - loaderContent = await loadFile(buildLoaderFilePath(locatorInfo)); - expect(loaderContent).toBeDefined(); + let loaderContent : Record; - loaderContent = await loadScriptFileExport(locatorInfo); - expect(loaderContent).toBeDefined(); - expect(loaderContent.key).toEqual('default'); - expect(loaderContent.value).toEqual({foo: 'bar'}); + if(locatorInfo) { + loaderContent = await loadFile(locatorInfo) as Record; + expect(loaderContent).toBeDefined(); + expect(loaderContent.default).toBeDefined(); + expect(loaderContent.foo).toEqual('bar'); - loaderContent = await loadScriptFile(buildLoaderFilePath(locatorInfo)); - expect(loaderContent).toBeDefined(); + loaderContent = await loadFile(buildLoaderFilePath(locatorInfo)) as Record; + expect(loaderContent).toBeDefined(); - // -------------------------------------------------------------------- + loaderContent = await loadScriptFileExport(locatorInfo) as Record; + expect(loaderContent).toBeDefined(); + expect(loaderContent.key).toEqual('default'); + expect(loaderContent.value).toEqual({foo: 'bar'}); - locatorInfo = locateFileSync( 'file.js', {path: [basePath]}); - loaderContent = loadFileSync(locatorInfo); - expect(loaderContent).toBeDefined(); - expect(loaderContent.default).toBeUndefined(); - expect(loaderContent.foo).toEqual('bar'); + loaderContent = await loadScriptFile(buildLoaderFilePath(locatorInfo)) as Record; + expect(loaderContent).toBeDefined(); + } + // -------------------------------------------------------------------- - loaderContent = loadFileSync(buildLoaderFilePath(locatorInfo)); - expect(loaderContent).toBeDefined(); + locatorInfo = locateFileSync('file.js', {path: [basePath]}); + expect(locatorInfo).toBeDefined(); - loaderContent = loadScriptFileExportSync(locatorInfo); - expect(loaderContent).toBeDefined(); - expect(loaderContent.key).toEqual('default'); - expect(loaderContent.value).toEqual({foo: 'bar'}); + if(locatorInfo) { + loaderContent = loadFileSync(locatorInfo) as Record; + expect(loaderContent).toBeDefined(); + expect(loaderContent.default).toBeUndefined(); + expect(loaderContent.foo).toEqual('bar'); - loaderContent = loadScriptFileSync(buildLoaderFilePath(locatorInfo)); - expect(loaderContent).toBeDefined(); + loaderContent = loadFileSync(buildLoaderFilePath(locatorInfo)) as Record; + expect(loaderContent).toBeDefined(); + + loaderContent = loadScriptFileExportSync(locatorInfo) as Record; + expect(loaderContent).toBeDefined(); + expect(loaderContent.key).toEqual('default'); + expect(loaderContent.value).toEqual({foo: 'bar'}); + + loaderContent = loadScriptFileSync(buildLoaderFilePath(locatorInfo)) as Record; + expect(loaderContent).toBeDefined(); + } }); it('should load .ts file', async () => { let locatorInfo = await locateFile( 'file-ts.ts', {path: [basePath]}); - let loaderContent : Record = await loadFile(locatorInfo); - expect(loaderContent).toBeDefined(); - expect(loaderContent.default).toBeDefined(); - expect(loaderContent.bar).toEqual('baz'); + expect(locatorInfo).toBeDefined(); - loaderContent = await loadScriptFileExport(locatorInfo); - expect(loaderContent).toBeDefined(); - expect(loaderContent.key).toEqual('default'); - expect(loaderContent.value).toEqual({bar: 'baz'}); + let loaderContent; + + if(locatorInfo) { + loaderContent = await loadFile(locatorInfo) as Record; + expect(loaderContent).toBeDefined(); + expect(loaderContent.default).toBeDefined(); + expect(loaderContent.bar).toEqual('baz'); + + loaderContent = await loadScriptFileExport(locatorInfo) as Record; + expect(loaderContent).toBeDefined(); + expect(loaderContent.key).toEqual('default'); + expect(loaderContent.value).toEqual({bar: 'baz'}); + } // -------------------------------------------------------------------- locatorInfo = locateFileSync( 'file-ts.ts', {path: [basePath]}); - loaderContent = loadFileSync(locatorInfo); - expect(loaderContent).toBeDefined(); - expect(loaderContent.bar).toEqual('baz'); + expect(locatorInfo).toBeDefined(); - loaderContent = loadScriptFileExportSync(locatorInfo); - expect(loaderContent).toBeDefined(); - expect(loaderContent.key).toEqual('default'); - expect(loaderContent.value).toEqual({bar: 'baz'}); + if(locatorInfo) { + loaderContent = loadFileSync(locatorInfo) as Record; + expect(loaderContent).toBeDefined(); + expect(loaderContent.bar).toEqual('baz'); + + loaderContent = loadScriptFileExportSync(locatorInfo) as Record;; + expect(loaderContent).toBeDefined(); + expect(loaderContent.key).toEqual('default'); + expect(loaderContent.value).toEqual({bar: 'baz'}); + } }); it('should filter .ts file', async () => { let locatorInfo = await locateFile( 'file-many-ts.ts', {path: [basePath]}); - let loaderContent : Record = await loadScriptFileExport(locatorInfo, (key, value) => { - return key === 'bar'; - }); - expect(loaderContent).toBeDefined(); - expect(loaderContent.key).toEqual('bar'); - expect(loaderContent.value).toEqual('baz'); + let loaderContent : Record; + + if(locatorInfo) { + loaderContent = await loadScriptFileExport(locatorInfo, (key) => { + return key === 'bar'; + }) as Record; + + expect(loaderContent).toBeDefined(); + expect(loaderContent.key).toEqual('bar'); + expect(loaderContent.value).toEqual('baz'); + } locatorInfo = locateFileSync( 'file-many-ts.ts', {path: [basePath]}); - loaderContent = loadScriptFileExportSync(locatorInfo, (key, value) => { - return key === 'bar'; - }); - expect(loaderContent).toBeDefined(); - expect(loaderContent.key).toEqual('bar'); - expect(loaderContent.value).toEqual('baz'); + expect(locatorInfo).toBeDefined(); + + if(locatorInfo) { + loaderContent = loadScriptFileExportSync(locatorInfo, (key) => { + return key === 'bar'; + }) as Record; + expect(loaderContent).toBeDefined(); + expect(loaderContent.key).toEqual('bar'); + expect(loaderContent.value).toEqual('baz'); + } }) it('should load .json file', async () => { - let locatorInfo = await locateFile( 'file.json', {path: [basePath]}); - let loaderContent : Record = await loadFile(locatorInfo); + let locatorInfo = await locateFile( 'file.json', {path: [basePath]}) as LocatorInfo; + expect(locatorInfo).toBeDefined(); + + let loaderContent : Record = await loadFile(locatorInfo) as Record; expect(loaderContent).toBeDefined(); expect(loaderContent.foo).toEqual('bar'); - locatorInfo = locateFileSync( 'file.json', {path: [basePath]}); - loaderContent = loadFileSync(locatorInfo); + locatorInfo = locateFileSync( 'file.json', {path: [basePath]}) as LocatorInfo; + expect(locatorInfo).toBeDefined(); + + loaderContent = loadFileSync(locatorInfo) as Record; expect(loaderContent).toBeDefined(); expect(loaderContent.foo).toEqual('bar'); }); it('should not load file', async () => { - let locatorInfo = await locateFile( 'file.foo', {path: [basePath]}); - let loaderContent : Record = await loadFile(locatorInfo); - expect(loaderContent).toBeUndefined(); - - locatorInfo = locateFileSync( 'file.foo', {path: [basePath]}); - loaderContent = loadFileSync(locatorInfo); - expect(loaderContent).toBeUndefined(); - - await expect(loadFile('file.foo')).rejects.toThrow(); + try { + await loadFile('file.foo'); + expect(true).toBe(false); + } catch (e) { + expect(e).toBeDefined(); + } try { loadFileSync('file.foo'); diff --git a/tsconfig.json b/tsconfig.json index 9be5380a..410674b0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,28 +1,9 @@ { + "extends": "@tada5hi/tsconfig", "compilerOptions": { - "strict": true, - "skipLibCheck": true, + "noPropertyAccessFromIndexSignature": false, "esModuleInterop": true, - "declarationDir": "dist/types", - "declaration": true, - "experimentalDecorators": true, - "emitDecoratorMetadata": true, - "lib": [ - "ESNext" - ], - "module": "ESNext", - "moduleResolution": "Node", - "newLine": "LF", - "noFallthroughCasesInSwitch": true, - "noImplicitAny": true, - "noImplicitReturns": true, - "noImplicitThis": false, - "noUnusedParameters": false, - "noUnusedLocals": true, "outDir": "dist", - "sourceMap": true, - "strictNullChecks": false, - "target": "ESNext" }, "include": [ "src/**/*.ts"