diff --git a/CHANGELOG.md b/CHANGELOG.md index 31c5e81..3c5a197 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [v1.0.3] - 2024-10-23 + +### Added +- Add JSDocs +- Add minified `.mjs` version + ## [v1.0.1] - 2024-10-21 ### Added diff --git a/package-lock.json b/package-lock.json index 21d9b9b..d5ef0aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@aegisjsproject/router", - "version": "1.0.1", + "version": "1.0.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@aegisjsproject/router", - "version": "1.0.1", + "version": "1.0.2", "funding": [ { "type": "librepay", @@ -19,12 +19,13 @@ ], "license": "MIT", "dependencies": { - "@aegisjsproject/state": "^1.0.1" + "@aegisjsproject/state": "^1.0.2" }, "devDependencies": { "@aegisjsproject/component": "^0.1.4", "@aegisjsproject/core": "^0.2.15", "@rollup/plugin-node-resolve": "^15.3.0", + "@rollup/plugin-terser": "^0.4.4", "@shgysk8zer0/eslint-config": "^1.0.1", "eslint": "^9.12.0", "http-server": "^14.1.1", @@ -123,9 +124,9 @@ } }, "node_modules/@aegisjsproject/state": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@aegisjsproject/state/-/state-1.0.1.tgz", - "integrity": "sha512-x2NxyGyiekvAbdQtUpCI6zk6kr5Qo96B9j+R7CR8pwm5Ky7MMCqAvfE+3QCEhn6+LXeL/O0Q1OF9f8xu5/qEqw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@aegisjsproject/state/-/state-1.0.2.tgz", + "integrity": "sha512-eRsLCidX+XwbVhJ/KOg/+Gw3ut3tl2qP4z9RHF/+iXUlHLTrMTt6j06OQIznY8ltxFDgv67L2rlJDY68H0F3Fg==", "funding": [ { "type": "librepay", @@ -358,6 +359,64 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@rollup/plugin-node-resolve": { "version": "15.3.0", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.0.tgz", @@ -382,6 +441,28 @@ } } }, + "node_modules/@rollup/plugin-terser": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", + "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", + "dev": true, + "dependencies": { + "serialize-javascript": "^6.0.1", + "smob": "^1.0.0", + "terser": "^5.17.4" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, "node_modules/@rollup/pluginutils": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.2.tgz", @@ -749,6 +830,12 @@ "concat-map": "0.0.1" } }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", @@ -811,6 +898,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "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/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1773,6 +1866,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -1858,6 +1960,15 @@ "integrity": "sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==", "dev": true }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -1914,6 +2025,31 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/smob": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", + "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", + "dev": true + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -1950,6 +2086,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/terser": { + "version": "5.36.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz", + "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -2082,9 +2236,9 @@ "dev": true }, "@aegisjsproject/state": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@aegisjsproject/state/-/state-1.0.1.tgz", - "integrity": "sha512-x2NxyGyiekvAbdQtUpCI6zk6kr5Qo96B9j+R7CR8pwm5Ky7MMCqAvfE+3QCEhn6+LXeL/O0Q1OF9f8xu5/qEqw==" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@aegisjsproject/state/-/state-1.0.2.tgz", + "integrity": "sha512-eRsLCidX+XwbVhJ/KOg/+Gw3ut3tl2qP4z9RHF/+iXUlHLTrMTt6j06OQIznY8ltxFDgv67L2rlJDY68H0F3Fg==" }, "@aegisjsproject/styles": { "version": "0.2.3", @@ -2214,6 +2368,55 @@ "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", "dev": true }, + "@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true + }, + "@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "@rollup/plugin-node-resolve": { "version": "15.3.0", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.0.tgz", @@ -2227,6 +2430,17 @@ "resolve": "^1.22.1" } }, + "@rollup/plugin-terser": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", + "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", + "dev": true, + "requires": { + "serialize-javascript": "^6.0.1", + "smob": "^1.0.0", + "terser": "^5.17.4" + } + }, "@rollup/pluginutils": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.2.tgz", @@ -2452,6 +2666,12 @@ "concat-map": "0.0.1" } }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, "call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", @@ -2496,6 +2716,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "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 + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -3179,6 +3405,15 @@ "side-channel": "^1.0.6" } }, + "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" + } + }, "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -3246,6 +3481,15 @@ "integrity": "sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==", "dev": true }, + "serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, "set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -3287,6 +3531,28 @@ "object-inspect": "^1.13.1" } }, + "smob": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", + "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -3308,6 +3574,18 @@ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true }, + "terser": { + "version": "5.36.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz", + "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + } + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", diff --git a/package.json b/package.json index 0a60d3c..cccf8da 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "@aegisjsproject/router", - "version": "1.0.1", + "version": "1.0.2", "description": "A simple but powerful router module", "keywords": [], "type": "module", "main": "./router.cjs", "module": "./router.js", - "unpkg": "./router.js", + "unpkg": "./router.mjs", "exports": { ".": { "import": "./router.js", @@ -78,12 +78,13 @@ }, "homepage": "https://github.com/AegisJSProject/router#readme", "dependencies": { - "@aegisjsproject/state": "^1.0.1" + "@aegisjsproject/state": "^1.0.2" }, "devDependencies": { "@aegisjsproject/component": "^0.1.4", "@aegisjsproject/core": "^0.2.15", "@rollup/plugin-node-resolve": "^15.3.0", + "@rollup/plugin-terser": "^0.4.4", "@shgysk8zer0/eslint-config": "^1.0.1", "eslint": "^9.12.0", "http-server": "^14.1.1", diff --git a/rollup.config.js b/rollup.config.js index b680a0f..d2af7c1 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,10 +1,16 @@ import nodeResolve from '@rollup/plugin-node-resolve'; +import terser from '@rollup/plugin-terser'; export default [{ input: 'router.js', plugins: [nodeResolve()], + external: ['@aegisjsproject/state'], output: [{ file: 'router.cjs', format: 'cjs', + }, { + file: 'router.mjs', + format: 'esm', + plugins: [terser()], }], }]; diff --git a/router.js b/router.js index 15c57cf..378d818 100644 --- a/router.js +++ b/router.js @@ -1,13 +1,11 @@ -import { getStateObj, diffState, notifyStateChange } from '@aegisjsproject/state/state.js'; +import { getStateObj, diffState, notifyStateChange } from '@aegisjsproject/state'; const registry = new Map(); const matchSymbol = Symbol('matchResult'); const NO_BODY_METHODS = ['GET', 'HEAD', 'DELETE', 'OPTIONS']; let rootEl = document.getElementById('root') ?? document.body; -const mutObserver = new MutationObserver(entries => { - entries.forEach(entry => interceptNav(entry.target)); -}); +const mutObserver = new MutationObserver(entries => entries.forEach(entry => interceptNav(entry.target))); async function _popstateHandler(event) { const diff = diffState(event.state); @@ -71,6 +69,11 @@ function _updatePage(content) { } else if (content instanceof Function && content.prototype instanceof HTMLElement) { const match = content[matchSymbol] ?? {}; rootEl.replaceChildren(new content({ state: getStateObj(), url: new URL(location.href), timestamp, ...match })); + } else if (content instanceof HTMLElement) { + // Cannot clone custom elements with non-clonable shadow roots (and cannot test on closed shadows) + const isClonable = typeof customElements.getName(content.constructor) !== 'string' + || (content.shadowRoot instanceof ShadowRoot && content.shadowRoot.clonable); + rootEl.replaceChildren(isClonable ? content.cloneNode(true) : content); } else if (content instanceof Node) { rootEl.replaceChildren(content.cloneNode(true)); } else if (content instanceof Function) { @@ -103,9 +106,9 @@ async function _handleModule(moduleSrc, args = {}) { ); } - module.default[matchSymbol] = args; + // module.default[matchSymbol] = args; - return module.default; + return new module.default(args); } else if (module.default instanceof Function) { return await module.default({ url, @@ -135,10 +138,28 @@ let view404 = ({ url = location.href, method = 'GET' }) => { return div; }; +/** + * Finds the matching URL pattern for a given input. + * + * @param {string|URL} input - The input URL or path. + * @returns {URLPattern|undefined} - The matching URL pattern, or undefined if no match is found. + */ export const findPath = input => registry.keys().find(pattern => pattern.test(input)); +/** + * Sets the 404 handler. + * + * @param {string} path - The path to the 404 handler module or the handler function itself. + */ export const set404 = path => view404 = path; +/** + * Intercepts navigation events within a target element. + * + * @param {HTMLElement|string} target - The element to intercept navigation events on. Defaults to document.body. + * @param {Object} [options] - Optional options. + * @param {AbortSignal} [options.signal] - An AbortSignal to cancel the interception. + */ export function interceptNav(target = document.body, { signal } = {}) { if (target.tagName === 'A' && target.href.startsWith(location.origin)) { entry.target.addEventListener('click', _interceptLinkClick, { signal, passive: false }); @@ -155,6 +176,11 @@ export function interceptNav(target = document.body, { signal } = {}) { } } +/** + * Sets the root element for the navigation system. + * + * @param {HTMLElement|string} target - The element to set as the root. + */ export function setRoot(target) { if (target instanceof HTMLElement) { rootEl = target; @@ -165,6 +191,13 @@ export function setRoot(target) { } } +/** + * Observes links on an element for navigation. + * + * @param {HTMLElement|string} target - The element to observe links on. Defaults to document.body. + * @param {object} [options] - Optional options. + * @param {AbortSignal} [options.signal] - An AbortSignal to cancel the observation. + */ export function observeLinksOn(target = document.body, { signal } = {}) { if (signal instanceof AbortSignal && signal.aborted) { throw signal.reason; @@ -180,6 +213,12 @@ export function observeLinksOn(target = document.body, { signal } = {}) { } } +/** + * Registers a URL pattern with its corresponding module source. + * + * @param {URLPattern|string|URL} path - The URL pattern or URL to register. + * @param {string} moduleSrc - The module source URL. + */ export function registerPath(path, moduleSrc) { if (typeof path === 'string') { registerPath(new URLPattern(path, document.baseURI), moduleSrc); @@ -192,6 +231,17 @@ export function registerPath(path, moduleSrc) { } } +/** + * Fetches a module or retrieves its content based on a URL or path. + * + * @param {URL|string|null} input - The URL, path, or null to throw an error. Defaults to `location`. + * @param {object} [options] - Optional options. + * @param {AbortSignal} [options.signal] - An AbortSignal to cancel the fetch. + * @param {string} [options.method] - The HTTP method to use for fetching the module. Defaults to 'GET'. + * @param {FormData} [options.formData] - The form data to send with the request. Defaults to a new FormData object. + * @returns {Promise} - A promise that resolves with the module content or triggers navigation if a path match is found. + * @throws {Error} - Throws an error if the input is null or cannot be parsed as a URL. + */ export async function getModule(input = location, { signal, method = 'GET', formData = new FormData() } = {}) { const timestamp = performance.now(); @@ -214,6 +264,17 @@ export async function getModule(input = location, { signal, method = 'GET', form } } +/** + * Navigates to a new URL. + * + * @param {string|URL} url - The URL to navigate to. + * @param {object} [newState] - The new state object to push to the history. + * @param {object} [options] - Optional options. + * @param {AbortSignal} [options.signal] - An AbortSignal to cancel the navigation. + * @param {string} [options.method="GET"] - The HTTP method to use for the navigation. + * @param {FormData} [options.formData] - The form data to send with the request. + * @returns {Promise} - A promise that resolves when the navigation is complete. + */ export async function navigate(url, newState = getStateObj(), { signal, method = 'GET', @@ -263,34 +324,70 @@ export async function navigate(url, newState = getStateObj(), { } } +/** + * Navigates back in the history. + */ export function back() { history.back(); } +/** + * Navigates forward in the history. + */ export function forward() { history.forward(); } +/** + * Navigates to a specific history entry. + * + * @param {number} delta - The number of entries to go back or forward. + */ export function go(delta = 0) { history.go(delta); } +/** + * Reloads the current page. + */ export function reload() { go(0); } +/** + * Adds a popstate listener to the window. + * + * @param {object} [options] - Optional options. + * @param {AbortSignal} [options.signal] - An AbortSignal to cancel the listener. + */ export function addPopstateListener({ signal } = {}) { globalThis.addEventListener('popstate', _popstateHandler, { signal }); } +/** + * Removes a popstate listener to the window. + */ export function removeListener() { globalThis.removeEventListener('popstate', _popstateHandler); } +/** + * Initializes the navigation system. + * + * @param {object} paths - An object mapping URL patterns to module source URLs or specifiers. + * @param {object} [options] - Optional options. + * @param {boolean} [options.preload=false] - Whether to preload all modules. + * @param {HTMLElement|string} [options.interceptRoot] - The element to intercept link clicks on. + * @param {string} [options.baseURL] - The base URL for URL patterns. + * @param {string} [options.notFound] - The 404 handler. + * @param {HTMLElement|string} [options.rootNode] - The root element for the navigation system. + * @param {AbortSignal} [options.signal] - An AbortSignal to cancel the initialization. + * @returns {Promise} - A promise that resolves when the initialization is complete. + */ export async function init(paths, { preload = false, inteceptRoot = document.body, - baseURL = document.baseURI, + baseURL = location.origin, notFound, rootNode, signal, @@ -320,10 +417,20 @@ export async function init(paths, { addPopstateListener({ signal }); } +/** + * Preloads a module asynchronously. + * + * @param {string} src - The URL or path to the module to preload. + * @param {object} [options] - Optional options for the preload element. + * @param {string} [options.crossOrigin="anonymous"] - The CORS mode to use when fetching the module. Defaults to 'anonymous'. + * @param {string} [options.referrerPolicy="no-referrer"] - The referrer policy to use when fetching the module. Defaults to 'no-referrer'. + * @param {string} [options.fetchPriority="low"] - The fetch priority for the preload request. Defaults to 'auto'. + * @param {string} [options.as="script"] - The type of resource to preload. Defaults to 'script'. + */ export function preloadModule(src, { crossOrigin = 'anonymous', referrerPolicy = 'no-referrer', - fetchPriority = 'auto', + fetchPriority = 'low', as = 'script', } = {}) { const link = document.createElement('link'); diff --git a/test/index.html b/test/index.html index f244e57..5bf0bc9 100644 --- a/test/index.html +++ b/test/index.html @@ -12,6 +12,7 @@ "@aegisjsproject/": "../node_modules/@aegisjsproject/", "@aegisjsproject/router": "../router.js", "@aegisjsproject/router/": "../", + "@aegisjsproject/state": "../node_modules/@aegisjsproject/state/state.mjs", "@highlightjs/cdn-assets/": "https://unpkg.com/@highlightjs/cdn-assets@11.10.0/es/", "@aegisjsproject/markdown/": "https://unpkg.com/@aegisjsproject/markdown@0.1.3/", "marked": "https://unpkg.com/marked@14.1.2/lib/marked.esm.js", @@ -34,6 +35,10 @@ Product 3 Markdown Test + Bacon Ipsum (3 lines) + Bacon Ipsum (5 lines) + shgysk8zer0 on GitHub + kernvalley on GitHub diff --git a/test/index.js b/test/index.js index ea7ea91..42e7525 100644 --- a/test/index.js +++ b/test/index.js @@ -8,6 +8,8 @@ init({ '/test/': '@view/home.js', '/search?q=:query': '@view/search.js', '/img': '@view/img.js', + '/page/bacon/:lines': '@view/bacon.js', + '/github/:username': '@view/github.js', }, { preload: true, notFound: '@view/404.js', @@ -16,18 +18,6 @@ init({ signal: controller.signal, }); -globalThis.base64ToBlob = function(input) { - const pattern = new URLPattern({ protocol: 'data:', pathname: ':type;base64,:data' }); - const { type, data } = pattern.exec(input)?.pathname?.groups ?? {}; - - if (typeof type === 'string' && typeof data === 'string') { - const bytes = Uint8Array.fromBase64(data); - return new Blob([bytes], { type }); - } else { - return null; - } -} - document.querySelectorAll('[data-link]').forEach(el => { el.addEventListener('click', ({ currentTarget }) => { const { link, ...state } = currentTarget.dataset; @@ -35,7 +25,7 @@ document.querySelectorAll('[data-link]').forEach(el => { }, { signal: controller.signal }); }); -document.querySelectorAll('[data-nav').forEach(el => { +document.querySelectorAll('[data-nav]').forEach(el => { el.addEventListener('click', ({ currentTarget }) => { switch (currentTarget.dataset.nav) { case 'back': diff --git a/test/views/bacon.js b/test/views/bacon.js new file mode 100644 index 0000000..f540ceb --- /dev/null +++ b/test/views/bacon.js @@ -0,0 +1,14 @@ +import { html } from '@aegisjsproject/core/parsers/html.js'; + +export default async ({ url: { matches} }) => { + const url = new URL('https://baconipsum.com/api/'); + url.searchParams.set('paras', matches?.pathname?.groups?.lines ?? 5); + url.searchParams.set('format', 'json'); + url.searchParams.set('start-with-lorem', 1); + url.searchParams.set('type', 'all-meat'); + + const resp = await fetch(url, { referrerPolicy: 'no-referrer' }); + const lines = await resp.json(); + + return html`${lines.map(line => `

