feat: 分类锚点&质量检查&依赖治理
- 分类生成唯一 slug,模板/子菜单/滚动/扩展定位统一使用 data-id - lint 覆盖 src/scripts/test,CI 增量格式检查 - 清理冗余依赖,升级 esbuild,overrides 修复审计项 - 补充单测并更新修复清单
This commit is contained in:
7
.github/workflows/ci.yml
vendored
7
.github/workflows/ci.yml
vendored
@@ -2,7 +2,7 @@ name: CI
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ main ]
|
branches: [main]
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -11,6 +11,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
@@ -21,6 +23,9 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Format check (changed files)
|
||||||
|
run: npm run format:check:changed
|
||||||
|
|
||||||
- name: Lint
|
- name: Lint
|
||||||
run: npm run lint
|
run: npm run lint
|
||||||
|
|
||||||
|
|||||||
347
package-lock.json
generated
347
package-lock.json
generated
@@ -9,27 +9,20 @@
|
|||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-regex": "^6.0.1",
|
|
||||||
"ansi-styles": "^6.2.1",
|
|
||||||
"color-convert": "^2.0.1",
|
|
||||||
"color-name": "^2.0.0",
|
|
||||||
"handlebars": "^4.7.8",
|
"handlebars": "^4.7.8",
|
||||||
"has-flag": "^5.0.1",
|
|
||||||
"js-yaml": "^4.1.1",
|
"js-yaml": "^4.1.1",
|
||||||
"mime-db": "^1.52.0",
|
"rss-parser": "^3.13.0"
|
||||||
"rss-parser": "^3.13.0",
|
|
||||||
"supports-color": "^9.4.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"esbuild": "^0.20.2",
|
"esbuild": "^0.27.2",
|
||||||
"prettier": "^3.4.2",
|
"prettier": "^3.4.2",
|
||||||
"serve": "^14.2.5"
|
"serve": "^14.2.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/aix-ppc64": {
|
"node_modules/@esbuild/aix-ppc64": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz",
|
||||||
"integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==",
|
"integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
@@ -40,13 +33,13 @@
|
|||||||
"aix"
|
"aix"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/android-arm": {
|
"node_modules/@esbuild/android-arm": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz",
|
||||||
"integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==",
|
"integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@@ -57,13 +50,13 @@
|
|||||||
"android"
|
"android"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/android-arm64": {
|
"node_modules/@esbuild/android-arm64": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz",
|
||||||
"integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==",
|
"integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -74,13 +67,13 @@
|
|||||||
"android"
|
"android"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/android-x64": {
|
"node_modules/@esbuild/android-x64": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz",
|
||||||
"integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==",
|
"integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -91,13 +84,13 @@
|
|||||||
"android"
|
"android"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/darwin-arm64": {
|
"node_modules/@esbuild/darwin-arm64": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz",
|
||||||
"integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==",
|
"integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -108,13 +101,13 @@
|
|||||||
"darwin"
|
"darwin"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/darwin-x64": {
|
"node_modules/@esbuild/darwin-x64": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz",
|
||||||
"integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==",
|
"integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -125,13 +118,13 @@
|
|||||||
"darwin"
|
"darwin"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/freebsd-arm64": {
|
"node_modules/@esbuild/freebsd-arm64": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz",
|
||||||
"integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==",
|
"integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -142,13 +135,13 @@
|
|||||||
"freebsd"
|
"freebsd"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/freebsd-x64": {
|
"node_modules/@esbuild/freebsd-x64": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz",
|
||||||
"integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==",
|
"integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -159,13 +152,13 @@
|
|||||||
"freebsd"
|
"freebsd"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-arm": {
|
"node_modules/@esbuild/linux-arm": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz",
|
||||||
"integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==",
|
"integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@@ -176,13 +169,13 @@
|
|||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-arm64": {
|
"node_modules/@esbuild/linux-arm64": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz",
|
||||||
"integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==",
|
"integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -193,13 +186,13 @@
|
|||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-ia32": {
|
"node_modules/@esbuild/linux-ia32": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz",
|
||||||
"integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==",
|
"integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
@@ -210,13 +203,13 @@
|
|||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-loong64": {
|
"node_modules/@esbuild/linux-loong64": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz",
|
||||||
"integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==",
|
"integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"loong64"
|
"loong64"
|
||||||
],
|
],
|
||||||
@@ -227,13 +220,13 @@
|
|||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-mips64el": {
|
"node_modules/@esbuild/linux-mips64el": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz",
|
||||||
"integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==",
|
"integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"mips64el"
|
"mips64el"
|
||||||
],
|
],
|
||||||
@@ -244,13 +237,13 @@
|
|||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-ppc64": {
|
"node_modules/@esbuild/linux-ppc64": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz",
|
||||||
"integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==",
|
"integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
@@ -261,13 +254,13 @@
|
|||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-riscv64": {
|
"node_modules/@esbuild/linux-riscv64": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz",
|
||||||
"integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==",
|
"integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
@@ -278,13 +271,13 @@
|
|||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-s390x": {
|
"node_modules/@esbuild/linux-s390x": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz",
|
||||||
"integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==",
|
"integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
@@ -295,13 +288,13 @@
|
|||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-x64": {
|
"node_modules/@esbuild/linux-x64": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz",
|
||||||
"integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==",
|
"integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -312,13 +305,30 @@
|
|||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/netbsd-arm64": {
|
||||||
|
"version": "0.27.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz",
|
||||||
|
"integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"netbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/netbsd-x64": {
|
"node_modules/@esbuild/netbsd-x64": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz",
|
||||||
"integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==",
|
"integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -329,13 +339,30 @@
|
|||||||
"netbsd"
|
"netbsd"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/openbsd-arm64": {
|
||||||
|
"version": "0.27.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz",
|
||||||
|
"integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"openbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/openbsd-x64": {
|
"node_modules/@esbuild/openbsd-x64": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz",
|
||||||
"integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==",
|
"integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -346,13 +373,30 @@
|
|||||||
"openbsd"
|
"openbsd"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/openharmony-arm64": {
|
||||||
|
"version": "0.27.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz",
|
||||||
|
"integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"openharmony"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/sunos-x64": {
|
"node_modules/@esbuild/sunos-x64": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz",
|
||||||
"integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==",
|
"integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -363,13 +407,13 @@
|
|||||||
"sunos"
|
"sunos"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-arm64": {
|
"node_modules/@esbuild/win32-arm64": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz",
|
||||||
"integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==",
|
"integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -380,13 +424,13 @@
|
|||||||
"win32"
|
"win32"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-ia32": {
|
"node_modules/@esbuild/win32-ia32": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz",
|
||||||
"integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==",
|
"integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
@@ -397,13 +441,13 @@
|
|||||||
"win32"
|
"win32"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-x64": {
|
"node_modules/@esbuild/win32-x64": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz",
|
||||||
"integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==",
|
"integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -414,7 +458,7 @@
|
|||||||
"win32"
|
"win32"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@zeit/schemas": {
|
"node_modules/@zeit/schemas": {
|
||||||
@@ -500,6 +544,7 @@
|
|||||||
"version": "6.1.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
|
||||||
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
|
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
@@ -512,6 +557,7 @@
|
|||||||
"version": "6.2.1",
|
"version": "6.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
|
||||||
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
|
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
@@ -585,9 +631,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/brace-expansion": {
|
"node_modules/brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.12",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -738,6 +784,7 @@
|
|||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"color-name": "~1.1.4"
|
"color-name": "~1.1.4"
|
||||||
@@ -750,17 +797,9 @@
|
|||||||
"version": "1.1.4",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/color-name": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-SbtvAMWvASO5TE2QP07jHBMXKafgdZz8Vrsrn96fiL+O92/FN/PLARzUW5sKt013fjAprK2d2iCn2hk2Xb5oow==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12.20"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/compressible": {
|
"node_modules/compressible": {
|
||||||
"version": "2.0.18",
|
"version": "2.0.18",
|
||||||
"resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
|
"resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
|
||||||
@@ -879,9 +918,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/esbuild": {
|
"node_modules/esbuild": {
|
||||||
"version": "0.20.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz",
|
||||||
"integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==",
|
"integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -889,32 +928,35 @@
|
|||||||
"esbuild": "bin/esbuild"
|
"esbuild": "bin/esbuild"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@esbuild/aix-ppc64": "0.20.2",
|
"@esbuild/aix-ppc64": "0.27.2",
|
||||||
"@esbuild/android-arm": "0.20.2",
|
"@esbuild/android-arm": "0.27.2",
|
||||||
"@esbuild/android-arm64": "0.20.2",
|
"@esbuild/android-arm64": "0.27.2",
|
||||||
"@esbuild/android-x64": "0.20.2",
|
"@esbuild/android-x64": "0.27.2",
|
||||||
"@esbuild/darwin-arm64": "0.20.2",
|
"@esbuild/darwin-arm64": "0.27.2",
|
||||||
"@esbuild/darwin-x64": "0.20.2",
|
"@esbuild/darwin-x64": "0.27.2",
|
||||||
"@esbuild/freebsd-arm64": "0.20.2",
|
"@esbuild/freebsd-arm64": "0.27.2",
|
||||||
"@esbuild/freebsd-x64": "0.20.2",
|
"@esbuild/freebsd-x64": "0.27.2",
|
||||||
"@esbuild/linux-arm": "0.20.2",
|
"@esbuild/linux-arm": "0.27.2",
|
||||||
"@esbuild/linux-arm64": "0.20.2",
|
"@esbuild/linux-arm64": "0.27.2",
|
||||||
"@esbuild/linux-ia32": "0.20.2",
|
"@esbuild/linux-ia32": "0.27.2",
|
||||||
"@esbuild/linux-loong64": "0.20.2",
|
"@esbuild/linux-loong64": "0.27.2",
|
||||||
"@esbuild/linux-mips64el": "0.20.2",
|
"@esbuild/linux-mips64el": "0.27.2",
|
||||||
"@esbuild/linux-ppc64": "0.20.2",
|
"@esbuild/linux-ppc64": "0.27.2",
|
||||||
"@esbuild/linux-riscv64": "0.20.2",
|
"@esbuild/linux-riscv64": "0.27.2",
|
||||||
"@esbuild/linux-s390x": "0.20.2",
|
"@esbuild/linux-s390x": "0.27.2",
|
||||||
"@esbuild/linux-x64": "0.20.2",
|
"@esbuild/linux-x64": "0.27.2",
|
||||||
"@esbuild/netbsd-x64": "0.20.2",
|
"@esbuild/netbsd-arm64": "0.27.2",
|
||||||
"@esbuild/openbsd-x64": "0.20.2",
|
"@esbuild/netbsd-x64": "0.27.2",
|
||||||
"@esbuild/sunos-x64": "0.20.2",
|
"@esbuild/openbsd-arm64": "0.27.2",
|
||||||
"@esbuild/win32-arm64": "0.20.2",
|
"@esbuild/openbsd-x64": "0.27.2",
|
||||||
"@esbuild/win32-ia32": "0.20.2",
|
"@esbuild/openharmony-arm64": "0.27.2",
|
||||||
"@esbuild/win32-x64": "0.20.2"
|
"@esbuild/sunos-x64": "0.27.2",
|
||||||
|
"@esbuild/win32-arm64": "0.27.2",
|
||||||
|
"@esbuild/win32-ia32": "0.27.2",
|
||||||
|
"@esbuild/win32-x64": "0.27.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/execa": {
|
"node_modules/execa": {
|
||||||
@@ -982,18 +1024,6 @@
|
|||||||
"uglify-js": "^3.1.4"
|
"uglify-js": "^3.1.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/has-flag": {
|
|
||||||
"version": "5.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-5.0.1.tgz",
|
|
||||||
"integrity": "sha512-CsNUt5x9LUdx6hnk/E2SZLsDyvfqANZSUq4+D3D8RzDJ2M+HDTIkF60ibS1vHaK55vzgiZw1bEPFG9yH7l33wA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/human-signals": {
|
"node_modules/human-signals": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
|
||||||
@@ -1113,6 +1143,7 @@
|
|||||||
"version": "1.54.0",
|
"version": "1.54.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
||||||
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
|
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
@@ -1517,18 +1548,6 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/supports-color": {
|
|
||||||
"version": "9.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.4.0.tgz",
|
|
||||||
"integrity": "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/type-fest": {
|
"node_modules/type-fest": {
|
||||||
"version": "2.19.0",
|
"version": "2.19.0",
|
||||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
|
||||||
|
|||||||
15
package.json
15
package.json
@@ -14,9 +14,10 @@
|
|||||||
"sync-projects": "node ./scripts/sync-projects.js",
|
"sync-projects": "node ./scripts/sync-projects.js",
|
||||||
"import-bookmarks": "node src/bookmark-processor.js",
|
"import-bookmarks": "node src/bookmark-processor.js",
|
||||||
"test": "node --test test/*.js",
|
"test": "node --test test/*.js",
|
||||||
"lint": "node --check \"src/generator.js\" && node --check \"src/bookmark-processor.js\" && node --check \"src/script.js\"",
|
"lint": "node ./scripts/lint.js",
|
||||||
"format": "prettier --write \"src/**/*.js\" \"scripts/**/*.js\" \"test/**/*.js\" \".github/**/*.yml\" \"*.{md,json}\" \"config/**/*.md\" \"config/**/*.yml\"",
|
"format": "prettier --write \"src/**/*.js\" \"scripts/**/*.js\" \"test/**/*.js\" \".github/**/*.yml\" \"*.{md,json}\" \"config/**/*.md\" \"config/**/*.yml\"",
|
||||||
"format:check": "prettier --check \"src/**/*.js\" \"scripts/**/*.js\" \"test/**/*.js\" \".github/**/*.yml\" \"*.{md,json}\" \"config/**/*.md\" \"config/**/*.yml\"",
|
"format:check": "prettier --check \"src/**/*.js\" \"scripts/**/*.js\" \"test/**/*.js\" \".github/**/*.yml\" \"*.{md,json}\" \"config/**/*.md\" \"config/**/*.yml\"",
|
||||||
|
"format:check:changed": "node ./scripts/format-check-changed.js",
|
||||||
"check": "npm run lint && npm test && npm run build"
|
"check": "npm run lint && npm test && npm run build"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@@ -29,18 +30,14 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"js-yaml": "^4.1.1",
|
"js-yaml": "^4.1.1",
|
||||||
"handlebars": "^4.7.8",
|
"handlebars": "^4.7.8",
|
||||||
"ansi-regex": "^6.0.1",
|
|
||||||
"ansi-styles": "^6.2.1",
|
|
||||||
"supports-color": "^9.4.0",
|
|
||||||
"has-flag": "^5.0.1",
|
|
||||||
"color-convert": "^2.0.1",
|
|
||||||
"color-name": "^2.0.0",
|
|
||||||
"mime-db": "^1.52.0",
|
|
||||||
"rss-parser": "^3.13.0"
|
"rss-parser": "^3.13.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"esbuild": "^0.20.2",
|
"esbuild": "^0.27.2",
|
||||||
"prettier": "^3.4.2",
|
"prettier": "^3.4.2",
|
||||||
"serve": "^14.2.5"
|
"serve": "^14.2.5"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"brace-expansion": "1.1.12"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
131
scripts/format-check-changed.js
Normal file
131
scripts/format-check-changed.js
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
const fs = require('node:fs');
|
||||||
|
const path = require('node:path');
|
||||||
|
const { execFileSync } = require('node:child_process');
|
||||||
|
|
||||||
|
function runGit(args, cwd) {
|
||||||
|
return execFileSync('git', args, { cwd, encoding: 'utf8' }).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
function tryReadGithubEvent(eventPath) {
|
||||||
|
if (!eventPath) return null;
|
||||||
|
try {
|
||||||
|
const raw = fs.readFileSync(eventPath, 'utf8');
|
||||||
|
return JSON.parse(raw);
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isAllZerosSha(value) {
|
||||||
|
return typeof value === 'string' && /^0{40}$/.test(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDiffRangeFromGithubEvent(event) {
|
||||||
|
if (!event || typeof event !== 'object') return null;
|
||||||
|
|
||||||
|
if (event.pull_request && event.pull_request.base && event.pull_request.head) {
|
||||||
|
const base = event.pull_request.base.sha;
|
||||||
|
const head = event.pull_request.head.sha;
|
||||||
|
if (base && head) return { base, head };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.before && (event.after || event.head_commit)) {
|
||||||
|
const base = event.before;
|
||||||
|
const head = event.after || (event.head_commit && event.head_commit.id);
|
||||||
|
if (base && head && !isAllZerosSha(base)) return { base, head };
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function collectChangedFiles(repoRoot, range) {
|
||||||
|
if (!range) return [];
|
||||||
|
const output = runGit(
|
||||||
|
['diff', '--name-only', '--diff-filter=ACMR', `${range.base}..${range.head}`],
|
||||||
|
repoRoot
|
||||||
|
);
|
||||||
|
return output
|
||||||
|
? output
|
||||||
|
.split('\n')
|
||||||
|
.map((line) => line.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
: [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function collectWorkingTreeChangedFiles(repoRoot) {
|
||||||
|
const files = new Set();
|
||||||
|
const unstaged = runGit(['diff', '--name-only', '--diff-filter=ACMR', 'HEAD'], repoRoot);
|
||||||
|
const staged = runGit(['diff', '--cached', '--name-only', '--diff-filter=ACMR'], repoRoot);
|
||||||
|
|
||||||
|
[unstaged, staged].forEach((block) => {
|
||||||
|
if (!block) return;
|
||||||
|
block
|
||||||
|
.split('\n')
|
||||||
|
.map((line) => line.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
.forEach((filePath) => files.add(filePath));
|
||||||
|
});
|
||||||
|
|
||||||
|
return Array.from(files).sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldCheckFile(filePath) {
|
||||||
|
const normalized = filePath.split(path.sep).join('/');
|
||||||
|
|
||||||
|
if (normalized === 'package-lock.json') return false;
|
||||||
|
|
||||||
|
// 这两个文件历史上未统一为 Prettier 风格;避免为了启用检查产生巨量格式化 diff
|
||||||
|
if (normalized === 'src/generator.js' || normalized === 'src/script.js') return false;
|
||||||
|
|
||||||
|
// 与现有 npm scripts 的检查范围对齐:不检查 docs/ 与 templates/
|
||||||
|
const allowedRoots = ['src/', 'scripts/', 'test/', '.github/', 'config/'];
|
||||||
|
const isRootFile = !normalized.includes('/');
|
||||||
|
const hasAllowedRoot = allowedRoots.some((prefix) => normalized.startsWith(prefix));
|
||||||
|
|
||||||
|
const isAllowedPath =
|
||||||
|
hasAllowedRoot || (isRootFile && (normalized.endsWith('.md') || normalized.endsWith('.json')));
|
||||||
|
|
||||||
|
if (!isAllowedPath) return false;
|
||||||
|
|
||||||
|
const ext = path.extname(normalized).toLowerCase();
|
||||||
|
return ['.js', '.json', '.md', '.yml', '.yaml'].includes(ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolvePrettierBin(repoRoot) {
|
||||||
|
const base = path.join(repoRoot, 'node_modules', '.bin', 'prettier');
|
||||||
|
if (fs.existsSync(base)) return base;
|
||||||
|
if (fs.existsSync(`${base}.cmd`)) return `${base}.cmd`;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
const repoRoot = path.resolve(__dirname, '..');
|
||||||
|
|
||||||
|
const event = tryReadGithubEvent(process.env.GITHUB_EVENT_PATH);
|
||||||
|
const range = getDiffRangeFromGithubEvent(event);
|
||||||
|
|
||||||
|
const candidateFiles = range
|
||||||
|
? collectChangedFiles(repoRoot, range)
|
||||||
|
: collectWorkingTreeChangedFiles(repoRoot);
|
||||||
|
|
||||||
|
const filesToCheck = candidateFiles.filter(shouldCheckFile);
|
||||||
|
|
||||||
|
if (filesToCheck.length === 0) {
|
||||||
|
console.log('格式检查:未发现需要检查的文件,跳过。');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const prettierBin = resolvePrettierBin(repoRoot);
|
||||||
|
if (!prettierBin) {
|
||||||
|
console.error('格式检查失败:未找到 prettier,可先运行 npm ci / npm install。');
|
||||||
|
process.exitCode = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`格式检查:共 ${filesToCheck.length} 个文件`);
|
||||||
|
filesToCheck.forEach((filePath) => console.log(`- ${filePath}`));
|
||||||
|
|
||||||
|
execFileSync(prettierBin, ['--check', ...filesToCheck], { cwd: repoRoot, stdio: 'inherit' });
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
67
scripts/lint.js
Normal file
67
scripts/lint.js
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
const fs = require('node:fs');
|
||||||
|
const path = require('node:path');
|
||||||
|
const { execFileSync } = require('node:child_process');
|
||||||
|
|
||||||
|
function collectJsFiles(rootDir) {
|
||||||
|
const files = [];
|
||||||
|
|
||||||
|
const walk = (currentDir) => {
|
||||||
|
let entries;
|
||||||
|
try {
|
||||||
|
entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
entries.forEach((entry) => {
|
||||||
|
const fullPath = path.join(currentDir, entry.name);
|
||||||
|
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
if (entry.name === 'node_modules' || entry.name === 'dist') return;
|
||||||
|
walk(fullPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.isFile() && entry.name.endsWith('.js')) {
|
||||||
|
files.push(fullPath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
walk(rootDir);
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
const projectRoot = path.resolve(__dirname, '..');
|
||||||
|
const targetDirs = ['src', 'scripts', 'test'].map((dir) => path.join(projectRoot, dir));
|
||||||
|
|
||||||
|
const jsFiles = targetDirs.flatMap((dir) => collectJsFiles(dir)).sort();
|
||||||
|
|
||||||
|
if (jsFiles.length === 0) {
|
||||||
|
console.log('未发现需要检查的 .js 文件,跳过。');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let hasError = false;
|
||||||
|
jsFiles.forEach((filePath) => {
|
||||||
|
const relativePath = path.relative(projectRoot, filePath);
|
||||||
|
try {
|
||||||
|
execFileSync(process.execPath, ['--check', filePath], { stdio: 'inherit' });
|
||||||
|
} catch (error) {
|
||||||
|
hasError = true;
|
||||||
|
console.error(`\n语法检查失败:${relativePath}`);
|
||||||
|
if (error && error.status) {
|
||||||
|
console.error(`退出码:${error.status}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (hasError) {
|
||||||
|
process.exitCode = 1;
|
||||||
|
} else {
|
||||||
|
console.log(`语法检查通过:${jsFiles.length} 个文件`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
@@ -413,6 +413,46 @@ function getSubmenuForNavItem(navItem, config) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function makeCategorySlugBase(name) {
|
||||||
|
const raw = typeof name === 'string' ? name : String(name ?? '');
|
||||||
|
const trimmed = raw.trim();
|
||||||
|
if (!trimmed) return 'category';
|
||||||
|
|
||||||
|
// 规则:尽量可读、跨平台稳定;保留字母/数字/下划线/短横线,其它字符替换为短横线
|
||||||
|
// 注意:分类名允许中文等非 ASCII 字符,Node 18+ 支持 Unicode 属性类
|
||||||
|
const normalized = trimmed
|
||||||
|
.replace(/\s+/g, '-')
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/[^\p{L}\p{N}_-]+/gu, '-')
|
||||||
|
.replace(/-+/g, '-')
|
||||||
|
.replace(/^-+|-+$/g, '');
|
||||||
|
|
||||||
|
return normalized || 'category';
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeUniqueSlug(base, usedSlugs) {
|
||||||
|
const current = usedSlugs.get(base) || 0;
|
||||||
|
const next = current + 1;
|
||||||
|
usedSlugs.set(base, next);
|
||||||
|
return next === 1 ? base : `${base}-${next}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function assignCategorySlugs(categories, usedSlugs) {
|
||||||
|
if (!Array.isArray(categories)) return;
|
||||||
|
|
||||||
|
categories.forEach(category => {
|
||||||
|
if (!category || typeof category !== 'object') return;
|
||||||
|
|
||||||
|
const base = makeCategorySlugBase(category.name);
|
||||||
|
const uniqueSlug = makeUniqueSlug(base, usedSlugs);
|
||||||
|
category.slug = uniqueSlug;
|
||||||
|
|
||||||
|
if (Array.isArray(category.subcategories)) {
|
||||||
|
assignCategorySlugs(category.subcategories, usedSlugs);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将 JSON 字符串安全嵌入到 <script> 中,避免出现 `</script>` 结束标签导致脚本块被提前终止。
|
* 将 JSON 字符串安全嵌入到 <script> 中,避免出现 `</script>` 结束标签导致脚本块被提前终止。
|
||||||
* 说明:返回值仍是合法 JSON,JSON.parse 后数据不变。
|
* 说明:返回值仍是合法 JSON,JSON.parse 后数据不变。
|
||||||
@@ -825,6 +865,16 @@ function prepareRenderData(config) {
|
|||||||
// 首页(默认页)规则:navigation 顺序第一项即首页
|
// 首页(默认页)规则:navigation 顺序第一项即首页
|
||||||
renderData.homePageId = renderData.navigation && renderData.navigation[0] ? renderData.navigation[0].id : null;
|
renderData.homePageId = renderData.navigation && renderData.navigation[0] ? renderData.navigation[0].id : null;
|
||||||
|
|
||||||
|
// 为每个页面的分类生成稳定锚点 slug(解决重名/空格/特殊字符导致的 hash 冲突)
|
||||||
|
if (Array.isArray(renderData.navigation)) {
|
||||||
|
renderData.navigation.forEach(navItem => {
|
||||||
|
const pageConfig = renderData[navItem.id];
|
||||||
|
if (pageConfig && Array.isArray(pageConfig.categories)) {
|
||||||
|
assignCategorySlugs(pageConfig.categories, new Map());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 添加序列化的配置数据,用于浏览器扩展(确保包含 homePageId 等处理结果)
|
// 添加序列化的配置数据,用于浏览器扩展(确保包含 homePageId 等处理结果)
|
||||||
renderData.configJSON = makeJsonSafeForHtmlScript(
|
renderData.configJSON = makeJsonSafeForHtmlScript(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
@@ -1382,6 +1432,11 @@ function renderPage(pageId, config) {
|
|||||||
if (config.profile.subtitle !== undefined) data.subtitle = config.profile.subtitle;
|
if (config.profile.subtitle !== undefined) data.subtitle = config.profile.subtitle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 分类锚点:为当前页面分类生成稳定 slug(用于 id/hash,避免重名/特殊字符冲突)
|
||||||
|
if (Array.isArray(data.categories) && data.categories.length > 0) {
|
||||||
|
assignCategorySlugs(data.categories, new Map());
|
||||||
|
}
|
||||||
|
|
||||||
if (config[pageId] && config[pageId].template) {
|
if (config[pageId] && config[pageId].template) {
|
||||||
console.log(`页面 ${pageId} 使用指定模板: ${templateName}`);
|
console.log(`页面 ${pageId} 使用指定模板: ${templateName}`);
|
||||||
}
|
}
|
||||||
|
|||||||
145
src/script.js
145
src/script.js
@@ -153,30 +153,42 @@ window.MeNav = {
|
|||||||
return menavConfigCacheValue;
|
return menavConfigCacheValue;
|
||||||
},
|
},
|
||||||
|
|
||||||
// 获取元素的唯一标识符
|
// 获取元素的唯一标识符
|
||||||
_getElementId: function(element) {
|
_getElementId: function(element) {
|
||||||
const type = element.getAttribute('data-type');
|
const type = element.getAttribute('data-type');
|
||||||
if (type === 'nav-item') {
|
if (type === 'nav-item') {
|
||||||
return element.getAttribute('data-id');
|
return element.getAttribute('data-id');
|
||||||
} else if (type === 'social-link') {
|
} else if (type === 'social-link') {
|
||||||
return element.getAttribute('data-url');
|
return element.getAttribute('data-url');
|
||||||
} else {
|
} else {
|
||||||
return element.getAttribute('data-name');
|
// 优先使用 data-id(例如分类 slug),回退 data-name(兼容旧扩展/旧页面)
|
||||||
}
|
return element.getAttribute('data-id') || element.getAttribute('data-name');
|
||||||
},
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// 根据类型和ID查找元素
|
// 根据类型和ID查找元素
|
||||||
_findElement: function(type, id) {
|
_findElement: function(type, id) {
|
||||||
let selector;
|
let selector;
|
||||||
if (type === 'nav-item') {
|
if (type === 'nav-item') {
|
||||||
selector = `[data-type="${type}"][data-id="${id}"]`;
|
selector = `[data-type="${type}"][data-id="${id}"]`;
|
||||||
} else if (type === 'social-link') {
|
} else if (type === 'social-link') {
|
||||||
selector = `[data-type="${type}"][data-url="${id}"]`;
|
selector = `[data-type="${type}"][data-url="${id}"]`;
|
||||||
} else {
|
} else if (type === 'site') {
|
||||||
selector = `[data-type="${type}"][data-name="${id}"]`;
|
// 站点:优先用 data-url(更稳定),回退 data-id/data-name
|
||||||
}
|
return (
|
||||||
return document.querySelector(selector);
|
document.querySelector(`[data-type="${type}"][data-url="${id}"]`) ||
|
||||||
},
|
document.querySelector(`[data-type="${type}"][data-id="${id}"]`) ||
|
||||||
|
document.querySelector(`[data-type="${type}"][data-name="${id}"]`)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// 其他:优先 data-id(例如分类 slug),回退 data-name(兼容旧扩展/旧页面)
|
||||||
|
return (
|
||||||
|
document.querySelector(`[data-type="${type}"][data-id="${id}"]`) ||
|
||||||
|
document.querySelector(`[data-type="${type}"][data-name="${id}"]`)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return document.querySelector(selector);
|
||||||
|
},
|
||||||
|
|
||||||
// 更新DOM元素
|
// 更新DOM元素
|
||||||
updateElement: function(type, id, newData) {
|
updateElement: function(type, id, newData) {
|
||||||
@@ -1929,19 +1941,33 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 子菜单项点击效果
|
// 子菜单项点击效果
|
||||||
submenuItems.forEach(item => {
|
submenuItems.forEach(item => {
|
||||||
item.addEventListener('click', (e) => {
|
item.addEventListener('click', (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
// 获取页面ID和分类名称
|
// 获取页面ID和分类名称
|
||||||
const pageId = item.getAttribute('data-page');
|
const pageId = item.getAttribute('data-page');
|
||||||
const categoryName = item.getAttribute('data-category');
|
const categoryName = item.getAttribute('data-category');
|
||||||
|
const categoryId = item.getAttribute('data-category-id');
|
||||||
|
|
||||||
if (pageId) {
|
const escapeSelector = value => {
|
||||||
// 清除所有子菜单项的激活状态
|
if (value === null || value === undefined) return '';
|
||||||
submenuItems.forEach(subItem => {
|
const text = String(value);
|
||||||
subItem.classList.remove('active');
|
if (window.CSS && typeof window.CSS.escape === 'function') return window.CSS.escape(text);
|
||||||
|
// 回退:尽量避免打断选择器(不追求完全覆盖所有边界字符)
|
||||||
|
return text.replace(/[^a-zA-Z0-9_\u00A0-\uFFFF-]/g, '\\$&');
|
||||||
|
};
|
||||||
|
|
||||||
|
const escapeAttrValue = value => {
|
||||||
|
if (value === null || value === undefined) return '';
|
||||||
|
return String(value).replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
||||||
|
};
|
||||||
|
|
||||||
|
if (pageId) {
|
||||||
|
// 清除所有子菜单项的激活状态
|
||||||
|
submenuItems.forEach(subItem => {
|
||||||
|
subItem.classList.remove('active');
|
||||||
});
|
});
|
||||||
|
|
||||||
// 激活当前子菜单项
|
// 激活当前子菜单项
|
||||||
@@ -1955,20 +1981,45 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
// 显示对应页面
|
// 显示对应页面
|
||||||
showPage(pageId);
|
showPage(pageId);
|
||||||
|
|
||||||
// 等待页面切换完成后滚动到对应分类
|
// 等待页面切换完成后滚动到对应分类
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// 查找目标分类元素
|
// 查找目标分类元素
|
||||||
const targetPage = document.getElementById(pageId);
|
const targetPage = document.getElementById(pageId);
|
||||||
if (targetPage) {
|
if (targetPage) {
|
||||||
const targetCategory = Array.from(targetPage.querySelectorAll('.category h2')).find(
|
let targetCategory = null;
|
||||||
heading => heading.textContent.trim().includes(categoryName)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (targetCategory) {
|
// 优先使用 slug/data-id 精准定位(解决重复命名始终命中第一个的问题)
|
||||||
// 优化的滚动实现:滚动到使目标分类位于视口1/4处(更靠近顶部位置)
|
if (categoryId) {
|
||||||
try {
|
const escapedId = escapeSelector(categoryId);
|
||||||
// 直接获取所需元素和属性,减少重复查询
|
targetCategory =
|
||||||
const contentElement = document.querySelector('.content');
|
targetPage.querySelector(`#${escapedId}`) ||
|
||||||
|
targetPage.querySelector(
|
||||||
|
`[data-type="category"][data-id="${escapeAttrValue(categoryId)}"]`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 回退:旧逻辑按文本包含匹配(兼容旧页面/旧数据)
|
||||||
|
if (!targetCategory && categoryName) {
|
||||||
|
targetCategory = Array.from(targetPage.querySelectorAll('.category h2')).find(
|
||||||
|
heading => heading.textContent.trim().includes(categoryName)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetCategory) {
|
||||||
|
// 由于对子菜单 click 做了 preventDefault,这里手动同步 hash(不触发浏览器默认跳转)
|
||||||
|
const nextHash = categoryId || categoryName;
|
||||||
|
if (nextHash) {
|
||||||
|
try {
|
||||||
|
history.replaceState(null, '', `#${nextHash}`);
|
||||||
|
} catch (error) {
|
||||||
|
// 忽略 history API 失败,避免影响滚动体验
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 优化的滚动实现:滚动到使目标分类位于视口1/4处(更靠近顶部位置)
|
||||||
|
try {
|
||||||
|
// 直接获取所需元素和属性,减少重复查询
|
||||||
|
const contentElement = document.querySelector('.content');
|
||||||
|
|
||||||
if (contentElement && contentElement.scrollHeight > contentElement.clientHeight) {
|
if (contentElement && contentElement.scrollHeight > contentElement.clientHeight) {
|
||||||
// 获取目标元素相对于内容区域的位置
|
// 获取目标元素相对于内容区域的位置
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<section class="category {{#if level}}category-level-{{level}}{{else}}category-level-1{{/if}}"
|
<section class="category {{#if level}}category-level-{{level}}{{else}}category-level-1{{/if}}"
|
||||||
id="{{name}}"
|
id="{{#if slug}}{{slug}}{{else}}{{name}}{{/if}}"
|
||||||
data-type="category"
|
data-type="category"
|
||||||
|
data-id="{{#if slug}}{{slug}}{{else}}{{name}}{{/if}}"
|
||||||
data-name="{{name}}"
|
data-name="{{name}}"
|
||||||
data-icon="{{icon}}"
|
data-icon="{{icon}}"
|
||||||
data-level="{{#if level}}{{level}}{{else}}1{{/if}}"
|
data-level="{{#if level}}{{level}}{{else}}1{{/if}}"
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
{{#if submenu}}
|
{{#if submenu}}
|
||||||
<div class="submenu">
|
<div class="submenu">
|
||||||
{{#each submenu}}
|
{{#each submenu}}
|
||||||
<a href="#{{name}}" class="submenu-item" data-page="{{../id}}" data-category="{{name}}">
|
<a href="#{{#if slug}}{{slug}}{{else}}{{name}}{{/if}}" class="submenu-item" data-page="{{../id}}" data-category="{{name}}" data-category-id="{{#if slug}}{{slug}}{{else}}{{name}}{{/if}}">
|
||||||
<i class="{{icon}}"></i>
|
<i class="{{icon}}"></i>
|
||||||
<span>{{name}}</span>
|
<span>{{name}}</span>
|
||||||
</a>
|
</a>
|
||||||
@@ -20,4 +20,4 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
48
test/category-slug-dedup.node-test.js
Normal file
48
test/category-slug-dedup.node-test.js
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
const test = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const path = require('node:path');
|
||||||
|
|
||||||
|
const { loadHandlebarsTemplates, generateAllPagesHTML } = require('../src/generator.js');
|
||||||
|
|
||||||
|
function withRepoRoot(fn) {
|
||||||
|
const originalCwd = process.cwd();
|
||||||
|
process.chdir(path.join(__dirname, '..'));
|
||||||
|
try {
|
||||||
|
return fn();
|
||||||
|
} finally {
|
||||||
|
process.chdir(originalCwd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test('P1-2:分类 slug 应稳定且可去重', () => {
|
||||||
|
withRepoRoot(() => {
|
||||||
|
loadHandlebarsTemplates();
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
site: { title: 'Test Site', description: '', author: '', favicon: '', logo_text: 'Test' },
|
||||||
|
profile: { title: 'PROFILE_TITLE', subtitle: 'PROFILE_SUBTITLE' },
|
||||||
|
social: [],
|
||||||
|
navigation: [{ id: 'home', name: '首页', icon: 'fas fa-home' }],
|
||||||
|
home: {
|
||||||
|
title: 'HOME',
|
||||||
|
subtitle: 'HOME_SUB',
|
||||||
|
template: 'page',
|
||||||
|
categories: [
|
||||||
|
{ name: '重复 分类', icon: 'fas fa-tag', sites: [] },
|
||||||
|
{ name: '重复 分类', icon: 'fas fa-tag', sites: [] },
|
||||||
|
{ name: '含 空格/特殊#字符', icon: 'fas fa-tag', sites: [] },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const pages = generateAllPagesHTML(config);
|
||||||
|
assert.ok(typeof pages.home === 'string' && pages.home.length > 0);
|
||||||
|
|
||||||
|
assert.ok(pages.home.includes('id="重复-分类"'), '首个重复分类应生成稳定 slug');
|
||||||
|
assert.ok(pages.home.includes('id="重复-分类-2"'), '重复分类应通过后缀去重');
|
||||||
|
assert.ok(pages.home.includes('id="含-空格-特殊-字符"'), '空格/特殊字符应被规范化为可用 slug');
|
||||||
|
|
||||||
|
assert.ok(pages.home.includes('data-id="重复-分类"'));
|
||||||
|
assert.ok(pages.home.includes('data-id="重复-分类-2"'));
|
||||||
|
});
|
||||||
|
});
|
||||||
43
test/navigation-submenu-uses-category-slug.node-test.js
Normal file
43
test/navigation-submenu-uses-category-slug.node-test.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
const test = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const path = require('node:path');
|
||||||
|
|
||||||
|
const { loadHandlebarsTemplates, generateHTML } = require('../src/generator.js');
|
||||||
|
|
||||||
|
function withRepoRoot(fn) {
|
||||||
|
const originalCwd = process.cwd();
|
||||||
|
process.chdir(path.join(__dirname, '..'));
|
||||||
|
try {
|
||||||
|
return fn();
|
||||||
|
} finally {
|
||||||
|
process.chdir(originalCwd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test('P1-2:子菜单锚点应使用分类 slug(href + data-category-id)', () => {
|
||||||
|
withRepoRoot(() => {
|
||||||
|
loadHandlebarsTemplates();
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
site: { title: 'Test Site', description: '', author: '', favicon: '', logo_text: 'Test' },
|
||||||
|
profile: { title: 'PROFILE_TITLE', subtitle: 'PROFILE_SUBTITLE' },
|
||||||
|
social: [],
|
||||||
|
navigation: [{ id: 'home', name: '首页', icon: 'fas fa-home' }],
|
||||||
|
home: {
|
||||||
|
title: 'HOME',
|
||||||
|
subtitle: 'HOME_SUB',
|
||||||
|
template: 'page',
|
||||||
|
categories: [
|
||||||
|
{ name: '重复 分类', icon: 'fas fa-tag', sites: [] },
|
||||||
|
{ name: '重复 分类', icon: 'fas fa-tag', sites: [] },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const html = generateHTML(config);
|
||||||
|
|
||||||
|
assert.ok(html.includes('class="submenu-item"'), '应输出子菜单项');
|
||||||
|
assert.ok(html.includes('href="#重复-分类"'), '子菜单 href 应指向 slug');
|
||||||
|
assert.ok(html.includes('data-category-id="重复-分类"'), '子菜单应携带 data-category-id');
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user