diff --git a/package.json b/package.json index 9d6b287..812de8f 100644 --- a/package.json +++ b/package.json @@ -47,9 +47,6 @@ "web-vitals": "^5.1.0" }, "devDependencies": { - "diff": "^8.0.2", - "@shikijs/transformers": "^3.15.0", - "sass-embedded": "^1.93.3", "@nuxt/devtools": "^3.0.0", "@nuxt/devtools-ui-kit": "^3.0.0", "@nuxt/eslint": "^1.9.0", @@ -57,11 +54,15 @@ "@nuxt/module-builder": "^1.0.0", "@nuxt/schema": "^4.1.2", "@nuxt/test-utils": "^3.19.2", + "@shikijs/transformers": "^3.15.0", "@types/node": "^24.0.0", "changelogen": "^0.6.0", + "diff": "^8.0.2", "eslint": "^9.36.0", + "happy-dom": "^20.0.10", "pkg-pr-new": "0.0.60", "rimraf": "^6.0.1", + "sass-embedded": "^1.93.3", "vitest": "^4.0.0" }, "packageManager": "pnpm@10.21.0+sha512.da3337267e400fdd3d479a6c68079ac6db01d8ca4f67572083e722775a796788a7a9956613749e000fac20d424b594f7a791a5f4e2e13581c5ef947f26968a40" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 874591e..8e0eaa6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -59,7 +59,7 @@ importers: version: 4.2.1 '@nuxt/test-utils': specifier: ^3.19.2 - version: 3.20.1(magicast@0.5.1)(typescript@5.9.3)(vitest@4.0.10(@types/node@24.10.1)(jiti@2.6.1)(sass-embedded@1.93.3)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1)) + version: 3.20.1(@vue/test-utils@2.4.6)(happy-dom@20.0.10)(magicast@0.5.1)(typescript@5.9.3)(vitest@4.0.10(@types/node@24.10.1)(happy-dom@20.0.10)(jiti@2.6.1)(sass-embedded@1.93.3)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1)) '@shikijs/transformers': specifier: ^3.15.0 version: 3.15.0 @@ -75,6 +75,9 @@ importers: eslint: specifier: ^9.36.0 version: 9.39.1(jiti@2.6.1) + happy-dom: + specifier: ^20.0.10 + version: 20.0.10 pkg-pr-new: specifier: 0.0.60 version: 0.0.60 @@ -86,7 +89,7 @@ importers: version: 1.93.3 vitest: specifier: ^4.0.0 - version: 4.0.10(@types/node@24.10.1)(jiti@2.6.1)(sass-embedded@1.93.3)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1) + version: 4.0.10(@types/node@24.10.1)(happy-dom@20.0.10)(jiti@2.6.1)(sass-embedded@1.93.3)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1) packages: @@ -832,6 +835,9 @@ packages: '@octokit/types@13.10.0': resolution: {integrity: sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==} + '@one-ini/wasm@0.1.1': + resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} + '@oxc-minify/binding-android-arm64@0.95.0': resolution: {integrity: sha512-ck0NakTt3oBWTMQjxKf5ZW1GzCs0y1kETzJdh8h8NAWTutlMfeWiuUxCgG4FMF4XiTnCdLq/dFAKFcdbiwcoqg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1475,6 +1481,9 @@ packages: '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + '@types/node@20.19.25': + resolution: {integrity: sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==} + '@types/node@24.10.1': resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==} @@ -1491,6 +1500,9 @@ packages: '@types/web-bluetooth@0.0.21': resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} + '@types/whatwg-mimetype@3.0.2': + resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==} + '@typescript-eslint/eslint-plugin@8.47.0': resolution: {integrity: sha512-fe0rz9WJQ5t2iaLfdbDc9T80GJy0AeO453q8C3YCilnGozvOyCG5t+EZtg7j7D88+c3FipfP/x+wzGnh1xp8ZA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1888,6 +1900,9 @@ packages: '@vue/shared@3.5.24': resolution: {integrity: sha512-9cwHL2EsJBdi8NY22pngYYWzkTDhld6fAD6jlaeloNGciNSJL6bLpbxVgXl96X00Jtc6YWQv96YA/0sxex/k1A==} + '@vue/test-utils@2.4.6': + resolution: {integrity: sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==} + '@vueuse/core@14.0.0': resolution: {integrity: sha512-d6tKRWkZE8IQElX2aHBxXOMD478fHIYV+Dzm2y9Ag122ICBpNKtGICiXKOhWU3L1kKdttDD9dCMS4bGP3jhCTQ==} peerDependencies: @@ -2000,6 +2015,10 @@ packages: '@xtuc/long@4.2.2': resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + abbrev@2.0.0: + resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + abbrev@3.0.1: resolution: {integrity: sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==} engines: {node: ^18.17.0 || >=20.5.0} @@ -2314,6 +2333,10 @@ packages: comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} + commander@11.1.0: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} @@ -2344,6 +2367,9 @@ packages: confbox@0.2.2: resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} + config-chain@1.1.13: + resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} + consola@3.4.2: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} @@ -2571,6 +2597,11 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + editorconfig@1.0.4: + resolution: {integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==} + engines: {node: '>=14'} + hasBin: true + ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -3004,6 +3035,10 @@ packages: h3@1.15.4: resolution: {integrity: sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==} + happy-dom@20.0.10: + resolution: {integrity: sha512-6umCCHcjQrhP5oXhrHQQvLB0bwb1UzHAHdsXy+FjtKoYjUhmNZsQL8NivwM1vDvNEChJabVrUYxUnp/ZdYmy2g==} + engines: {node: '>=20.0.0'} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -3085,6 +3120,9 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + ini@4.1.1: resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -3229,6 +3267,15 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + js-beautify@1.15.4: + resolution: {integrity: sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==} + engines: {node: '>=14'} + hasBin: true + + js-cookie@3.0.5: + resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} + engines: {node: '>=14'} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -3459,6 +3506,10 @@ packages: resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} engines: {node: '>=10'} + minimatch@9.0.1: + resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==} + engines: {node: '>=16 || 14 >=14.17'} + minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} @@ -3578,6 +3629,11 @@ packages: node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + nopt@7.2.1: + resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + hasBin: true + nopt@8.1.0: resolution: {integrity: sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==} engines: {node: ^18.17.0 || >=20.5.0} @@ -4006,6 +4062,9 @@ packages: property-information@7.1.0: resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + proto-list@1.2.4: + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + protocols@2.0.2: resolution: {integrity: sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==} @@ -4691,6 +4750,9 @@ packages: unctx@2.4.1: resolution: {integrity: sha512-AbaYw0Nm4mK4qjhns67C+kgxR2YWiwlDBPzxrN8h8C6VtAdCgditAY5Dezu3IJy4XVqAnbrXt9oQJvsn3fyozg==} + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} @@ -5039,6 +5101,9 @@ packages: vue-bundle-renderer@2.2.0: resolution: {integrity: sha512-sz/0WEdYH1KfaOm0XaBmRZOWgYTEvUDt6yPYaUzl4E52qzgWLlknaPPTTZmp6benaPTlQAI/hN1x3tAzZygycg==} + vue-component-type-helpers@2.2.12: + resolution: {integrity: sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw==} + vue-devtools-stub@0.1.0: resolution: {integrity: sha512-RutnB7X8c5hjq39NceArgXg28WZtZpGc3+J16ljMiYnFhKvd8hITxSWQSQ5bvldxMDU6gG5mkxl1MTQLXckVSQ==} @@ -5099,6 +5164,10 @@ packages: webpack-cli: optional: true + whatwg-mimetype@3.0.0: + resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} + engines: {node: '>=12'} + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -6312,7 +6381,7 @@ snapshots: transitivePeerDependencies: - magicast - '@nuxt/test-utils@3.20.1(magicast@0.5.1)(typescript@5.9.3)(vitest@4.0.10(@types/node@24.10.1)(jiti@2.6.1)(sass-embedded@1.93.3)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1))': + '@nuxt/test-utils@3.20.1(@vue/test-utils@2.4.6)(happy-dom@20.0.10)(magicast@0.5.1)(typescript@5.9.3)(vitest@4.0.10(@types/node@24.10.1)(happy-dom@20.0.10)(jiti@2.6.1)(sass-embedded@1.93.3)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1))': dependencies: '@nuxt/kit': 4.2.1(magicast@0.5.1) c12: 3.3.2(magicast@0.5.1) @@ -6336,10 +6405,12 @@ snapshots: tinyexec: 1.0.2 ufo: 1.6.1 unplugin: 2.3.10 - vitest-environment-nuxt: 1.0.1(magicast@0.5.1)(typescript@5.9.3)(vitest@4.0.10(@types/node@24.10.1)(jiti@2.6.1)(sass-embedded@1.93.3)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1)) + vitest-environment-nuxt: 1.0.1(@vue/test-utils@2.4.6)(happy-dom@20.0.10)(magicast@0.5.1)(typescript@5.9.3)(vitest@4.0.10(@types/node@24.10.1)(happy-dom@20.0.10)(jiti@2.6.1)(sass-embedded@1.93.3)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1)) vue: 3.5.24(typescript@5.9.3) optionalDependencies: - vitest: 4.0.10(@types/node@24.10.1)(jiti@2.6.1)(sass-embedded@1.93.3)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1) + '@vue/test-utils': 2.4.6 + happy-dom: 20.0.10 + vitest: 4.0.10(@types/node@24.10.1)(happy-dom@20.0.10)(jiti@2.6.1)(sass-embedded@1.93.3)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1) transitivePeerDependencies: - magicast - typescript @@ -6475,6 +6546,9 @@ snapshots: dependencies: '@octokit/openapi-types': 24.2.0 + '@one-ini/wasm@0.1.1': + optional: true + '@oxc-minify/binding-android-arm64@0.95.0': optional: true @@ -6931,6 +7005,10 @@ snapshots: dependencies: '@types/unist': 3.0.3 + '@types/node@20.19.25': + dependencies: + undici-types: 6.21.0 + '@types/node@24.10.1': dependencies: undici-types: 7.16.0 @@ -6945,6 +7023,8 @@ snapshots: '@types/web-bluetooth@0.0.21': {} + '@types/whatwg-mimetype@3.0.2': {} + '@typescript-eslint/eslint-plugin@8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -7532,6 +7612,12 @@ snapshots: '@vue/shared@3.5.24': {} + '@vue/test-utils@2.4.6': + dependencies: + js-beautify: 1.15.4 + vue-component-type-helpers: 2.2.12 + optional: true + '@vueuse/core@14.0.0(vue@3.5.24(typescript@5.9.3))': dependencies: '@types/web-bluetooth': 0.0.21 @@ -7646,6 +7732,9 @@ snapshots: '@xtuc/long@4.2.2': {} + abbrev@2.0.0: + optional: true + abbrev@3.0.1: {} abort-controller@3.0.0: @@ -7975,6 +8064,9 @@ snapshots: comma-separated-tokens@2.0.3: {} + commander@10.0.1: + optional: true + commander@11.1.0: {} commander@2.20.3: {} @@ -7999,6 +8091,12 @@ snapshots: confbox@0.2.2: {} + config-chain@1.1.13: + dependencies: + ini: 1.3.8 + proto-list: 1.2.4 + optional: true + consola@3.4.2: {} convert-gitmoji@0.1.5: {} @@ -8191,6 +8289,14 @@ snapshots: eastasianwidth@0.2.0: {} + editorconfig@1.0.4: + dependencies: + '@one-ini/wasm': 0.1.1 + commander: 10.0.1 + minimatch: 9.0.1 + semver: 7.7.3 + optional: true + ee-first@1.1.1: {} electron-to-chromium@1.5.255: {} @@ -8705,6 +8811,12 @@ snapshots: ufo: 1.6.1 uncrypto: 0.1.3 + happy-dom@20.0.10: + dependencies: + '@types/node': 20.19.25 + '@types/whatwg-mimetype': 3.0.2 + whatwg-mimetype: 3.0.0 + has-flag@4.0.0: {} hasown@2.0.2: @@ -8787,6 +8899,9 @@ snapshots: inherits@2.0.4: {} + ini@1.3.8: + optional: true + ini@4.1.1: {} ioredis@5.8.2: @@ -8906,6 +9021,18 @@ snapshots: jiti@2.6.1: {} + js-beautify@1.15.4: + dependencies: + config-chain: 1.1.13 + editorconfig: 1.0.4 + glob: 10.5.0 + js-cookie: 3.0.5 + nopt: 7.2.1 + optional: true + + js-cookie@3.0.5: + optional: true + js-tokens@4.0.0: {} js-tokens@9.0.1: {} @@ -9132,6 +9259,11 @@ snapshots: dependencies: brace-expansion: 2.0.2 + minimatch@9.0.1: + dependencies: + brace-expansion: 2.0.2 + optional: true + minimatch@9.0.5: dependencies: brace-expansion: 2.0.2 @@ -9312,6 +9444,11 @@ snapshots: node-releases@2.0.27: {} + nopt@7.2.1: + dependencies: + abbrev: 2.0.0 + optional: true + nopt@8.1.0: dependencies: abbrev: 3.0.1 @@ -9873,6 +10010,9 @@ snapshots: property-information@7.1.0: {} + proto-list@1.2.4: + optional: true + protocols@2.0.2: {} punycode@2.3.1: {} @@ -10561,6 +10701,8 @@ snapshots: magic-string: 0.30.21 unplugin: 2.3.10 + undici-types@6.21.0: {} + undici-types@7.16.0: {} undici@5.29.0: @@ -10899,9 +11041,9 @@ snapshots: terser: 5.44.1 yaml: 2.8.1 - vitest-environment-nuxt@1.0.1(magicast@0.5.1)(typescript@5.9.3)(vitest@4.0.10(@types/node@24.10.1)(jiti@2.6.1)(sass-embedded@1.93.3)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1)): + vitest-environment-nuxt@1.0.1(@vue/test-utils@2.4.6)(happy-dom@20.0.10)(magicast@0.5.1)(typescript@5.9.3)(vitest@4.0.10(@types/node@24.10.1)(happy-dom@20.0.10)(jiti@2.6.1)(sass-embedded@1.93.3)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1)): dependencies: - '@nuxt/test-utils': 3.20.1(magicast@0.5.1)(typescript@5.9.3)(vitest@4.0.10(@types/node@24.10.1)(jiti@2.6.1)(sass-embedded@1.93.3)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1)) + '@nuxt/test-utils': 3.20.1(@vue/test-utils@2.4.6)(happy-dom@20.0.10)(magicast@0.5.1)(typescript@5.9.3)(vitest@4.0.10(@types/node@24.10.1)(happy-dom@20.0.10)(jiti@2.6.1)(sass-embedded@1.93.3)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1)) transitivePeerDependencies: - '@cucumber/cucumber' - '@jest/globals' @@ -10916,7 +11058,7 @@ snapshots: - typescript - vitest - vitest@4.0.10(@types/node@24.10.1)(jiti@2.6.1)(sass-embedded@1.93.3)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1): + vitest@4.0.10(@types/node@24.10.1)(happy-dom@20.0.10)(jiti@2.6.1)(sass-embedded@1.93.3)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1): dependencies: '@vitest/expect': 4.0.10 '@vitest/mocker': 4.0.10(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(sass-embedded@1.93.3)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1)) @@ -10940,6 +11082,7 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.10.1 + happy-dom: 20.0.10 transitivePeerDependencies: - jiti - less @@ -10960,6 +11103,9 @@ snapshots: dependencies: ufo: 1.6.1 + vue-component-type-helpers@2.2.12: + optional: true + vue-devtools-stub@0.1.0: {} vue-eslint-parser@10.2.0(eslint@9.39.1(jiti@2.6.1)): @@ -11043,6 +11189,8 @@ snapshots: - esbuild - uglify-js + whatwg-mimetype@3.0.0: {} + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 diff --git a/src/runtime/third-party-scripts/plugin.client.ts b/src/runtime/third-party-scripts/plugin.client.ts index 3714250..2fc3d0e 100644 --- a/src/runtime/third-party-scripts/plugin.client.ts +++ b/src/runtime/third-party-scripts/plugin.client.ts @@ -1,5 +1,31 @@ import { defineNuxtPlugin, ref, useNuxtApp } from '#imports' +const EXTENSIONS_SCHEMES_RE = /^(chrome-extension|moz-extension|safari-extension|ms-browser-extension):/ + +function isExtensionScript(src: string) { + try { + const url = new URL(src, window.location.origin) + return EXTENSIONS_SCHEMES_RE.test(url.protocol) + } + catch { + return false + } +} + +function isSameOriginScript(src: string) { + try { + const url = new URL(src, window.location.origin) + return url.origin === window.location.origin + } + catch { + return false + } +} + +function isIgnoredScript(src: string) { + return isSameOriginScript(src) || isExtensionScript(src) +} + export default defineNuxtPlugin({ name: 'nuxt-hints:third-party-scripts', setup() { @@ -27,7 +53,7 @@ export default defineNuxtPlugin({ nuxtApp.hooks.hookOnce('app:mounted', () => { let hasThirdPartyScript = false for (const script of document.scripts) { - if (script.src && !script.src.startsWith(window.location.origin)) { + if (script.src && !isIgnoredScript(script.src)) { hasThirdPartyScript = true onScriptAdded(script) } @@ -42,7 +68,7 @@ export default defineNuxtPlugin({ for (const mutation of mutations) { if (mutation.type === 'childList') { for (const node of mutation.addedNodes) { - if (isScript(node) && node.src && !node.src.startsWith(window.location.origin)) { + if (isScript(node) && node.src && !isIgnoredScript(node.src)) { onScriptAdded(node) } } @@ -56,9 +82,6 @@ export default defineNuxtPlugin({ }) function onScriptAdded(script: HTMLScriptElement) { - if (script.src.startsWith('chrome-extension')) { - return - } if (!script.crossOrigin) { console.warn(`[@nuxt/hints]: Third-party script "${script.src}" is missing crossorigin attribute. Consider adding crossorigin="anonymous" for better security and error reporting.`) } diff --git a/test/basic.test.ts b/test/basic.test.ts deleted file mode 100644 index 7c08b56..0000000 --- a/test/basic.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { fileURLToPath } from 'node:url' -import { describe, it, expect } from 'vitest' -import { setup, $fetch } from '@nuxt/test-utils' - -describe('ssr', async () => { - await setup({ - rootDir: fileURLToPath(new URL('./fixtures/basic', import.meta.url)), - }) - - it('renders the index page', async () => { - // Get response to a server-rendered page with `$fetch`. - const html = await $fetch('/') - expect(html).toContain('