${line}

`).join('\n')}`; +} diff --git a/test/views/github.js b/test/views/github.js new file mode 100644 index 0000000..fc05f88 --- /dev/null +++ b/test/views/github.js @@ -0,0 +1,31 @@ +import { html } from '@aegisjsproject/core/parsers/html.js'; + +export default async ({ url: { matches } }) => { + const username = matches?.pathname?.groups?.username; + + if (!username) { + return html`

Error: No GitHub username provided.

`; + } + + const apiUrl = `https://api.github.com/users/${encodeURIComponent(username)}`; + const resp = await fetch(apiUrl, { referrerPolicy: 'no-referrer' }); + + if (!resp.ok) { + return html`

Error fetching GitHub user data: ${resp.statusText}

`; + } + + const user = await resp.json(); + + return html` +
+

${user.name ?? username}

+

Username: ${user.login}

+

Bio: ${user.bio ?? 'No bio available'}

+

Public Repos: ${user.public_repos}

+

Followers: ${user.followers}

+

Following: ${user.following}

+ ${user.blog ? `

Website

` : ''} + ${user.avatar_url ? `Avatar` : ''} +
+ `; +}; diff --git a/test/views/product.js b/test/views/product.js index 0e549b4..01843f3 100644 --- a/test/views/product.js +++ b/test/views/product.js @@ -3,13 +3,19 @@ class ProductView extends HTMLElement { constructor(params) { super(); - console.log(params); - this.#shadow = this.attachShadow({ mode: 'closed' }); - const pre = document.createElement('pre'); - const code = document.createElement('code'); - code.textContent = JSON.stringify(params, null, 4); - pre.append(code); - this.#shadow.append(pre); + + if (this.shadowRoot === null) { + this.#shadow = this.attachShadow({ mode: 'open', clonable: true, serializable: true }); + const pre = document.createElement('pre'); + const code = document.createElement('code'); + code.textContent = JSON.stringify(params, null, 4); + pre.append(code); + this.#shadow.append(pre); + } else { + this.#shadow = this.shadowRoot; + } + + console.log(this.shadowRoot); } connectedCallback() {