From e28d0705ad35389c29843322b376eb80759a353e Mon Sep 17 00:00:00 2001 From: "C.Nelhomme" <64921289+D3ller@users.noreply.github.com> Date: Thu, 15 Oct 2026 23:31:55 +0200 Subject: [PATCH 1/7] test: add vitest non-regression test suite --- package.json | 6 +- pnpm-lock.yaml | 595 +++++++++++++++++++++++++++++++++++++++++ src/index.ts | 144 ++-------- src/seo.ts | 91 +++++++ tests/content.test.ts | 34 +++ tests/heading.test.ts | 23 ++ tests/image.test.ts | 17 ++ tests/link.test.ts | 17 ++ tests/utils/analyze.ts | 11 + tsconfig.json | 2 +- vitest.config.ts | 8 + 11 files changed, 827 insertions(+), 121 deletions(-) create mode 100644 src/seo.ts create mode 100644 tests/content.test.ts create mode 100644 tests/heading.test.ts create mode 100644 tests/image.test.ts create mode 100644 tests/link.test.ts create mode 100644 tests/utils/analyze.ts create mode 100644 vitest.config.ts diff --git a/package.json b/package.json index 698ba64..127e643 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,8 @@ "typecheck": "tsc --noEmit", "play": "tsx playground/text.ts", "prepublishOnly": "pnpm run typecheck && pnpm run build", - "test": "echo \"Error: no test specified\" && exit 1" + "test": "vitest run", + "test:watch": "vitest" }, "peerDependencies": { "comark": ">=0.4.0" @@ -48,6 +49,7 @@ "comark": "^0.7.0", "tsdown": "^0.23.0", "tsx": "^4.23.13", - "typescript": "^7.0.2" + "typescript": "^7.0.2", + "vitest": "^5.0.5" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b2013b6..5454cbe 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,9 @@ importers: typescript: specifier: ^7.0.2 version: 7.0.2 + vitest: + specifier: ^5.0.5 + version: 5.0.5(@types/node@26.5.1)(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(tsx@4.23.13)) packages: @@ -182,48 +185,104 @@ packages: cpu: [x64] os: [win32] + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.6.0': + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@oxc-project/types@0.149.0': resolution: {integrity: sha512-Efcc+iF0j3Bf67YjEqIqWXbX5XddXoK/Mw4K1/JuXwRCZ8N16VR7iT23nlCc9XrveFVh/E5Rqs2StT0V8v9LdA==} + '@oxc-project/types@0.154.0': + resolution: {integrity: sha512-KYOUGQFlLWR+s4QMV2Q9ko38TZm7EdO87Qm7rvZLqk/webse/cDjtyxKhg/47l0byCbs/k46LT8qc4PKjAikzA==} + '@quansync/fs@1.0.0': resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==} + '@rolldown/binding-android-arm-eabi@1.2.14': + resolution: {integrity: sha512-aWR+XKH9+rW7m5fWq/5360J3mHycrx/o6xZM2DQFdJnTMdyP7/WzxPjhtLbVWdKo2y612/4U1bWqb3HQhiF7vg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + '@rolldown/binding-android-arm-eabi@1.2.8': resolution: {integrity: sha512-tN5aztYkKCte4i5SIrrz5yK/HMjEuCqCSCJa418jOV8tZ1cBY3YF2otxB1ktPxzsLA1BeTqwapK0bfjxNvHJVw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] + '@rolldown/binding-android-arm64@1.2.14': + resolution: {integrity: sha512-QiVxHofl6A8lQU7WAtOUY4QMVZXohxwz7WJJoeh8NBEUyKfIkMRKhYyq8az/1RypNiIXzNTtiS6KwHz0erxYRQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + '@rolldown/binding-android-arm64@1.2.8': resolution: {integrity: sha512-dIYTWl9XprMUiQFoc55KUyk/oS8SKYH3zFl0LTR7RT0Xj4hgSVyuJcroH8JUu8RcpF8fTB6E0aOwCkZoYPcDSQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] + '@rolldown/binding-darwin-arm64@1.2.14': + resolution: {integrity: sha512-lTQOzHuBIooh3jIr5XINQkjPGEuGy+Dsy0meXDr6Sjty0b99kYgGh4uBC/8mJX1T0kC8d6S0aPP1Y+bHkh6aBw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + '@rolldown/binding-darwin-arm64@1.2.8': resolution: {integrity: sha512-PCSDQGXD2IyTEFrcgPyBM8jJuGmrbCMuoIOXdbEGVemruKACXoLQJrb+A45Z0L5t1RQkdfJprAYPkikbh7dzdA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] + '@rolldown/binding-darwin-x64@1.2.14': + resolution: {integrity: sha512-hyMKEGatjmBYCs/Q4sbIcL/GqpFEqsX3wc+HYVQ/85A4rxc1o7rPm4DUI4GV4k/h0ITddwFSGpqQunI14GXjTA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + '@rolldown/binding-darwin-x64@1.2.8': resolution: {integrity: sha512-Uk7lRsGhPFHVX/sAUC6D5H9Ol30dFHd6iquokll2th3LpdJ3F5CzQB+7DHn0Ri2mG+U7k2zXiPHDrwZenXhwSA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] + '@rolldown/binding-freebsd-x64@1.2.14': + resolution: {integrity: sha512-u371GbXoVXrEgP20PwzoGNOdAOqAMhzo19JzzY+V4YmmnC+DTOoqdbMu+O+54emM59Mik/UdrtWgcuEDKWRPKA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + '@rolldown/binding-freebsd-x64@1.2.8': resolution: {integrity: sha512-DjszaTEVogPqA5bYzsEeqDCQxbcp2fexQwKcRspYji2yzR68fCf+e4fx6kBSRDwX5/brZaHw/hWS9+A/+/w9sQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] + '@rolldown/binding-linux-arm-gnueabihf@1.2.14': + resolution: {integrity: sha512-BqwKsdZQf6EqVWr8fv2MrDYzAvOZ7+NYFSJESRGs87fkseEhs0TU9TXgRJTkZoRRkxTizyEg1LKUXfU3/78uqg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + '@rolldown/binding-linux-arm-gnueabihf@1.2.8': resolution: {integrity: sha512-zmwa7FTmdzB6aaEEuuls18H6Ap5JmJPSoPTuXixeJZV6tG40SyLkApQtz1g8ptZtiEKqj9OM0oNLPh1AgvE31Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] + '@rolldown/binding-linux-arm64-gnu@1.2.14': + resolution: {integrity: sha512-SD9kY8M009x/7s57Z1dgUVlP5+uYBgKQK0Tkr1WIWngrtUJmRCW1RJFMY7QDla2khXhmg2i5Io7MUjcmZNZ/KQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-arm64-gnu@1.2.8': resolution: {integrity: sha512-KdYQDPHwJVnbFwdTGMgxsI9SqblBlz6STGM+w1We/d5B8OWWidYH0MwkU/uA1wM5fIpO2MkOVxXrNzzuZhw9ew==} engines: {node: ^20.19.0 || >=22.12.0} @@ -231,6 +290,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-arm64-musl@1.2.14': + resolution: {integrity: sha512-BJ2CL19M6uuWesMgnqJzgxoI+N+eV7b0A9O9vLV42y+gitC41fNa8KElau1tHVzuLWX5GzEuxMPhAO0tQXQMkg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + '@rolldown/binding-linux-arm64-musl@1.2.8': resolution: {integrity: sha512-jFJTifHnNPY+yzOoNZQfSIysrVyXzEQPhPnOUjmD1bcQGHH6s7c8cViKWar8YplQImE5N9JRqMCLrM2CdxOrZA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -238,6 +304,13 @@ packages: os: [linux] libc: [musl] + '@rolldown/binding-linux-ppc64-gnu@1.2.14': + resolution: {integrity: sha512-4+Kl8daPV8NDHaD7mfCcc1pRM+Qg7ab8DyMm5FG5WoZgv4h2i3KFN1CybYBNbQqmuYm7ftJLvmMI1eHYJ22S/Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-ppc64-gnu@1.2.8': resolution: {integrity: sha512-FhiOziBDWPBjbcmRzfLyIJnaP7AVMFXT7YCXPjXxj7wKU3vx24RjrCNN/zjvVa+N2vVoHJwCoUBvsrN/DG3zIA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -245,6 +318,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-s390x-gnu@1.2.14': + resolution: {integrity: sha512-V/h8ePq1fKDrmtFMz6xcCN3DKvuvMRrwwD1q0PkBeeo4DpK64biaKvqWGVxqCeYKqeRk7gE7/iKPxLCn08O97A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-s390x-gnu@1.2.8': resolution: {integrity: sha512-WnHfADMzOV2Y55wlx1hzzQnar/wDt/VdvWSD99r18Mz9ylNieIGOkRx3UV21h7m/eJvjySYJkO26VvGNFkwsIQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -252,6 +332,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-x64-gnu@1.2.14': + resolution: {integrity: sha512-WxalXzgrLVpKC93xfpaJ3gCXUWzeCr+FRCbDVD2mUAy4L6Vo3lNVz0epUEUpxPWJkLNYUwM4OSIikv36OJ9mLg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-x64-gnu@1.2.8': resolution: {integrity: sha512-H9tRr5ibfXFVLxbPOseVewewFpl28zcEdjRDt2FTUZU7odxP0gEv1ki4/kGmcGOh78oRwZuuQllGLZ9zTJp84g==} engines: {node: ^20.19.0 || >=22.12.0} @@ -259,6 +346,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-x64-musl@1.2.14': + resolution: {integrity: sha512-3G3tnAmTpdk9jO3GQtyHXqeFD2SlecfTws/Y3M2mmj9nMBwwuLT4kur8sZKeu7ENUHSpVO3cIsm5A52LEWWwlg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + '@rolldown/binding-linux-x64-musl@1.2.8': resolution: {integrity: sha512-UefiqfM3D6IVNlZ8tSGs9+Ejjud2T+oxO0IHADU45Y+lyEjD2dVFyZHbkfX0LUb5Zugo/oIv1eCO/KVYhgYJYA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -266,18 +360,36 @@ packages: os: [linux] libc: [musl] + '@rolldown/binding-openharmony-arm64@1.2.14': + resolution: {integrity: sha512-qyr5XiNGxm2ytx17vvtcJ9nXn6v1gENETi503bJx3OGwZ1tSonj7BosxbMa/xeAfSl5iS9X6KjEWYXLu6v1L7Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + '@rolldown/binding-openharmony-arm64@1.2.8': resolution: {integrity: sha512-637Ke4kWSy6rp9cxQ9gMOXlxPgIw/c1beASV4M//3+9I4uwBVOOl74G+e3zyU3u19U7RkRl/HuewixZ/Z6+Rjg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] + '@rolldown/binding-win32-arm64-msvc@1.2.14': + resolution: {integrity: sha512-oA4o5o0S2yB199YyYXDzKUv1Z56Rc+mgOjwm7Z/vJ9Z8igiDPYvoOuDyo6g7AK/ZaF09nPhDKVnGBcYHO11GXA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + '@rolldown/binding-win32-arm64-msvc@1.2.8': resolution: {integrity: sha512-xWBkPOF1Q9k/Gv1nQXnVdLxKu74jXppuOM4Z3mnypVUJJJwLsMl7hNJGRAUJoG8A5MgOI1ACKM+wBFxSJzKy4A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] + '@rolldown/binding-win32-x64-msvc@1.2.14': + resolution: {integrity: sha512-9mE94bf2GZUaR/fUSXCMpBoWkctu421Mi0ORpm4zqfbkjKep7RxzPFa5etcGs5h+2KApoWBOA/hAJa/7saGgEQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + '@rolldown/binding-win32-x64-msvc@1.2.8': resolution: {integrity: sha512-uz2ZvfgXbxqNwijjjbxrnvALwpyODDcgc1T1N8N3rf/DXKQmaFwmB4LX4yyjggpwN2obdQLb2rgirX5ffCWYng==} engines: {node: ^20.19.0 || >=22.12.0} @@ -287,6 +399,15 @@ packages: '@rolldown/pluginutils@1.0.1': resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + '@types/linkify-it@5.0.0': resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} @@ -416,10 +537,25 @@ packages: cpu: [x64] os: [win32] + '@vitest/mocker@5.0.5': + resolution: {integrity: sha512-xLL3lkDegJZw+MGoGaCCsFayDZthGgpAtr3Vziyfc4p7xH89K7KRPcRBBh/kEYm0Aqkt5DtTmkYpBtRV/FrHZg==} + peerDependencies: + msw: ^2.4.9 || ^3.0.0 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/spy@5.0.5': + resolution: {integrity: sha512-lwJRExuH417257Q5wv9QYugN9IMJkoxcrKrYxGPQkBzl7wlNpTUxD/5yNX4ESKVUIShKPgkGchYPFMWOOk0wzw==} + '@yuku-codegen/binding-android-arm64@0.9.5': resolution: {integrity: sha512-jrOY5WM+AaAqkv51fHP1x28ifto4WgcZVzodLUyMU1jMWn5Sq+VciRdk/n8E0Ey5w4p4cWWE+m5GfXWOYh7Kzw==} cpu: [arm64] os: [android] + deprecated: yuku-codegen is pure JavaScript since 0.14 '@yuku-codegen/binding-darwin-arm64@0.9.5': resolution: {integrity: sha512-4O4lkCQIzPZGjiNB1GORSI6hBECbiiSBS/APZXPvNKYH+nhY4uuqv03LNXA+SET3hoBjvr95P5rIhY8KQaQUBA==} @@ -430,62 +566,73 @@ packages: resolution: {integrity: sha512-9EvoUO0SEhD6/d8VHdWuPerepPMSR1y84+UEgz8Un1Ope14Oe7xMvePpEQLTLovoIFZ8Zg3iZ8z8E11pZMqC3g==} cpu: [x64] os: [darwin] + deprecated: yuku-codegen is pure JavaScript since 0.14 '@yuku-codegen/binding-freebsd-x64@0.9.5': resolution: {integrity: sha512-HqT78WwgHTmp8lwujoUa9CrIortX4DdpuiVC18ZPSGvuuJf4ylpIEI6QrQEM78Zwz3muhAWAOXZ5irdiYY+AyA==} cpu: [x64] os: [freebsd] + deprecated: yuku-codegen is pure JavaScript since 0.14 '@yuku-codegen/binding-linux-arm-gnu@0.9.5': resolution: {integrity: sha512-QJXwIW6Ms3QIawbcBIedmrmXnfdpuAOjZJ/eAABq5XTzWvSxZ7lutu9W5yIHahlaTaFnBo7ikrVMD1szLTpPUw==} cpu: [arm] os: [linux] libc: [glibc] + deprecated: yuku-codegen is pure JavaScript since 0.14 '@yuku-codegen/binding-linux-arm-musl@0.9.5': resolution: {integrity: sha512-eHbFy3IHGb+IYarrYwAo0yWSEQV3eAmEn6VrsKA6I1Wy1YPJxWqSJlV69JhqsHtJuJlljUIF3ex0y46yaKIu9w==} cpu: [arm] os: [linux] libc: [musl] + deprecated: yuku-codegen is pure JavaScript since 0.14 '@yuku-codegen/binding-linux-arm64-gnu@0.9.5': resolution: {integrity: sha512-ByoJMbySTaDhjAXSu8q6Lh7HKg3YoesXpcT72aYk0Aiw4PCznmY4ybpLTq0RCvp0RIPhFm/6yECFiGBwyCC1nw==} cpu: [arm64] os: [linux] libc: [glibc] + deprecated: yuku-codegen is pure JavaScript since 0.14 '@yuku-codegen/binding-linux-arm64-musl@0.9.5': resolution: {integrity: sha512-gD9vfXIoBw1toSxhO9rgmSu/FEfy3PMznJAxVjIuH8DrWEiDKXmJO0pJKfj1Ltbe/TmtWVZR+TjISqeSIGQzMg==} cpu: [arm64] os: [linux] libc: [musl] + deprecated: yuku-codegen is pure JavaScript since 0.14 '@yuku-codegen/binding-linux-x64-gnu@0.9.5': resolution: {integrity: sha512-BARvdnvqMGjOr5Iel2JH+9H5vAIE0R6H0Z2fsT02xrvmI/1ZXNB8lkuX+ZGevPhZb3zJ9WeC/R8JZstrsUOK5g==} cpu: [x64] os: [linux] libc: [glibc] + deprecated: yuku-codegen is pure JavaScript since 0.14 '@yuku-codegen/binding-linux-x64-musl@0.9.5': resolution: {integrity: sha512-x8flcevS1fbb7ESrmpOY/pON4eInSaE/7Ktjqx2udOE2W33BNSZmJuwpyUgo54AoHNqrcaM7szqydyJn5fNvew==} cpu: [x64] os: [linux] libc: [musl] + deprecated: yuku-codegen is pure JavaScript since 0.14 '@yuku-codegen/binding-win32-arm64@0.9.5': resolution: {integrity: sha512-KOL/rBatWqH4ZpCNoF8ZtSNdOJbAxBJLmk/VeRciepGROPTbPum1A9t67GpFgOU7qrkUWlPJdJ+KHKbvbmOt+w==} cpu: [arm64] os: [win32] + deprecated: yuku-codegen is pure JavaScript since 0.14 '@yuku-codegen/binding-win32-x64@0.9.5': resolution: {integrity: sha512-FxENahEjWSan59Syh/us/Kf4wNq8qrJLFJ3R2N4Oiwtb6yNdz/rWLNTIoNSssnsp7IoWJdUP6o/Z8ppg7lXMcg==} cpu: [x64] os: [win32] + deprecated: yuku-codegen is pure JavaScript since 0.14 '@yuku-parser/binding-android-arm64@0.9.5': resolution: {integrity: sha512-A2JCFCSHfnficqYEw4Iujpx7XrkMM3UfFcgJFmYpZSo9zM4nyhmdIIE0FogSduuU60lhM0/UcfuUBXIVNBMlGQ==} cpu: [arm64] os: [android] + deprecated: yuku-parser runs on yuku-core since 0.14 '@yuku-parser/binding-darwin-arm64@0.9.5': resolution: {integrity: sha512-3PiyU+Eare4YuKaQ22N98/yAiROPY5o/NQJHraICzDvk4pgS+m+bgLKOvkGBRn33OnV95Vdv1Mn38b+MQHpULQ==} @@ -496,57 +643,67 @@ packages: resolution: {integrity: sha512-blFMAFI7AInI83XaiOF8cIeiRM46Nz9EfpZtZPRLbKxSA9aAr5v8aHYpmfN6NoyXxAv/10pwS4gsAuc1W6fy5Q==} cpu: [x64] os: [darwin] + deprecated: yuku-parser runs on yuku-core since 0.14 '@yuku-parser/binding-freebsd-x64@0.9.5': resolution: {integrity: sha512-TsNuL4qsZdO0tHp5GW43Y5fHeLPpPHA675wdcPNTcdq2ZO5AvsQWFFoiDg8CH4oBktfsQ9tdvKhjLnLYwKvp4g==} cpu: [x64] os: [freebsd] + deprecated: yuku-parser runs on yuku-core since 0.14 '@yuku-parser/binding-linux-arm-gnu@0.9.5': resolution: {integrity: sha512-b0afYK5gHeV8RdmOcqAlgM8ONsye4cax4DMnIBaoJyPMd1UTGvTbpkqQcPVdhmHlcfcGVGMV1laeVovlr/dscw==} cpu: [arm] os: [linux] libc: [glibc] + deprecated: yuku-parser runs on yuku-core since 0.14 '@yuku-parser/binding-linux-arm-musl@0.9.5': resolution: {integrity: sha512-fD3lKzl+r6j6n8DwiMY53qnh5DLqD8KJjCp+NbVud54Nnh3Q9Wprqss3YzyMHP3NSJk663Wlg1E1X5qOuFVFig==} cpu: [arm] os: [linux] libc: [musl] + deprecated: yuku-parser runs on yuku-core since 0.14 '@yuku-parser/binding-linux-arm64-gnu@0.9.5': resolution: {integrity: sha512-aRU/aCphV1MWCl/lvI6NX8LgucHQ68Fx+vz7NBb/5MEr2EuzCxiPOQqeFcMdWh+2AED/p0AvAREch0c+cSnlhA==} cpu: [arm64] os: [linux] libc: [glibc] + deprecated: yuku-parser runs on yuku-core since 0.14 '@yuku-parser/binding-linux-arm64-musl@0.9.5': resolution: {integrity: sha512-5+Guro0l8H473YXlEjVNBRLN/IbPbJdnQh1zo0OLt49xxnON+XMJRRaEyTOTfkn9QSRg0+BhEKGR4W9Gu2uZJQ==} cpu: [arm64] os: [linux] libc: [musl] + deprecated: yuku-parser runs on yuku-core since 0.14 '@yuku-parser/binding-linux-x64-gnu@0.9.5': resolution: {integrity: sha512-pwwSyV9q+GlvzSXlsMZBMlgk22L5bud714/vqZCdeUTivzeUVltQzUaf3IQXOGXdpc59JYTeuMCtbGquaAUoCA==} cpu: [x64] os: [linux] libc: [glibc] + deprecated: yuku-parser runs on yuku-core since 0.14 '@yuku-parser/binding-linux-x64-musl@0.9.5': resolution: {integrity: sha512-z18j6JN3lBHH8vzN7gG1M8fI0nlgItSfnC9PfbmUbt97iHViKfw2iA2G9fGwRMe5LyPRZBrejIlapbygPbpdaw==} cpu: [x64] os: [linux] libc: [musl] + deprecated: yuku-parser runs on yuku-core since 0.14 '@yuku-parser/binding-win32-arm64@0.9.5': resolution: {integrity: sha512-s6Gwttb1dQvtPX6Bgkw+UPC9IO3UBDXc6Zezog8MMgvu3UfJBBB9TQqKBX/2quu0Eyh+lLSAyNlIyyecaagUPg==} cpu: [arm64] os: [win32] + deprecated: yuku-parser runs on yuku-core since 0.14 '@yuku-parser/binding-win32-x64@0.9.5': resolution: {integrity: sha512-FrERt9YWatY3bJfSUdi4YWY+6iQcyo3MzCC821BxlWM5TFZEHijnpz/bknR79VHlXY/9CvXz8ZlaAGPsTtN3nw==} cpu: [x64] os: [win32] + deprecated: yuku-parser runs on yuku-core since 0.14 '@yuku-toolchain/types@0.9.5': resolution: {integrity: sha512-KiuLNNgX9uNealaWAR+G3/cMXnRk9x4TY2EkYe/KIag+UPdwiA0RRf1hr1WAxzTP8KGzCTkqUdLPvqh32sEO3w==} @@ -554,10 +711,18 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + cac@7.0.0: resolution: {integrity: sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==} engines: {node: '>=20.19.0'} + chai@6.3.0: + resolution: {integrity: sha512-XWAtwJ6OHO+tj0EKCs0Y2UamnyOxseZWltU4x2U2wh8g4AigdjwvtUjvLP2tqkA/avxHEtzxNaqGq/YGNwckKg==} + engines: {node: '>=18'} + comark@0.7.0: resolution: {integrity: sha512-680hLtUOBcvBEJCD+iCU20jk5TrIJlIcE6X4npdC4x7LBhCvmiYJgByozR2fKav6DYw7AYoXsJVae65kXV6Qhw==} peerDependencies: @@ -578,6 +743,10 @@ packages: defu@6.1.7: resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + dom-serializer@3.1.1: resolution: {integrity: sha512-4MEa38/QexBob6gFNwu+EGdWvhJ1OKuNwdYY3Y3NyeWDQfnGeDYQUDfIRzWu5B5gsv03so2Uxd28YC6zrsx3Lw==} engines: {node: '>=20.19.0'} @@ -615,11 +784,21 @@ packages: resolution: {integrity: sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA==} engines: {node: '>=20.19.0'} + es-module-lexer@2.3.2: + resolution: {integrity: sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==} + esbuild@0.28.2: resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} engines: {node: '>=18'} hasBin: true + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + expect-type@1.4.0: + resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} + engines: {node: '>=12.0.0'} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -653,23 +832,116 @@ packages: resolution: {integrity: sha512-m+aqu+LwO1O6sIopafj8HUVl5aawITwZQe/yHpMCKjaWBaA/d07B/QdMb3529REftiU+RMMHL3Vlsw3hON7vWg==} hasBin: true + lightningcss-android-arm64@1.33.0: + resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.33.0: + resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.33.0: + resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.33.0: + resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.33.0: + resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.33.0: + resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.33.0: + resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.33.0: + resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.33.0: + resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.33.0: + resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.33.0: + resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.33.0: + resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} + engines: {node: '>= 12.0.0'} + linkify-it@5.0.2: resolution: {integrity: sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==} + magic-string@1.4.3: + resolution: {integrity: sha512-z12OxmaPGE0F4xlpGdjuAUckipLpQlTAuAmyGhNoD7ODpYUzvDfvtxUbjM/jwznyP178oju/KDdyi220wNJ0RQ==} + markdown-exit@1.1.0-beta.2: resolution: {integrity: sha512-8CzMGVlFZ4DEfnc8KU+4ycUW2SIOuiXqCHD7z51ecVEi/weyc0f2ylQbCm4KoKuVlTZSuMUMnWT0hTyquZ7anQ==} mdurl@2.1.0: resolution: {integrity: sha512-1+HBaOx0zi/dQWht8rNv9MYf9qqpqL/kxI0hXImU6Y547zM6Sni8BQibt7ifgMcYtQg41ao3Ivd6cnSM86inpg==} + nanoid@3.3.20: + resolution: {integrity: sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + obug@2.2.1: resolution: {integrity: sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==} engines: {node: '>=12.20.0'} + obug@3.0.0: + resolution: {integrity: sha512-5vvB5+W7ePv+p3uqxi+RcW1XAzLW0/hxt3/4X4Lc4qHudzOhmBiBwOY6DRob4WnanAEGvNcLjF+KNOufrUoEQw==} + engines: {node: '>=12.20.0'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + picomatch@4.0.7: resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} engines: {node: '>=12'} + postcss@8.5.30: + resolution: {integrity: sha512-zkd+e9S1AQHhmaBKye9zlFHWjOwVgqXl1q3ECYy8561K7qxR2cREf/STLskulBFd78k6AOFeA+ff1TtEzk9bAA==} + engines: {node: ^10 || ^12 || >=14} + punycode.js@2.3.1: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} @@ -699,11 +971,27 @@ packages: vue-tsc: optional: true + rolldown@1.2.14: + resolution: {integrity: sha512-eTBTTqMR6uHKLgcUqpJP8ntzDI6V4LYA8negAMBEI7gkgVvOdrx6VsvS2Ym+83KhOPdLCHWJu0w7UQFJZhHKNw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + rolldown@1.2.8: resolution: {integrity: sha512-Z67nTmhZe7anqnM/EjI392w5i/ANUinjip7QYsOyN37oayduxt3ksdX0hf5OOamkAd53BiIHfbfSzfUmzKFQqQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true + source-map-js@1.2.2: + resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==} + engines: {node: '>=0.10.0'} + + std-env@4.3.0: + resolution: {integrity: sha512-OtU/EgQ1kIm5KwqQpBC6ZEMXrZRui11w8zgfTWp8cdO9B8OaPsbA8bTHO2P+HNo1VlUTGMVBwPhydu6poeXiag==} + + tinybench@6.2.2: + resolution: {integrity: sha512-nIZ2N2dFpjBsg2hgitKu7mA+FvsIJuGJOwysRngmVRRmWgR/UyPjwJj8c/fT/dhm8EkHnF5EOogRf+0Z2qrimA==} + engines: {node: '>=20.0.0'} + tinyexec@1.3.1: resolution: {integrity: sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==} engines: {node: '>=18'} @@ -773,6 +1061,95 @@ packages: resolution: {integrity: sha512-sXMwN6DMHeouPfCxkxWkKAmxphWKEenHYY5H1nIBzU3PmDsmJp6kBXJdshjVdpMZuWCmL9SH7KFRx29AylpP6g==} engines: {node: '>=18.12.0'} + vite@8.3.4: + resolution: {integrity: sha512-IftLE8phJhdNRIGNEV4JCCvfNScoZQVfcXaN8TQropWGJtOHcu+iAB9pHcuGvmEb/kddw0LBe/jS8ztdC6xdiQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.7.1 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@5.0.5: + resolution: {integrity: sha512-cPODOMF8YnkiiYtDdHo6n4wWmBrOBBbOIYH2d33M4l3CdNn72h+qMmO6uXffUN6A5AZFXNND/d+krS9mgkXRfg==} + engines: {node: ^22.12.0 || ^24.0.0 || >=26.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 5.0.5 + '@vitest/browser-preview': 5.0.5 + '@vitest/browser-webdriverio': ^5.0.0-beta.5 || >=5.0.0 + '@vitest/coverage-istanbul': 5.0.5 + '@vitest/coverage-v8': 5.0.5 + '@vitest/ui': 5.0.5 + happy-dom: '*' + jsdom: '*' + vite: ^6.4.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + why-is-node-running@3.2.1: + resolution: {integrity: sha512-Tb2FUhB4vUsGQlfSquQLYkApkuPAFQXGFzxWKHHumVz2dK+X1RUm/HnID4+TfIGYJ1kTcwOaCk/buYCEJr6YjQ==} + engines: {node: '>=20.11'} + hasBin: true + yuku-ast@0.9.5: resolution: {integrity: sha512-Q8qW8WwQnN5Cm0ZZivdRIfv0sRLTjUq0YumXJkw8CYN1aCdICH9rk4C47/4n6kA5EqDtlj+F608twoTSV2MwdQ==} @@ -862,59 +1239,124 @@ snapshots: '@esbuild/win32-x64@0.28.2': optional: true + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.6.0': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.6.0 + '@oxc-project/types@0.149.0': {} + '@oxc-project/types@0.154.0': {} + '@quansync/fs@1.0.0': dependencies: quansync: 1.0.0 + '@rolldown/binding-android-arm-eabi@1.2.14': + optional: true + '@rolldown/binding-android-arm-eabi@1.2.8': optional: true + '@rolldown/binding-android-arm64@1.2.14': + optional: true + '@rolldown/binding-android-arm64@1.2.8': optional: true + '@rolldown/binding-darwin-arm64@1.2.14': + optional: true + '@rolldown/binding-darwin-arm64@1.2.8': optional: true + '@rolldown/binding-darwin-x64@1.2.14': + optional: true + '@rolldown/binding-darwin-x64@1.2.8': optional: true + '@rolldown/binding-freebsd-x64@1.2.14': + optional: true + '@rolldown/binding-freebsd-x64@1.2.8': optional: true + '@rolldown/binding-linux-arm-gnueabihf@1.2.14': + optional: true + '@rolldown/binding-linux-arm-gnueabihf@1.2.8': optional: true + '@rolldown/binding-linux-arm64-gnu@1.2.14': + optional: true + '@rolldown/binding-linux-arm64-gnu@1.2.8': optional: true + '@rolldown/binding-linux-arm64-musl@1.2.14': + optional: true + '@rolldown/binding-linux-arm64-musl@1.2.8': optional: true + '@rolldown/binding-linux-ppc64-gnu@1.2.14': + optional: true + '@rolldown/binding-linux-ppc64-gnu@1.2.8': optional: true + '@rolldown/binding-linux-s390x-gnu@1.2.14': + optional: true + '@rolldown/binding-linux-s390x-gnu@1.2.8': optional: true + '@rolldown/binding-linux-x64-gnu@1.2.14': + optional: true + '@rolldown/binding-linux-x64-gnu@1.2.8': optional: true + '@rolldown/binding-linux-x64-musl@1.2.14': + optional: true + '@rolldown/binding-linux-x64-musl@1.2.8': optional: true + '@rolldown/binding-openharmony-arm64@1.2.14': + optional: true + '@rolldown/binding-openharmony-arm64@1.2.8': optional: true + '@rolldown/binding-win32-arm64-msvc@1.2.14': + optional: true + '@rolldown/binding-win32-arm64-msvc@1.2.8': optional: true + '@rolldown/binding-win32-x64-msvc@1.2.14': + optional: true + '@rolldown/binding-win32-x64-msvc@1.2.8': optional: true '@rolldown/pluginutils@1.0.1': {} + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + + '@types/estree@1.0.9': {} + '@types/linkify-it@5.0.0': {} '@types/mdurl@2.0.0': {} @@ -983,6 +1425,17 @@ snapshots: '@typescript/typescript-win32-x64@7.0.2': optional: true + '@vitest/mocker@5.0.5(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(tsx@4.23.13))': + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + '@vitest/spy': 5.0.5 + estree-walker: 3.0.3 + magic-string: 1.4.3 + optionalDependencies: + vite: 8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(tsx@4.23.13) + + '@vitest/spy@5.0.5': {} + '@yuku-codegen/binding-android-arm64@0.9.5': optional: true @@ -1059,8 +1512,12 @@ snapshots: argparse@2.0.1: {} + assertion-error@2.0.1: {} + cac@7.0.0: {} + chai@6.3.0: {} + comark@0.7.0: dependencies: entities: 8.1.0 @@ -1070,6 +1527,8 @@ snapshots: defu@6.1.7: {} + detect-libc@2.1.2: {} + dom-serializer@3.1.1: dependencies: domelementtype: 3.0.0 @@ -1096,6 +1555,8 @@ snapshots: entities@8.1.0: {} + es-module-lexer@2.3.2: {} + esbuild@0.28.2: optionalDependencies: '@esbuild/aix-ppc64': 0.28.2 @@ -1125,6 +1586,12 @@ snapshots: '@esbuild/win32-ia32': 0.28.2 '@esbuild/win32-x64': 0.28.2 + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + + expect-type@1.4.0: {} + fdir@6.5.0(picomatch@4.0.7): optionalDependencies: picomatch: 4.0.7 @@ -1151,10 +1618,63 @@ snapshots: dependencies: argparse: 2.0.1 + lightningcss-android-arm64@1.33.0: + optional: true + + lightningcss-darwin-arm64@1.33.0: + optional: true + + lightningcss-darwin-x64@1.33.0: + optional: true + + lightningcss-freebsd-x64@1.33.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.33.0: + optional: true + + lightningcss-linux-arm64-gnu@1.33.0: + optional: true + + lightningcss-linux-arm64-musl@1.33.0: + optional: true + + lightningcss-linux-x64-gnu@1.33.0: + optional: true + + lightningcss-linux-x64-musl@1.33.0: + optional: true + + lightningcss-win32-arm64-msvc@1.33.0: + optional: true + + lightningcss-win32-x64-msvc@1.33.0: + optional: true + + lightningcss@1.33.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.33.0 + lightningcss-darwin-arm64: 1.33.0 + lightningcss-darwin-x64: 1.33.0 + lightningcss-freebsd-x64: 1.33.0 + lightningcss-linux-arm-gnueabihf: 1.33.0 + lightningcss-linux-arm64-gnu: 1.33.0 + lightningcss-linux-arm64-musl: 1.33.0 + lightningcss-linux-x64-gnu: 1.33.0 + lightningcss-linux-x64-musl: 1.33.0 + lightningcss-win32-arm64-msvc: 1.33.0 + lightningcss-win32-x64-msvc: 1.33.0 + linkify-it@5.0.2: dependencies: uc.micro: 2.1.0 + magic-string@1.4.3: + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + markdown-exit@1.1.0-beta.2: dependencies: '@types/linkify-it': 5.0.0 @@ -1167,10 +1687,22 @@ snapshots: mdurl@2.1.0: {} + nanoid@3.3.20: {} + obug@2.2.1: {} + obug@3.0.0: {} + + picocolors@1.1.1: {} + picomatch@4.0.7: {} + postcss@8.5.30: + dependencies: + nanoid: 3.3.20 + picocolors: 1.1.1 + source-map-js: 1.2.2 + punycode.js@2.3.1: {} quansync@1.0.0: {} @@ -1191,6 +1723,27 @@ snapshots: transitivePeerDependencies: - oxc-resolver + rolldown@1.2.14: + dependencies: + '@oxc-project/types': 0.154.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm-eabi': 1.2.14 + '@rolldown/binding-android-arm64': 1.2.14 + '@rolldown/binding-darwin-arm64': 1.2.14 + '@rolldown/binding-darwin-x64': 1.2.14 + '@rolldown/binding-freebsd-x64': 1.2.14 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.14 + '@rolldown/binding-linux-arm64-gnu': 1.2.14 + '@rolldown/binding-linux-arm64-musl': 1.2.14 + '@rolldown/binding-linux-ppc64-gnu': 1.2.14 + '@rolldown/binding-linux-s390x-gnu': 1.2.14 + '@rolldown/binding-linux-x64-gnu': 1.2.14 + '@rolldown/binding-linux-x64-musl': 1.2.14 + '@rolldown/binding-openharmony-arm64': 1.2.14 + '@rolldown/binding-win32-arm64-msvc': 1.2.14 + '@rolldown/binding-win32-x64-msvc': 1.2.14 + rolldown@1.2.8: dependencies: '@oxc-project/types': 0.149.0 @@ -1212,6 +1765,12 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.2.8 '@rolldown/binding-win32-x64-msvc': 1.2.8 + source-map-js@1.2.2: {} + + std-env@4.3.0: {} + + tinybench@6.2.2: {} + tinyexec@1.3.1: {} tinyglobby@0.2.17: @@ -1286,6 +1845,42 @@ snapshots: verkit@0.4.0: {} + vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(tsx@4.23.13): + dependencies: + lightningcss: 1.33.0 + picomatch: 4.0.7 + postcss: 8.5.30 + rolldown: 1.2.14 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 26.5.1 + esbuild: 0.28.2 + fsevents: 2.3.3 + tsx: 4.23.13 + + vitest@5.0.5(@types/node@26.5.1)(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(tsx@4.23.13)): + dependencies: + '@types/chai': 5.2.3 + '@vitest/mocker': 5.0.5(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(tsx@4.23.13)) + chai: 6.3.0 + es-module-lexer: 2.3.2 + expect-type: 1.4.0 + magic-string: 1.4.3 + obug: 3.0.0 + picomatch: 4.0.7 + std-env: 4.3.0 + tinybench: 6.2.2 + tinyexec: 1.3.1 + tinyglobby: 0.2.17 + vite: 8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(tsx@4.23.13) + why-is-node-running: 3.2.1 + optionalDependencies: + '@types/node': 26.5.1 + transitivePeerDependencies: + - msw + + why-is-node-running@3.2.1: {} + yuku-ast@0.9.5: dependencies: '@yuku-toolchain/types': 0.9.5 diff --git a/src/index.ts b/src/index.ts index 710a38c..c470942 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,125 +1,33 @@ -import { ComarkPluginFactory, Node } from 'comark' -import { defineComarkPlugin } from 'comark/parse' -import { - Analytics, - HeadingAnalytics, - LinksAnalytics, - ImagesAnalytics, - ContentAnalytics, - ComarkSeoMeta, - ComarkSeoOptions, - Issue, - RepeatedWord, +import type { ComarkPluginFactory } from "comark"; +import { defineComarkPlugin } from "comark/parse"; + +import { seo } from "./seo.js"; +import type { + Analytics, + ComarkSeoMeta, + ComarkSeoOptions, + ContentAnalytics, + HeadingAnalytics, + ImagesAnalytics, + Issue, + LinksAnalytics, + RepeatedWord, } from "./types.js"; -import type { ImageNode } from "./types.js"; -import { frenchStopWords, englishStopWords } from "./constants.js"; - -import { headingRule } from "./rules/heading.js"; -import { linkRule } from "./rules/link.js"; -import { imageRule } from "./rules/image.js"; -import { createIssue } from "./utils/issue.js"; -import { contentRule } from "./rules/content.js"; - -const headingType = new Set(['h1', 'h2', "h3", 'h4', 'h5', 'h6']); - -const browse = (node: Node, analytics: Analytics, previousHeading: { value: string }, stoppingWords: Set, wordCounts: Map) => { - - if (typeof node === "string") return; - - if (headingType.has(node[0]!)) { - headingRule(previousHeading, node, analytics) - } - if (node[0] === "a") { - linkRule(node, analytics); - } - if (node[0] === "img") { - imageRule(node as ImageNode, analytics); - } - - contentRule(analytics, node, stoppingWords, previousHeading, wordCounts, browse); -} - - -const seo = (TreeNode: Node[], options: ComarkSeoOptions = {}): Analytics => { - - const { - readingSpeed = 200 - } = options - - const analytics: Analytics = { - content: { - words: 0, - readingTime: 0, - repeatedWords: [] - }, - links: { - count: 0, - internal: 0, - external: 0, - special: { - anchor: 0, - emails: 0, - phone: 0 - }, - invalid: 0 - }, - images: { - count: 0, - missingAlt: 0 - }, - headings: { - h1Count: 0, - count: 0, - hierarchyValid: true - }, - issues: [] - } - - const wordCounts = new Map(); - let stoppingWords: Set = new Set(); - const previousHeading = {value: ""}; - const lang = options.language; - - if (lang) { - lang === "fra" ? stoppingWords = frenchStopWords : stoppingWords = englishStopWords - } - - TreeNode.forEach((event) => { - browse(event, analytics, previousHeading, stoppingWords, wordCounts); - }) - - if(analytics.headings.h1Count === 0) { - createIssue({reason: "missing-heading-one"}, analytics); - } - - if (analytics.headings.h1Count > 1) { - createIssue({reason: "multiple-h1", count: analytics.headings.h1Count}, analytics) - } - - analytics.content.readingTime = Math.max(1, Math.round(analytics.content.words / readingSpeed)); - analytics.content.repeatedWords = [...wordCounts] - .filter(([, count]) => count > 1) - .sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])) - .map(([word, count]) => ({word, count})) - - return analytics -} const plugin: ComarkPluginFactory = defineComarkPlugin((options = {}) => { + const { + enabled = true, + } = options; - const { - enabled = true, - } = options - - return { - name: 'seo', + return { + name: "seo", - post(state) { - if (!enabled) return; - state.tree.meta.seo = seo(state.tree.nodes, options) - } - } -}) + post(state) { + if (!enabled) return; + state.tree.meta.seo = seo(state.tree.nodes, options); + }, + }; +}); export default plugin; -export type { Analytics, Issue, HeadingAnalytics, ContentAnalytics, LinksAnalytics, ImagesAnalytics, RepeatedWord }; \ No newline at end of file +export type { Analytics, ContentAnalytics, HeadingAnalytics, ImagesAnalytics, Issue, LinksAnalytics, RepeatedWord }; diff --git a/src/seo.ts b/src/seo.ts new file mode 100644 index 0000000..2631d0a --- /dev/null +++ b/src/seo.ts @@ -0,0 +1,91 @@ +import type { Node } from "comark"; + +import { englishStopWords, frenchStopWords } from "./constants.js"; +import { contentRule } from "./rules/content.js"; +import { headingRule } from "./rules/heading.js"; +import { imageRule } from "./rules/image.js"; +import { linkRule } from "./rules/link.js"; +import type { Analytics, ComarkSeoOptions, ImageNode } from "./types.js"; +import { createIssue } from "./utils/issue.js"; + +const headingType = new Set(["h1", "h2", "h3", "h4", "h5", "h6"]); + +export const seo = (TreeNode: Node[], options: ComarkSeoOptions = {}): Analytics => { + const { + readingSpeed = 200, + } = options; + + const analytics: Analytics = { + content: { + words: 0, + readingTime: 1, + repeatedWords: [], + }, + links: { + count: 0, + internal: 0, + external: 0, + special: { + anchor: 0, + emails: 0, + phone: 0, + }, + invalid: 0, + }, + images: { + count: 0, + missingAlt: 0, + }, + headings: { + h1Count: 0, + count: 0, + hierarchyValid: true, + }, + issues: [], + }; + + const wordCounts = new Map(); + let stoppingWords: Set = new Set(); + const previousHeading = { value: "" }; + const lang = options.language; + + if (lang) { + stoppingWords = lang === "fra" ? frenchStopWords : englishStopWords; + } + + TreeNode.forEach((event) => { + browse(event, analytics, previousHeading, stoppingWords, wordCounts); + }); + + if (analytics.headings.h1Count === 0) { + createIssue({ reason: "missing-heading-one" }, analytics); + } + + if (analytics.headings.h1Count > 1) { + createIssue({ reason: "multiple-h1", count: analytics.headings.h1Count }, analytics); + } + + analytics.content.readingTime = Math.max(1, Math.round(analytics.content.words / readingSpeed)); + analytics.content.repeatedWords = [...wordCounts] + .filter(([, count]) => count > 1) + .sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])) + .map(([word, count]) => ({ word, count })); + + return analytics; +}; + +const browse = (node: Node, analytics: Analytics, previousHeading: { value: string }, stoppingWords: Set, wordCounts: Map) => { + if (typeof node === "string") return; + + if (headingType.has(node[0]!)) { + headingRule(previousHeading, node, analytics); + } + if (node[0] === "a") { + linkRule(node, analytics); + } + if (node[0] === "img") { + imageRule(node as ImageNode, analytics); + } + + contentRule(analytics, node, stoppingWords, previousHeading, wordCounts, browse); +}; diff --git a/tests/content.test.ts b/tests/content.test.ts new file mode 100644 index 0000000..f5fde9e --- /dev/null +++ b/tests/content.test.ts @@ -0,0 +1,34 @@ +import { describe, expect, test } from "vitest"; + +import { analyze } from "./utils/analyze.js"; + +describe("content", () => { + test("excludes
 and  from the word count", async () => {
+    const { analytics } = await analyze(" i  want an 
egg
"); + + expect(analytics.content.words).toBe(2); + }); + + test("never reports a reading time below one minute", async () => { + const { analytics } = await analyze("# Hello world"); + + expect(analytics.content.readingTime).toBeGreaterThanOrEqual(1); + }); + + test("sorts repeated words by frequency", async () => { + const { analytics } = await analyze("# Bonjour comment allez-vous monsieur ? Bonjour monsieur je vais bien ! Bonjour"); + + const repeatedWords = analytics.content.repeatedWords; + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const wordOne = repeatedWords[0]!; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const wordTwo = repeatedWords[1]!; + + expect(wordOne.word).toBe("bonjour"); + expect(wordOne.count).toBe(3); + + expect(wordTwo.word).toBe("monsieur"); + expect(wordTwo.count).toBe(2); + }); +}); diff --git a/tests/heading.test.ts b/tests/heading.test.ts new file mode 100644 index 0000000..2d7ea93 --- /dev/null +++ b/tests/heading.test.ts @@ -0,0 +1,23 @@ +import { describe, expect, test } from "vitest"; + +import { analyze } from "./utils/analyze.js"; + +describe("headings", () => { + test("reports a missing h1", async () => { + const { analytics } = await analyze("## hey"); + + expect(analytics.issues).toContainEqual({ reason: "missing-heading-one" }); + }); + + test("reports multiple h1", async () => { + const { analytics } = await analyze("# hey\n# hey 2"); + + expect(analytics.issues).toContainEqual({ reason: "multiple-h1", count: 2 }); + }); + + test("reports a skipped heading level", async () => { + const { analytics } = await analyze("# H1\n###### H6"); + + expect(analytics.issues).toContainEqual({ reason: "heading-hierarchy", from: "h1", to: "h6" }); + }); +}); diff --git a/tests/image.test.ts b/tests/image.test.ts new file mode 100644 index 0000000..4952655 --- /dev/null +++ b/tests/image.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, test } from "vitest"; + +import { analyze } from "./utils/analyze.js"; + +describe("images", () => { + test("reports an image without alt text", async () => { + const { analytics } = await analyze("# hey\n ![](image.jpg)"); + + expect(analytics.issues).toContainEqual({ reason: "missing-alt", src: "image.jpg" }); + }); + + test("reports an image without width and height", async () => { + const { analytics } = await analyze("# hey\n ![](image.jpg)"); + + expect(analytics.issues).toContainEqual({ reason: "missing-dimensions", src: "image.jpg", missing: "both" }); + }); +}); diff --git a/tests/link.test.ts b/tests/link.test.ts new file mode 100644 index 0000000..5201fcc --- /dev/null +++ b/tests/link.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, test } from "vitest"; + +import { analyze } from "./utils/analyze.js"; + +describe("links", () => { + test("reports a link with an invalid url", async () => { + const { analytics } = await analyze("# i love you\n[Duck Duck Go](hmm://javascript:alert(1))"); + + expect(analytics.issues).toContainEqual({ reason: "invalid-link", href: "hmm://javascript:alert(1)" }); + }); + + test("reports a link without url", async () => { + const { analytics } = await analyze("# i love you\n[Hello World]()"); + + expect(analytics.issues).toContainEqual({ reason: "missing-url", text: "Hello World" }); + }); +}); diff --git a/tests/utils/analyze.ts b/tests/utils/analyze.ts new file mode 100644 index 0000000..e73be47 --- /dev/null +++ b/tests/utils/analyze.ts @@ -0,0 +1,11 @@ +import { parseMarkdown } from "comark"; + +import { seo } from "../../src/seo.js"; +import type { ComarkSeoOptions } from "../../src/types.js"; + +export const analyze = async (content: string, options?: ComarkSeoOptions) => { + const markdown = await parseMarkdown(content); + const analytics = seo(markdown.nodes, options); + + return { markdown, analytics }; +}; diff --git a/tsconfig.json b/tsconfig.json index a0b158a..dd72cd9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -21,6 +21,6 @@ "skipLibCheck": true, "isolatedModules": true }, - "include": ["src", "playground", "tsdown.config.ts"], + "include": ["src", "tests", "playground", "tsdown.config.ts", "vitest.config.ts"], "exclude": ["node_modules", "dist"] } diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..ba29bd1 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + include: ["tests/**/*.test.ts"], + environment: "node", + }, +}); From 1a2569012684e96f2aff83bb0d651e6ff4a1c3e8 Mon Sep 17 00:00:00 2001 From: "C.Nelhomme" <64921289+D3ller@users.noreply.github.com> Date: Thu, 15 Oct 2026 23:32:31 +0200 Subject: [PATCH 2/7] build: add eslint and move to typescript 6 --- eslint.config.ts | 7 + package.json | 10 +- pnpm-lock.yaml | 1108 +++++++++++++++++++++++++++++++++++++--------- tsconfig.json | 2 +- 4 files changed, 924 insertions(+), 203 deletions(-) create mode 100644 eslint.config.ts diff --git a/eslint.config.ts b/eslint.config.ts new file mode 100644 index 0000000..687d06b --- /dev/null +++ b/eslint.config.ts @@ -0,0 +1,7 @@ +import { karibsen } from "@karibsen/eslint-config"; +import type { Linter } from "eslint"; +import type { FlatConfigComposer } from "eslint-flat-config-utils"; + +const config: FlatConfigComposer = karibsen(); + +export default config; diff --git a/package.json b/package.json index 127e643..e419959 100644 --- a/package.json +++ b/package.json @@ -39,17 +39,23 @@ "play": "tsx playground/text.ts", "prepublishOnly": "pnpm run typecheck && pnpm run build", "test": "vitest run", - "test:watch": "vitest" + "test:watch": "vitest", + "lint": "eslint .", + "lint:fix": "eslint . --fix" }, "peerDependencies": { "comark": ">=0.4.0" }, "devDependencies": { + "@karibsen/eslint-config": "^0.1.0", "@types/node": "^26.5.1", "comark": "^0.7.0", + "eslint": "^10.12.0", + "eslint-flat-config-utils": "^3.2.0", + "jiti": "^2.7.0", "tsdown": "^0.23.0", "tsx": "^4.23.13", - "typescript": "^7.0.2", + "typescript": "^6.0.3", "vitest": "^5.0.5" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5454cbe..30163de 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,27 +8,45 @@ importers: .: devDependencies: + '@karibsen/eslint-config': + specifier: ^0.1.0 + version: 0.1.0(eslint@10.12.0(jiti@2.7.0))(typescript@6.0.3) '@types/node': specifier: ^26.5.1 version: 26.5.1 comark: specifier: ^0.7.0 version: 0.7.0 + eslint: + specifier: ^10.12.0 + version: 10.12.0(jiti@2.7.0) + eslint-flat-config-utils: + specifier: ^3.2.0 + version: 3.2.0 + jiti: + specifier: ^2.7.0 + version: 2.7.0 tsdown: specifier: ^0.23.0 - version: 0.23.0(tsx@4.23.13)(typescript@7.0.2) + version: 0.23.0(tsx@4.23.13)(typescript@6.0.3) tsx: specifier: ^4.23.13 version: 4.23.13 typescript: - specifier: ^7.0.2 - version: 7.0.2 + specifier: ^6.0.3 + version: 6.0.3 vitest: specifier: ^5.0.5 - version: 5.0.5(@types/node@26.5.1)(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(tsx@4.23.13)) + version: 5.0.5(@types/node@26.5.1)(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)) packages: + '@cacheable/memory@2.2.0': + resolution: {integrity: sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ==} + + '@cacheable/utils@2.5.0': + resolution: {integrity: sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA==} + '@esbuild/aix-ppc64@0.28.2': resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} engines: {node: '>=18'} @@ -185,6 +203,69 @@ packages: cpu: [x64] os: [win32] + '@eslint-community/eslint-utils@4.10.1': + resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.23.5': + resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/config-helpers@0.5.5': + resolution: {integrity: sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/config-helpers@0.7.0': + resolution: {integrity: sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/core@1.2.1': + resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/js@10.0.1': + resolution: {integrity: sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + peerDependencies: + eslint: ^10.0.0 + peerDependenciesMeta: + eslint: + optional: true + + '@eslint/object-schema@3.0.5': + resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/plugin-kit@0.7.3': + resolution: {integrity: sha512-IkO+/KEUvwbVpiURZg+P7zF74z5Jxe0UgJxVni+RtoHQ6IZieXaO02kmadomap/q+l6bc/jdPGGqTjhuZnuz1Q==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} + engines: {node: '>=18.18.0'} + + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} @@ -195,6 +276,21 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@karibsen/eslint-config@0.1.0': + resolution: {integrity: sha512-7HBCLWrNnyCcMF60aaV5lWB/ZX1soPxxGNIhQyO0rrCXH6KQO/yelWXxNXjnPJPAoshOwGHlDcwP+GPb5q40hw==} + engines: {node: '>=20.0.0'} + peerDependencies: + eslint: ^9.0.0 || ^10.0.0 + + '@keyv/bigmap@1.3.1': + resolution: {integrity: sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==} + engines: {node: '>= 18'} + peerDependencies: + keyv: ^5.6.0 + + '@keyv/serialize@1.1.1': + resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==} + '@oxc-project/types@0.149.0': resolution: {integrity: sha512-Efcc+iF0j3Bf67YjEqIqWXbX5XddXoK/Mw4K1/JuXwRCZ8N16VR7iT23nlCc9XrveFVh/E5Rqs2StT0V8v9LdA==} @@ -399,15 +495,27 @@ packages: '@rolldown/pluginutils@1.0.1': resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + '@stylistic/eslint-plugin@5.10.0': + resolution: {integrity: sha512-nPK52ZHvot8Ju/0A4ucSX1dcPV2/1clx0kLcH5wDmrE4naKso7TUC/voUyU1O9OTKTrR6MYip6LP0ogEMQ9jPQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^9.0.0 || ^10.0.0 + '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@types/esrecurse@4.3.1': + resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} + '@types/estree@1.0.9': resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/linkify-it@5.0.0': resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} @@ -417,125 +525,64 @@ packages: '@types/node@26.5.1': resolution: {integrity: sha512-CzNm2FezW4VR/LjG6yUdiEgLE/rAQ9Slj5gCu/C2VrdcW7I0ahNZ8DRbHT7zOZ6r3ONgd/bsQIeSaoDGrd1C6g==} - '@typescript/typescript-aix-ppc64@7.0.2': - resolution: {integrity: sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==} - engines: {node: '>=16.20.0'} - cpu: [ppc64] - os: [aix] - - '@typescript/typescript-darwin-arm64@7.0.2': - resolution: {integrity: sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [darwin] - - '@typescript/typescript-darwin-x64@7.0.2': - resolution: {integrity: sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [darwin] - - '@typescript/typescript-freebsd-arm64@7.0.2': - resolution: {integrity: sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [freebsd] - - '@typescript/typescript-freebsd-x64@7.0.2': - resolution: {integrity: sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [freebsd] - - '@typescript/typescript-linux-arm64@7.0.2': - resolution: {integrity: sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [linux] - - '@typescript/typescript-linux-arm@7.0.2': - resolution: {integrity: sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==} - engines: {node: '>=16.20.0'} - cpu: [arm] - os: [linux] - - '@typescript/typescript-linux-loong64@7.0.2': - resolution: {integrity: sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==} - engines: {node: '>=16.20.0'} - cpu: [loong64] - os: [linux] - - '@typescript/typescript-linux-mips64el@7.0.2': - resolution: {integrity: sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==} - engines: {node: '>=16.20.0'} - cpu: [mips64el] - os: [linux] - - '@typescript/typescript-linux-ppc64@7.0.2': - resolution: {integrity: sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==} - engines: {node: '>=16.20.0'} - cpu: [ppc64] - os: [linux] + '@typescript-eslint/eslint-plugin@8.71.2': + resolution: {integrity: sha512-K72/pvT7qpm8q3k8G5u93NCSN1RcLxX5h7Gw0bQpbMXviBHeY6Nx1WEwmk9wP+eKTSQ8ecxvcgt/ZX/rB938xQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.71.2 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript/typescript-linux-riscv64@7.0.2': - resolution: {integrity: sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==} - engines: {node: '>=16.20.0'} - cpu: [riscv64] - os: [linux] + '@typescript-eslint/parser@8.71.2': + resolution: {integrity: sha512-aTtmZjp/x3gsGHkDs04/1I8kNogBJkpQaeGaN0PfiG43NzDEmW2n+OP5im9wfsvyX0yP1UZWBrAGtDBfH9jEVw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript/typescript-linux-s390x@7.0.2': - resolution: {integrity: sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==} - engines: {node: '>=16.20.0'} - cpu: [s390x] - os: [linux] + '@typescript-eslint/project-service@8.71.2': + resolution: {integrity: sha512-Pd68GsLVh5ZXlcEccFPdhSOvtHZ/2WU0XsA8zmXOS3F158lVlcTLhfQ6qvtL1RzbMie0Kp8xtbVwAg4nejKPHw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' - '@typescript/typescript-linux-x64@7.0.2': - resolution: {integrity: sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [linux] + '@typescript-eslint/scope-manager@8.71.2': + resolution: {integrity: sha512-YF4wgg5iUX5Obywoac27B56FhozMNFhdJSbh11H5GBAwmBtfyRhmgTQqW9tRNNmHDvsZ2CX6UGzoz+YfYn2Leg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript/typescript-netbsd-arm64@7.0.2': - resolution: {integrity: sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [netbsd] - - '@typescript/typescript-netbsd-x64@7.0.2': - resolution: {integrity: sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [netbsd] + '@typescript-eslint/tsconfig-utils@8.71.2': + resolution: {integrity: sha512-jz49TAWokm/7yWD9/o837nYax9DyALxIPOImdImvVzo6canBCZYzin8zJyqNR5k1j9K1DE0bVvr0XYB+99uAdg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' - '@typescript/typescript-openbsd-arm64@7.0.2': - resolution: {integrity: sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [openbsd] + '@typescript-eslint/type-utils@8.71.2': + resolution: {integrity: sha512-cC8UaalCViJkb3rH/xLIvidEwoFRtMZMUqDjjJMGEKaTFwYRHYBcoczlEGHuvkHEO8svRDrgZ0yQgOArFmwang==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript/typescript-openbsd-x64@7.0.2': - resolution: {integrity: sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [openbsd] + '@typescript-eslint/types@8.71.2': + resolution: {integrity: sha512-y5Ukl3oVp7e/VGxqIoEXoeb/Roj71PAJ4WG/N/RGj+eeDvKRLM15kGr9MijLbN0i03S52zxu31Z98E5gWChJKw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript/typescript-sunos-x64@7.0.2': - resolution: {integrity: sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [sunos] + '@typescript-eslint/typescript-estree@8.71.2': + resolution: {integrity: sha512-DgNOEsl4pdYzwSL+N/Cl33tX1Hlw3FvId73LnKXfq7jnrF2viOEn7X+P7RBkkSWCVm92gnWd28GIC5vJuLREeA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' - '@typescript/typescript-win32-arm64@7.0.2': - resolution: {integrity: sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [win32] + '@typescript-eslint/utils@8.71.2': + resolution: {integrity: sha512-RyKa1G1M9rKHDhrk+HJtiF1MvLD5Ux2JW3TSkzw+02pRALdpJb+QzG1Y5em+LvCgzGwgg8H7mBRFKljNz7ImPw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript/typescript-win32-x64@7.0.2': - resolution: {integrity: sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [win32] + '@typescript-eslint/visitor-keys@8.71.2': + resolution: {integrity: sha512-zozlN0UA32bSG2zkKAgQyRYSbEISVoyU6vvkKYo2aSny74D8Jh4e+POkJ6Lk0dlezZi5x7TtD+88Xb06IB8nhg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@vitest/mocker@5.0.5': resolution: {integrity: sha512-xLL3lkDegJZw+MGoGaCCsFayDZthGgpAtr3Vziyfc4p7xH89K7KRPcRBBh/kEYm0Aqkt5DtTmkYpBtRV/FrHZg==} @@ -708,6 +755,19 @@ packages: '@yuku-toolchain/types@0.9.5': resolution: {integrity: sha512-KiuLNNgX9uNealaWAR+G3/cMXnRk9x4TY2EkYe/KIag+UPdwiA0RRf1hr1WAxzTP8KGzCTkqUdLPvqh32sEO3w==} + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.19.0: + resolution: {integrity: sha512-oJlA3XiRm7Cyk6qFD2Jn8ak9B7jSy0qy00ADO3+8dpT0LSjFihQYv4C02LFCSYJV3Q37xYwwRy5m+IpIiUzqWw==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -715,10 +775,21 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + brace-expansion@5.0.12: + resolution: {integrity: sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==} + engines: {node: 20 || >=22} + cac@7.0.0: resolution: {integrity: sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==} engines: {node: '>=20.19.0'} + cacheable@2.5.0: + resolution: {integrity: sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==} + chai@6.3.0: resolution: {integrity: sha512-XWAtwJ6OHO+tj0EKCs0Y2UamnyOxseZWltU4x2U2wh8g4AigdjwvtUjvLP2tqkA/avxHEtzxNaqGq/YGNwckKg==} engines: {node: '>=18'} @@ -740,6 +811,22 @@ packages: shiki: optional: true + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + defu@6.1.7: resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} @@ -792,13 +879,84 @@ packages: engines: {node: '>=18'} hasBin: true + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-flat-config-utils@3.2.0: + resolution: {integrity: sha512-PHgo1X5uqIorJONLVD9BIaOSdoYFD3z/AeJljdqDPlWVRpeCYkDbK9k0AXoYVqqNJr6FEYIEr5Rm2TSktLQcHw==} + + eslint-plugin-simple-import-sort@14.0.0: + resolution: {integrity: sha512-NUJO0+XFCkk+o5EsAJruTgnfMEpeWrPWeJS15UVF60GgXmqz1BJ9/3hzlvG7lkL8Bubzos5cCLptThbFfPnSMQ==} + peerDependencies: + eslint: '>=5.0.0' + + eslint-scope@9.1.2: + resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@10.12.0: + resolution: {integrity: sha512-npHjrHb2o4ehH3mE+YuxABR+0gyb0aVWCIolgJDArwCiHEIsonBm3ZKjel5b0U5+a+MbEvIyRCGCzD3eKKK2NA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + espree@11.2.0: + resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + expect-type@1.4.0: resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} engines: {node: '>=12.0.0'} + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -808,6 +966,19 @@ packages: picomatch: optional: true + file-entry-cache@11.1.5: + resolution: {integrity: sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q==} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@6.1.23: + resolution: {integrity: sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==} + + flatted@3.4.4: + resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -817,21 +988,79 @@ packages: resolution: {integrity: sha512-X6fBC0pmImC70gvX2zm56go9hx0MyoGVdG0tUCkg/D+Xnh5TJsOZ7iDbOdI3PvmtrDxnu1YdDufpK2QJX1Meqw==} engines: {node: '>=20.20.0'} + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + globals@17.13.0: + resolution: {integrity: sha512-RwMTC61u7hrG3ZJMkZQOK4JLJrKS8QtoTii63EmWvFXHqycY9FObBJQCbsLxSO8kjKhWE5kV1GC+Vb1g3RI0Zg==} + engines: {node: '>=18'} + + hashery@1.5.1: + resolution: {integrity: sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==} + engines: {node: '>=20'} + hookable@6.1.1: resolution: {integrity: sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ==} + hookified@1.15.1: + resolution: {integrity: sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==} + + hookified@2.2.0: + resolution: {integrity: sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==} + htmlparser2@12.0.0: resolution: {integrity: sha512-Tz7u1i95/g2x2jz81+x0FBVhBhY5aRTvD3tXXdFaljuNdzDLJ8UGNRrTcj2cgQvAg3iW/h77Fz15nLW0L0CrZw==} engines: {node: '>=20.19.0'} + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.12: + resolution: {integrity: sha512-/8UvqAPU9DGTI9k4mxtf49U37Isfwr8Uts96+SBHIkFxPJnHS0Ew4f00sM4Scd8V8EjM0jUNtVDdv1kPdt35lg==} + engines: {node: '>= 4'} + import-without-cache@0.4.0: resolution: {integrity: sha512-NkJQA7oZ4YHQhd2+H3BoRFKF3d/XNsiKpHZCQEMH9pDX27hQQLsTyOocyRgaIVtf8gHX3Nt3LPkR4e5EdtPAGQ==} engines: {node: ^22.18.0 || >=24.0.0} + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + js-yaml@5.4.2: resolution: {integrity: sha512-m+aqu+LwO1O6sIopafj8HUVl5aawITwZQe/yHpMCKjaWBaA/d07B/QdMb3529REftiU+RMMHL3Vlsw3hON7vWg==} hasBin: true + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + keyv@5.6.0: + resolution: {integrity: sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + lightningcss-android-arm64@1.33.0: resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} engines: {node: '>= 12.0.0'} @@ -909,6 +1138,10 @@ packages: linkify-it@5.0.2: resolution: {integrity: sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==} + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + magic-string@1.4.3: resolution: {integrity: sha512-z12OxmaPGE0F4xlpGdjuAUckipLpQlTAuAmyGhNoD7ODpYUzvDfvtxUbjM/jwznyP178oju/KDdyi220wNJ0RQ==} @@ -918,11 +1151,21 @@ packages: mdurl@2.1.0: resolution: {integrity: sha512-1+HBaOx0zi/dQWht8rNv9MYf9qqpqL/kxI0hXImU6Y547zM6Sni8BQibt7ifgMcYtQg41ao3Ivd6cnSM86inpg==} + minimatch@10.2.6: + resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} + engines: {node: 18 || 20 || >=22} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + nanoid@3.3.20: resolution: {integrity: sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + obug@2.2.1: resolution: {integrity: sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==} engines: {node: '>=12.20.0'} @@ -931,6 +1174,29 @@ packages: resolution: {integrity: sha512-5vvB5+W7ePv+p3uqxi+RcW1XAzLW0/hxt3/4X4Lc4qHudzOhmBiBwOY6DRob4WnanAEGvNcLjF+KNOufrUoEQw==} engines: {node: '>=12.20.0'} + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -942,10 +1208,22 @@ packages: resolution: {integrity: sha512-zkd+e9S1AQHhmaBKye9zlFHWjOwVgqXl1q3ECYy8561K7qxR2cREf/STLskulBFd78k6AOFeA+ff1TtEzk9bAA==} engines: {node: ^10 || ^12 || >=14} + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + punycode.js@2.3.1: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qified@0.10.1: + resolution: {integrity: sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==} + engines: {node: '>=20'} + quansync@1.0.0: resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==} @@ -981,6 +1259,19 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + source-map-js@1.2.2: resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==} engines: {node: '>=0.10.0'} @@ -1004,6 +1295,12 @@ packages: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + tsdown@0.23.0: resolution: {integrity: sha512-BaT+ep1xnj5hdyICLd5r5SYYE+TXnI1ATePLykv9vcKpHpFTWUWRH+x1AF/E2qcu3YB6+vI8IdyxIIIffEqw5Q==} engines: {node: ^22.18.0 || ^24.11.0 || >=26.0.0} @@ -1043,9 +1340,20 @@ packages: engines: {node: '>=18.0.0'} hasBin: true - typescript@7.0.2: - resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==} - engines: {node: '>=16.20.0'} + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + typescript-eslint@8.71.2: + resolution: {integrity: sha512-Rz4effbMy2g9wnvOJZG6SbVavX313Lap1vNEbk1RUochzickvzP8P4HB+bkNg5e50eVz1hQGjh9K1omI1xB4Bw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} + engines: {node: '>=14.17'} hasBin: true uc.micro@2.1.0: @@ -1057,6 +1365,9 @@ packages: undici-types@8.9.0: resolution: {integrity: sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==} + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + verkit@0.4.0: resolution: {integrity: sha512-sXMwN6DMHeouPfCxkxWkKAmxphWKEenHYY5H1nIBzU3PmDsmJp6kBXJdshjVdpMZuWCmL9SH7KFRx29AylpP6g==} engines: {node: '>=18.12.0'} @@ -1145,11 +1456,24 @@ packages: jsdom: optional: true + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + why-is-node-running@3.2.1: resolution: {integrity: sha512-Tb2FUhB4vUsGQlfSquQLYkApkuPAFQXGFzxWKHHumVz2dK+X1RUm/HnID4+TfIGYJ1kTcwOaCk/buYCEJr6YjQ==} engines: {node: '>=20.11'} hasBin: true + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + yuku-ast@0.9.5: resolution: {integrity: sha512-Q8qW8WwQnN5Cm0ZZivdRIfv0sRLTjUq0YumXJkw8CYN1aCdICH9rk4C47/4n6kA5EqDtlj+F608twoTSV2MwdQ==} @@ -1161,6 +1485,18 @@ packages: snapshots: + '@cacheable/memory@2.2.0': + dependencies: + '@cacheable/utils': 2.5.0 + '@keyv/bigmap': 1.3.1(keyv@5.6.0) + hookified: 1.15.1 + keyv: 5.6.0 + + '@cacheable/utils@2.5.0': + dependencies: + hashery: 1.5.1 + keyv: 5.6.0 + '@esbuild/aix-ppc64@0.28.2': optional: true @@ -1239,6 +1575,60 @@ snapshots: '@esbuild/win32-x64@0.28.2': optional: true + '@eslint-community/eslint-utils@4.10.1(eslint@10.12.0(jiti@2.7.0))': + dependencies: + eslint: 10.12.0(jiti@2.7.0) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.23.5': + dependencies: + '@eslint/object-schema': 3.0.5 + debug: 4.4.3 + minimatch: 10.2.6 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.5.5': + dependencies: + '@eslint/core': 1.2.1 + + '@eslint/config-helpers@0.7.0': + dependencies: + '@eslint/core': 1.2.1 + + '@eslint/core@1.2.1': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/js@10.0.1(eslint@10.12.0(jiti@2.7.0))': + optionalDependencies: + eslint: 10.12.0(jiti@2.7.0) + + '@eslint/object-schema@3.0.5': {} + + '@eslint/plugin-kit@0.7.3': + dependencies: + '@eslint/core': 1.2.1 + levn: 0.4.1 + + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 + + '@humanfs/node@0.16.8': + dependencies: + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 + '@humanwhocodes/retry': 0.4.3 + + '@humanfs/types@0.15.0': {} + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/sourcemap-codec@1.6.0': {} @@ -1248,6 +1638,27 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.6.0 + '@karibsen/eslint-config@0.1.0(eslint@10.12.0(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@eslint/js': 10.0.1(eslint@10.12.0(jiti@2.7.0)) + '@stylistic/eslint-plugin': 5.10.0(eslint@10.12.0(jiti@2.7.0)) + eslint: 10.12.0(jiti@2.7.0) + eslint-flat-config-utils: 3.2.0 + eslint-plugin-simple-import-sort: 14.0.0(eslint@10.12.0(jiti@2.7.0)) + globals: 17.13.0 + typescript-eslint: 8.71.2(eslint@10.12.0(jiti@2.7.0))(typescript@6.0.3) + transitivePeerDependencies: + - supports-color + - typescript + + '@keyv/bigmap@1.3.1(keyv@5.6.0)': + dependencies: + hashery: 1.5.1 + hookified: 1.15.1 + keyv: 5.6.0 + + '@keyv/serialize@1.1.1': {} + '@oxc-project/types@0.149.0': {} '@oxc-project/types@0.154.0': {} @@ -1348,6 +1759,16 @@ snapshots: '@rolldown/pluginutils@1.0.1': {} + '@stylistic/eslint-plugin@5.10.0(eslint@10.12.0(jiti@2.7.0))': + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@10.12.0(jiti@2.7.0)) + '@typescript-eslint/types': 8.71.2 + eslint: 10.12.0(jiti@2.7.0) + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + estraverse: 5.3.0 + picomatch: 4.0.7 + '@types/chai@5.2.3': dependencies: '@types/deep-eql': 4.0.2 @@ -1355,8 +1776,12 @@ snapshots: '@types/deep-eql@4.0.2': {} + '@types/esrecurse@4.3.1': {} + '@types/estree@1.0.9': {} + '@types/json-schema@7.0.15': {} + '@types/linkify-it@5.0.0': {} '@types/mdurl@2.0.0': {} @@ -1365,74 +1790,105 @@ snapshots: dependencies: undici-types: 8.9.0 - '@typescript/typescript-aix-ppc64@7.0.2': - optional: true - - '@typescript/typescript-darwin-arm64@7.0.2': - optional: true - - '@typescript/typescript-darwin-x64@7.0.2': - optional: true - - '@typescript/typescript-freebsd-arm64@7.0.2': - optional: true - - '@typescript/typescript-freebsd-x64@7.0.2': - optional: true - - '@typescript/typescript-linux-arm64@7.0.2': - optional: true - - '@typescript/typescript-linux-arm@7.0.2': - optional: true - - '@typescript/typescript-linux-loong64@7.0.2': - optional: true - - '@typescript/typescript-linux-mips64el@7.0.2': - optional: true - - '@typescript/typescript-linux-ppc64@7.0.2': - optional: true - - '@typescript/typescript-linux-riscv64@7.0.2': - optional: true + '@typescript-eslint/eslint-plugin@8.71.2(@typescript-eslint/parser@8.71.2(eslint@10.12.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.12.0(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.71.2(eslint@10.12.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.71.2 + '@typescript-eslint/type-utils': 8.71.2(eslint@10.12.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/utils': 8.71.2(eslint@10.12.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.71.2 + eslint: 10.12.0(jiti@2.7.0) + ignore: 7.0.12 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color - '@typescript/typescript-linux-s390x@7.0.2': - optional: true + '@typescript-eslint/parser@8.71.2(eslint@10.12.0(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.71.2 + '@typescript-eslint/types': 8.71.2 + '@typescript-eslint/typescript-estree': 8.71.2(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.71.2 + debug: 4.4.3 + eslint: 10.12.0(jiti@2.7.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color - '@typescript/typescript-linux-x64@7.0.2': - optional: true + '@typescript-eslint/project-service@8.71.2(typescript@6.0.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.71.2(typescript@6.0.3) + '@typescript-eslint/types': 8.71.2 + debug: 4.4.3 + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color - '@typescript/typescript-netbsd-arm64@7.0.2': - optional: true + '@typescript-eslint/scope-manager@8.71.2': + dependencies: + '@typescript-eslint/types': 8.71.2 + '@typescript-eslint/visitor-keys': 8.71.2 - '@typescript/typescript-netbsd-x64@7.0.2': - optional: true + '@typescript-eslint/tsconfig-utils@8.71.2(typescript@6.0.3)': + dependencies: + typescript: 6.0.3 - '@typescript/typescript-openbsd-arm64@7.0.2': - optional: true + '@typescript-eslint/type-utils@8.71.2(eslint@10.12.0(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@typescript-eslint/types': 8.71.2 + '@typescript-eslint/typescript-estree': 8.71.2(typescript@6.0.3) + '@typescript-eslint/utils': 8.71.2(eslint@10.12.0(jiti@2.7.0))(typescript@6.0.3) + debug: 4.4.3 + eslint: 10.12.0(jiti@2.7.0) + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color - '@typescript/typescript-openbsd-x64@7.0.2': - optional: true + '@typescript-eslint/types@8.71.2': {} - '@typescript/typescript-sunos-x64@7.0.2': - optional: true + '@typescript-eslint/typescript-estree@8.71.2(typescript@6.0.3)': + dependencies: + '@typescript-eslint/project-service': 8.71.2(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.71.2(typescript@6.0.3) + '@typescript-eslint/types': 8.71.2 + '@typescript-eslint/visitor-keys': 8.71.2 + debug: 4.4.3 + minimatch: 10.2.6 + semver: 7.8.5 + tinyglobby: 0.2.17 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color - '@typescript/typescript-win32-arm64@7.0.2': - optional: true + '@typescript-eslint/utils@8.71.2(eslint@10.12.0(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@10.12.0(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.71.2 + '@typescript-eslint/types': 8.71.2 + '@typescript-eslint/typescript-estree': 8.71.2(typescript@6.0.3) + eslint: 10.12.0(jiti@2.7.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color - '@typescript/typescript-win32-x64@7.0.2': - optional: true + '@typescript-eslint/visitor-keys@8.71.2': + dependencies: + '@typescript-eslint/types': 8.71.2 + eslint-visitor-keys: 5.0.1 - '@vitest/mocker@5.0.5(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(tsx@4.23.13))': + '@vitest/mocker@5.0.5(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13))': dependencies: '@jridgewell/trace-mapping': 0.3.31 '@vitest/spy': 5.0.5 estree-walker: 3.0.3 magic-string: 1.4.3 optionalDependencies: - vite: 8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(tsx@4.23.13) + vite: 8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13) '@vitest/spy@5.0.5': {} @@ -1510,12 +1966,39 @@ snapshots: '@yuku-toolchain/types@0.9.5': {} + acorn-jsx@5.3.2(acorn@8.19.0): + dependencies: + acorn: 8.19.0 + + acorn@8.19.0: {} + + ajv@6.15.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + argparse@2.0.1: {} assertion-error@2.0.1: {} + balanced-match@4.0.4: {} + + brace-expansion@5.0.12: + dependencies: + balanced-match: 4.0.4 + cac@7.0.0: {} + cacheable@2.5.0: + dependencies: + '@cacheable/memory': 2.2.0 + '@cacheable/utils': 2.5.0 + hookified: 1.15.1 + keyv: 5.6.0 + qified: 0.10.1 + chai@6.3.0: {} comark@0.7.0: @@ -1525,6 +2008,18 @@ snapshots: js-yaml: 5.4.2 markdown-exit: 1.1.0-beta.2 + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + defu@6.1.7: {} detect-libc@2.1.2: {} @@ -1586,16 +2081,124 @@ snapshots: '@esbuild/win32-ia32': 0.28.2 '@esbuild/win32-x64': 0.28.2 + escape-string-regexp@4.0.0: {} + + eslint-flat-config-utils@3.2.0: + dependencies: + '@eslint/config-helpers': 0.5.5 + pathe: 2.0.3 + + eslint-plugin-simple-import-sort@14.0.0(eslint@10.12.0(jiti@2.7.0)): + dependencies: + eslint: 10.12.0(jiti@2.7.0) + + eslint-scope@9.1.2: + dependencies: + '@types/esrecurse': 4.3.1 + '@types/estree': 1.0.9 + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint-visitor-keys@5.0.1: {} + + eslint@10.12.0(jiti@2.7.0): + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@10.12.0(jiti@2.7.0)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.23.5 + '@eslint/config-helpers': 0.7.0 + '@eslint/core': 1.2.1 + '@eslint/plugin-kit': 0.7.3 + '@humanfs/node': 0.16.8 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.9 + ajv: 6.15.0 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 9.1.2 + eslint-visitor-keys: 5.0.1 + espree: 11.2.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 11.1.5 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + minimatch: 10.2.6 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.7.0 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.19.0 + acorn-jsx: 5.3.2(acorn@8.19.0) + eslint-visitor-keys: 4.2.1 + + espree@11.2.0: + dependencies: + acorn: 8.19.0 + acorn-jsx: 5.3.2(acorn@8.19.0) + eslint-visitor-keys: 5.0.1 + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + estree-walker@3.0.3: dependencies: '@types/estree': 1.0.9 + esutils@2.0.3: {} + expect-type@1.4.0: {} + fast-deep-equal@3.1.3: {} + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + fdir@6.5.0(picomatch@4.0.7): optionalDependencies: picomatch: 4.0.7 + file-entry-cache@11.1.5: + dependencies: + flat-cache: 6.1.23 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@6.1.23: + dependencies: + cacheable: 2.5.0 + flatted: 3.4.4 + hookified: 1.15.1 + + flatted@3.4.4: {} + fsevents@2.3.3: optional: true @@ -1603,8 +2206,22 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@17.13.0: {} + + hashery@1.5.1: + dependencies: + hookified: 1.15.1 + hookable@6.1.1: {} + hookified@1.15.1: {} + + hookified@2.2.0: {} + htmlparser2@12.0.0: dependencies: domelementtype: 3.0.0 @@ -1612,12 +2229,41 @@ snapshots: domutils: 4.0.2 entities: 8.1.0 + ignore@5.3.2: {} + + ignore@7.0.12: {} + import-without-cache@0.4.0: {} + imurmurhash@0.1.4: {} + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + isexe@2.0.0: {} + + jiti@2.7.0: {} + js-yaml@5.4.2: dependencies: argparse: 2.0.1 + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + keyv@5.6.0: + dependencies: + '@keyv/serialize': 1.1.1 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + lightningcss-android-arm64@1.33.0: optional: true @@ -1671,6 +2317,10 @@ snapshots: dependencies: uc.micro: 2.1.0 + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + magic-string@1.4.3: dependencies: '@jridgewell/sourcemap-codec': 1.6.0 @@ -1687,12 +2337,43 @@ snapshots: mdurl@2.1.0: {} + minimatch@10.2.6: + dependencies: + brace-expansion: 5.0.12 + + ms@2.1.3: {} + nanoid@3.3.20: {} + natural-compare@1.4.0: {} + obug@2.2.1: {} obug@3.0.0: {} + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + pathe@2.0.3: {} + picocolors@1.1.1: {} picomatch@4.0.7: {} @@ -1703,13 +2384,21 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.2 + prelude-ls@1.2.1: {} + punycode.js@2.3.1: {} + punycode@2.3.1: {} + + qified@0.10.1: + dependencies: + hookified: 2.2.0 + quansync@1.0.0: {} resolve-pkg-maps@1.0.0: {} - rolldown-plugin-dts@0.28.5(rolldown@1.2.8)(typescript@7.0.2): + rolldown-plugin-dts@0.28.5(rolldown@1.2.8)(typescript@6.0.3): dependencies: dts-resolver: 3.0.0 get-tsconfig: 5.0.0-beta.6 @@ -1719,7 +2408,7 @@ snapshots: yuku-codegen: 0.9.5 yuku-parser: 0.9.5 optionalDependencies: - typescript: 7.0.2 + typescript: 6.0.3 transitivePeerDependencies: - oxc-resolver @@ -1765,6 +2454,14 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.2.8 '@rolldown/binding-win32-x64-msvc': 1.2.8 + semver@7.8.5: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + source-map-js@1.2.2: {} std-env@4.3.0: {} @@ -1780,7 +2477,11 @@ snapshots: tree-kill@1.2.2: {} - tsdown@0.23.0(tsx@4.23.13)(typescript@7.0.2): + ts-api-utils@2.5.0(typescript@6.0.3): + dependencies: + typescript: 6.0.3 + + tsdown@0.23.0(tsx@4.23.13)(typescript@6.0.3): dependencies: cac: 7.0.0 defu: 6.1.7 @@ -1790,7 +2491,7 @@ snapshots: obug: 2.2.1 picomatch: 4.0.7 rolldown: 1.2.8 - rolldown-plugin-dts: 0.28.5(rolldown@1.2.8)(typescript@7.0.2) + rolldown-plugin-dts: 0.28.5(rolldown@1.2.8)(typescript@6.0.3) tinyexec: 1.3.1 tinyglobby: 0.2.17 tree-kill: 1.2.2 @@ -1798,7 +2499,7 @@ snapshots: verkit: 0.4.0 optionalDependencies: tsx: 4.23.13 - typescript: 7.0.2 + typescript: 6.0.3 transitivePeerDependencies: - '@typescript/native-preview' - '@volar/typescript' @@ -1811,28 +2512,22 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - typescript@7.0.2: - optionalDependencies: - '@typescript/typescript-aix-ppc64': 7.0.2 - '@typescript/typescript-darwin-arm64': 7.0.2 - '@typescript/typescript-darwin-x64': 7.0.2 - '@typescript/typescript-freebsd-arm64': 7.0.2 - '@typescript/typescript-freebsd-x64': 7.0.2 - '@typescript/typescript-linux-arm': 7.0.2 - '@typescript/typescript-linux-arm64': 7.0.2 - '@typescript/typescript-linux-loong64': 7.0.2 - '@typescript/typescript-linux-mips64el': 7.0.2 - '@typescript/typescript-linux-ppc64': 7.0.2 - '@typescript/typescript-linux-riscv64': 7.0.2 - '@typescript/typescript-linux-s390x': 7.0.2 - '@typescript/typescript-linux-x64': 7.0.2 - '@typescript/typescript-netbsd-arm64': 7.0.2 - '@typescript/typescript-netbsd-x64': 7.0.2 - '@typescript/typescript-openbsd-arm64': 7.0.2 - '@typescript/typescript-openbsd-x64': 7.0.2 - '@typescript/typescript-sunos-x64': 7.0.2 - '@typescript/typescript-win32-arm64': 7.0.2 - '@typescript/typescript-win32-x64': 7.0.2 + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typescript-eslint@8.71.2(eslint@10.12.0(jiti@2.7.0))(typescript@6.0.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.71.2(@typescript-eslint/parser@8.71.2(eslint@10.12.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.12.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/parser': 8.71.2(eslint@10.12.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.71.2(typescript@6.0.3) + '@typescript-eslint/utils': 8.71.2(eslint@10.12.0(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.12.0(jiti@2.7.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + typescript@6.0.3: {} uc.micro@2.1.0: {} @@ -1843,9 +2538,13 @@ snapshots: undici-types@8.9.0: {} + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + verkit@0.4.0: {} - vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(tsx@4.23.13): + vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13): dependencies: lightningcss: 1.33.0 picomatch: 4.0.7 @@ -1856,12 +2555,13 @@ snapshots: '@types/node': 26.5.1 esbuild: 0.28.2 fsevents: 2.3.3 + jiti: 2.7.0 tsx: 4.23.13 - vitest@5.0.5(@types/node@26.5.1)(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(tsx@4.23.13)): + vitest@5.0.5(@types/node@26.5.1)(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)): dependencies: '@types/chai': 5.2.3 - '@vitest/mocker': 5.0.5(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(tsx@4.23.13)) + '@vitest/mocker': 5.0.5(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)) chai: 6.3.0 es-module-lexer: 2.3.2 expect-type: 1.4.0 @@ -1872,15 +2572,23 @@ snapshots: tinybench: 6.2.2 tinyexec: 1.3.1 tinyglobby: 0.2.17 - vite: 8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(tsx@4.23.13) + vite: 8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13) why-is-node-running: 3.2.1 optionalDependencies: '@types/node': 26.5.1 transitivePeerDependencies: - msw + which@2.0.2: + dependencies: + isexe: 2.0.0 + why-is-node-running@3.2.1: {} + word-wrap@1.2.5: {} + + yocto-queue@0.1.0: {} + yuku-ast@0.9.5: dependencies: '@yuku-toolchain/types': 0.9.5 diff --git a/tsconfig.json b/tsconfig.json index dd72cd9..c673a85 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -21,6 +21,6 @@ "skipLibCheck": true, "isolatedModules": true }, - "include": ["src", "tests", "playground", "tsdown.config.ts", "vitest.config.ts"], + "include": ["src", "tests", "playground", "tsdown.config.ts", "vitest.config.ts", "eslint.config.ts"], "exclude": ["node_modules", "dist"] } From d10d09434f291981df4b8f04f9bc5b4cbce15fac Mon Sep 17 00:00:00 2001 From: "C.Nelhomme" <64921289+D3ller@users.noreply.github.com> Date: Thu, 15 Oct 2026 23:33:29 +0200 Subject: [PATCH 3/7] style: apply eslint rules --- playground/text.ts | 866 +++++++++++++++++++++---------------------- src/constants.ts | 112 +++--- src/rules/content.ts | 44 ++- src/rules/heading.ts | 75 ++-- src/rules/image.ts | 27 +- src/rules/link.ts | 55 +-- src/types.ts | 157 ++++---- src/utils/flatten.ts | 7 +- src/utils/issue.ts | 6 +- tsdown.config.ts | 10 +- 10 files changed, 683 insertions(+), 676 deletions(-) diff --git a/playground/text.ts b/playground/text.ts index dead287..c71cd67 100644 --- a/playground/text.ts +++ b/playground/text.ts @@ -1,437 +1,437 @@ import { parseMarkdown } from "comark"; -import seo from "../src/index.js" -const tree = await parseMarkdown('# Le guide complet du développement web moderne en 2026\n' + - '\n' + - 'Le développement web moderne ne consiste plus simplement à créer\n' + - 'quelques pages HTML accompagnées d\'une feuille de style. Les\n' + - 'applications actuelles combinent souvent plusieurs technologies pour\n' + - 'gérer l\'interface utilisateur, les données, l\'authentification, les\n' + - 'performances et le déploiement.\n' + - '\n' + - 'Pour construire une application robuste, il est important de comprendre\n' + - 'les différentes couches qui composent une architecture web moderne.\n' + - '\n' + - 'Ce guide présente les principaux concepts à connaître ainsi que les\n' + - 'technologies couramment utilisées par les développeurs.\n' + - '\n' + - '![Un développeur travaillant sur une application\n' + - 'web](https://images.example.com/developer.jpg)\n' + - '\n' + - '## Les fondamentaux du Web\n' + - '\n' + - 'Le Web repose historiquement sur trois technologies principales :\n' + - '\n' + - '- HTML\n' + - '- CSS\n' + - '- JavaScript\n' + - '\n' + - 'Chacune possède un rôle différent dans le fonctionnement d\'une page.\n' + - '\n' + - '### HTML et la structure des documents\n' + - '\n' + - 'HTML permet de définir la structure et la sémantique d\'une page.\n' + - '\n' + - 'Un document correctement structuré utilise des éléments adaptés au\n' + - 'contenu qu\'il représente.\n' + - '\n' + - '### CSS et la présentation\n' + - '\n' + - 'CSS contrôle l\'apparence d\'un document.\n' + - '\n' + - 'Les développeurs peuvent notamment modifier :\n' + - '\n' + - '- les couleurs ;\n' + - '- les espacements ;\n' + - '- les polices ;\n' + - '- les dimensions ;\n' + - '- les animations ;\n' + - '- le positionnement ;\n' + - '- les layouts.\n' + - '\n' + - 'Les fonctionnalités modernes comme **Flexbox** et **CSS Grid**\n' + - 'permettent de construire des interfaces complexes sans utiliser les\n' + - 'anciennes techniques basées sur `float`.\n' + - '\n' + - '![Exemple d\'une interface utilisant CSS\n' + - 'Grid](https://images.example.com/css-grid.png)\n' + - '\n' + - '### JavaScript et les interactions\n' + - '\n' + - 'JavaScript permet d\'ajouter des comportements dynamiques aux pages.\n' + - '\n' + - '``` js\n' + - 'const message = "Hello World"\n' + - '\n' + - 'console.log(message)\n' + - '```\n' + - '\n' + - '## Les frameworks frontend\n' + - '\n' + - 'Lorsque les interfaces deviennent complexes, organiser l\'ensemble du\n' + - 'JavaScript devient rapidement difficile.\n' + - '\n' + - '### React\n' + - '\n' + - '[React](https://react.dev/) est une bibliothèque développée initialement\n' + - 'par Meta.\n' + - '\n' + - 'React repose sur une approche basée sur les composants.\n' + - '\n' + - '### Vue\n' + - '\n' + - '[Vue](https://vuejs.org/) est un framework progressif permettant\n' + - 'également de construire des interfaces à partir de composants.\n' + - '\n' + - 'Pour construire des applications plus importantes, Vue est souvent\n' + - 'utilisé avec [Nuxt](https://nuxt.com/).\n' + - '\n' + - '### Angular\n' + - '\n' + - '[Angular](https://angular.dev/) est un framework beaucoup plus complet.\n' + - '\n' + - '## Construire une interface accessible\n' + - '\n' + - 'L\'accessibilité est une partie importante du développement frontend.\n' + - '\n' + - '### Utiliser du HTML sémantique\n' + - '\n' + - 'Une erreur courante consiste à construire toute une interface uniquement\n' + - 'avec des éléments `div`.\n' + - '\n' + - '``` html\n' + - '\n' + - '```\n' + - '\n' + - '### Les images\n' + - '\n' + - 'Les images importantes doivent posséder une description alternative.\n' + - '\n' + - '![Architecture simplifiée d\'une application\n' + - 'web](https://images.example.com/architecture.png)\n' + - '\n' + - '![](https://images.example.com/background-decoration.png)\n' + - '\n' + - '![](https://images.example.com/product-dashboard.png)\n' + - '\n' + - '## Le développement backend\n' + - '\n' + - 'Une application moderne possède généralement une partie backend.\n' + - '\n' + - 'Le backend peut notamment gérer :\n' + - '\n' + - '- l\'authentification ;\n' + - '- les permissions ;\n' + - '- les données ;\n' + - '- les paiements ;\n' + - '- les emails ;\n' + - '- les tâches asynchrones ;\n' + - '- les fichiers.\n' + - '\n' + - '### Les technologies backend\n' + - '\n' + - '1. PHP avec Laravel ;\n' + - '2. JavaScript ou TypeScript avec Node.js ;\n' + - '3. C# avec ASP.NET Core ;\n' + - '4. Java avec Spring Boot ;\n' + - '5. Python avec Django ou FastAPI ;\n' + - '6. Go ;\n' + - '7. Rust.\n' + - '\n' + - '## Les API\n' + - '\n' + - 'Les applications communiquent généralement grâce à des API.\n' + - '\n' + - '### REST\n' + - '\n' + - '``` text\n' + - 'GET /api/users\n' + - 'GET /api/users/42\n' + - 'POST /api/users\n' + - 'PATCH /api/users/42\n' + - 'DELETE /api/users/42\n' + - '```\n' + - '\n' + - '``` json\n' + - '{\n' + - ' "id": 42,\n' + - ' "name": "Alice",\n' + - ' "email": "alice@example.com"\n' + - '}\n' + - '```\n' + - '\n' + - '### GraphQL\n' + - '\n' + - '[GraphQL](https://graphql.org/) propose une autre approche.\n' + - '\n' + - '### gRPC\n' + - '\n' + - 'gRPC est particulièrement utilisé pour les communications entre\n' + - 'services.\n' + - '\n' + - '## Les bases de données\n' + - '\n' + - '### Les bases relationnelles\n' + - '\n' + - '- PostgreSQL ;\n' + - '- MySQL ;\n' + - '- MariaDB ;\n' + - '- SQLite.\n' + - '\n' + - '[PostgreSQL](https://www.postgresql.org/) est particulièrement populaire\n' + - 'pour les applications web modernes.\n' + - '\n' + - '### Les bases NoSQL\n' + - '\n' + - 'MongoDB utilise par exemple des documents.\n' + - '\n' + - 'Redis utilise principalement un modèle clé-valeur et est fréquemment\n' + - 'utilisé pour le cache.\n' + - '\n' + - '### Les bases analytiques\n' + - '\n' + - '[ClickHouse](https://clickhouse.com/) est une base orientée colonnes\n' + - 'particulièrement adaptée aux workloads analytiques.\n' + - '\n' + - '## Les performances\n' + - '\n' + - 'Les performances ont un impact direct sur l\'expérience utilisateur.\n' + - '\n' + - '### Réduire les ressources\n' + - '\n' + - '- code splitting ;\n' + - '- lazy loading ;\n' + - '- tree shaking ;\n' + - '- compression ;\n' + - '- cache ;\n' + - '- CDN.\n' + - '\n' + - '### Optimiser les images\n' + - '\n' + - '![Comparaison entre plusieurs formats\n' + - 'd\'image](https://images.example.com/image-formats.avif)\n' + - '\n' + - '### Utiliser le cache\n' + - '\n' + - '1. navigateur ;\n' + - '2. CDN ;\n' + - '3. serveur ;\n' + - '4. application ;\n' + - '5. base de données.\n' + - '\n' + - '## Le référencement naturel\n' + - '\n' + - 'Le SEO permet d\'améliorer la visibilité d\'un site dans les moteurs de\n' + - 'recherche.\n' + - '\n' + - '### Le titre de la page\n' + - '\n' + - 'Chaque page importante doit posséder un titre descriptif.\n' + - '\n' + - '### La meta description\n' + - '\n' + - 'La description fournit un résumé du contenu.\n' + - '\n' + - '### La structure des titres\n' + - '\n' + - 'Une page doit posséder une hiérarchie cohérente.\n' + - '\n' + - '#### Exemple de sous-section\n' + - '\n' + - 'Cette partie se trouve logiquement sous une section de niveau supérieur.\n' + - '\n' + - '##### Une section encore plus profonde\n' + - '\n' + - 'Il est possible d\'utiliser plusieurs niveaux lorsque la structure du\n' + - 'contenu le nécessite.\n' + - '\n' + - '### Les liens internes\n' + - '\n' + - '[Découvrir nos services](/services)\n' + - '\n' + - '[Consulter notre page de contact](/contact)\n' + - '\n' + - '[Lire notre guide sur les performances](/blog/performance-web)\n' + - '\n' + - '### Les liens externes\n' + - '\n' + - 'Consultez la [documentation MDN](https://developer.mozilla.org/).\n' + - '\n' + - '[Documentation inexistante](https://example.invalid/documentation)\n' + - '\n' + - '## L\'architecture d\'une application moderne\n' + - '\n' + - '``` text\n' + - 'Utilisateur\n' + - ' |\n' + - ' v\n' + - 'CDN\n' + - ' |\n' + - ' v\n' + - 'Frontend\n' + - ' |\n' + - ' v\n' + - 'API\n' + - ' |\n' + - ' +--------> Redis\n' + - ' |\n' + - ' +--------> PostgreSQL\n' + - ' |\n' + - ' +--------> Object Storage\n' + - ' |\n' + - ' +--------> Queue\n' + - ' |\n' + - ' v\n' + - ' Workers\n' + - '```\n' + - '\n' + - '## Le déploiement\n' + - '\n' + - 'Une fois l\'application développée, elle doit être déployée sur une\n' + - 'infrastructure accessible depuis Internet.\n' + - '\n' + - '### Les plateformes cloud\n' + - '\n' + - 'Elles peuvent automatiquement gérer :\n' + - '\n' + - '- les builds ;\n' + - '- les certificats HTTPS ;\n' + - '- les domaines ;\n' + - '- les déploiements continus ;\n' + - '- certaines fonctions serveur.\n' + - '\n' + - '### Les VPS\n' + - '\n' + - 'Un serveur privé virtuel offre davantage de contrôle.\n' + - '\n' + - '## Docker\n' + - '\n' + - 'Docker permet d\'exécuter une application dans des conteneurs.\n' + - '\n' + - '``` yaml\n' + - 'services:\n' + - ' app:\n' + - ' build: .\n' + - '\n' + - ' postgres:\n' + - ' image: postgres:17\n' + - '\n' + - ' redis:\n' + - ' image: redis:7\n' + - '\n' + - ' worker:\n' + - ' build: .\n' + - '```\n' + - '\n' + - '## La sécurité\n' + - '\n' + - '### Authentification\n' + - '\n' + - 'Les mots de passe ne doivent jamais être enregistrés directement en\n' + - 'clair.\n' + - '\n' + - '### Autorisation\n' + - '\n' + - 'Être authentifié ne signifie pas automatiquement avoir accès à toutes\n' + - 'les ressources.\n' + - '\n' + - '### Validation des données\n' + - '\n' + - 'Les données provenant d\'un utilisateur doivent toujours être considérées\n' + - 'comme non fiables.\n' + - '\n' + - '## Tests\n' + - '\n' + - '### Tests unitaires\n' + - '\n' + - 'Les tests unitaires vérifient généralement une petite unité de logique.\n' + - '\n' + - '### Tests d\'intégration\n' + - '\n' + - 'Les tests d\'intégration vérifient le fonctionnement de plusieurs\n' + - 'composants ensemble.\n' + - '\n' + - '### Tests end-to-end\n' + - '\n' + - '1. ouvrir la page de connexion ;\n' + - '2. saisir un email ;\n' + - '3. saisir un mot de passe ;\n' + - '4. cliquer sur le bouton de connexion ;\n' + - '5. vérifier que le dashboard apparaît.\n' + - '\n' + - '## Monitoring et observabilité\n' + - '\n' + - 'Plusieurs informations peuvent être surveillées :\n' + - '\n' + - '- utilisation CPU ;\n' + - '- mémoire ;\n' + - '- temps de réponse ;\n' + - '- taux d\'erreur ;\n' + - '- requêtes par seconde ;\n' + - '- jobs en attente ;\n' + - '- disponibilité des services.\n' + - '\n' + - '## Une architecture doit rester proportionnée\n' + - '\n' + - '> La meilleure architecture n\'est pas celle qui utilise le plus de\n' + - '> technologies, mais celle qui répond correctement aux contraintes du\n' + - '> projet.\n' + - '\n' + - '###### Choisir ses technologies\n' + - '\n' + - ' -----------------------------------------------------------------------\n' + - ' Critère Question\n' + - ' ----------------------------------- -----------------------------------\n' + - ' Performance Cette technologie répond-elle aux\n' + - ' besoins réels ?\n' + - '\n' + - ' Écosystème Existe-t-il suffisamment de\n' + - ' bibliothèques ?\n' + - '\n' + - ' Recrutement Peut-on trouver facilement des\n' + - ' développeurs ?\n' + - '\n' + - ' Maintenance Le projet sera-t-il maintenable\n' + - ' dans plusieurs années ?\n' + - '\n' + - ' Documentation La documentation est-elle\n' + - ' suffisamment complète ?\n' + - '\n' + - ' Sécurité Les mises à jour sont-elles\n' + - ' régulières ?\n' + - ' -----------------------------------------------------------------------\n' + - '\n' + - '# Conclusion\n' + - '\n' + - 'Le développement web moderne couvre un domaine extrêmement large.\n' + - '\n' + - 'Un développeur n\'a pas besoin de maîtriser immédiatement toutes les\n' + - 'technologies existantes. Il est généralement plus important de\n' + - 'comprendre les concepts fondamentaux derrière ces outils.\n' + - '\n' + - 'HTML reste responsable de la structure.\n' + - '\n' + - 'CSS reste responsable de la présentation.\n' + - '\n' + - 'JavaScript permet de construire des interactions complexes.\n' + - '\n' + - 'Les frameworks facilitent l\'organisation des applications.\n' + - '\n' + - 'Les bases de données permettent de conserver les informations.\n' + - '\n' + - 'Enfin, les performances, l\'accessibilité, la sécurité et le\n' + - 'référencement doivent être considérés comme des éléments importants du\n' + - 'développement d\'un produit web.\n' + - '\n' + - 'Pour continuer votre apprentissage, consultez notre [guide du\n' + - 'frontend](/guides/frontend), notre [guide du backend](/guides/backend)\n' + - 'ou [MDN Web Docs](https://developer.mozilla.org/).\n', { - registerDefaultPlugins: false, - plugins: [ - seo({language: 'fra'}), - ] +import seo from "../src/index.js"; + +const tree = await parseMarkdown("# Le guide complet du développement web moderne en 2026\n" + + "\n" + + "Le développement web moderne ne consiste plus simplement à créer\n" + + "quelques pages HTML accompagnées d'une feuille de style. Les\n" + + "applications actuelles combinent souvent plusieurs technologies pour\n" + + "gérer l'interface utilisateur, les données, l'authentification, les\n" + + "performances et le déploiement.\n" + + "\n" + + "Pour construire une application robuste, il est important de comprendre\n" + + "les différentes couches qui composent une architecture web moderne.\n" + + "\n" + + "Ce guide présente les principaux concepts à connaître ainsi que les\n" + + "technologies couramment utilisées par les développeurs.\n" + + "\n" + + "![Un développeur travaillant sur une application\n" + + "web](https://images.example.com/developer.jpg)\n" + + "\n" + + "## Les fondamentaux du Web\n" + + "\n" + + "Le Web repose historiquement sur trois technologies principales :\n" + + "\n" + + "- HTML\n" + "- CSS\n" + + "- JavaScript\n" + + "\n" + + "Chacune possède un rôle différent dans le fonctionnement d'une page.\n" + + "\n" + + "### HTML et la structure des documents\n" + + "\n" + + "HTML permet de définir la structure et la sémantique d'une page.\n" + + "\n" + + "Un document correctement structuré utilise des éléments adaptés au\n" + + "contenu qu'il représente.\n" + + "\n" + + "### CSS et la présentation\n" + + "\n" + + "CSS contrôle l'apparence d'un document.\n" + + "\n" + + "Les développeurs peuvent notamment modifier :\n" + + "\n" + + "- les couleurs ;\n" + + "- les espacements ;\n" + + "- les polices ;\n" + + "- les dimensions ;\n" + + "- les animations ;\n" + + "- le positionnement ;\n" + + "- les layouts.\n" + + "\n" + + "Les fonctionnalités modernes comme **Flexbox** et **CSS Grid**\n" + + "permettent de construire des interfaces complexes sans utiliser les\n" + + "anciennes techniques basées sur `float`.\n" + + "\n" + + "![Exemple d'une interface utilisant CSS\n" + + "Grid](https://images.example.com/css-grid.png)\n" + + "\n" + + "### JavaScript et les interactions\n" + + "\n" + + "JavaScript permet d'ajouter des comportements dynamiques aux pages.\n" + + "\n" + + "``` js\n" + + 'const message = "Hello World"\n' + + "\n" + + "console.log(message)\n" + + "```\n" + + "\n" + + "## Les frameworks frontend\n" + + "\n" + + "Lorsque les interfaces deviennent complexes, organiser l'ensemble du\n" + + "JavaScript devient rapidement difficile.\n" + + "\n" + + "### React\n" + + "\n" + + "[React](https://react.dev/) est une bibliothèque développée initialement\n" + + "par Meta.\n" + + "\n" + + "React repose sur une approche basée sur les composants.\n" + + "\n" + + "### Vue\n" + + "\n" + + "[Vue](https://vuejs.org/) est un framework progressif permettant\n" + + "également de construire des interfaces à partir de composants.\n" + + "\n" + + "Pour construire des applications plus importantes, Vue est souvent\n" + + "utilisé avec [Nuxt](https://nuxt.com/).\n" + + "\n" + + "### Angular\n" + + "\n" + + "[Angular](https://angular.dev/) est un framework beaucoup plus complet.\n" + + "\n" + + "## Construire une interface accessible\n" + + "\n" + + "L'accessibilité est une partie importante du développement frontend.\n" + + "\n" + + "### Utiliser du HTML sémantique\n" + + "\n" + + "Une erreur courante consiste à construire toute une interface uniquement\n" + + "avec des éléments `div`.\n" + + "\n" + + "``` html\n" + + "\n" + + "```\n" + + "\n" + + "### Les images\n" + + "\n" + + "Les images importantes doivent posséder une description alternative.\n" + + "\n" + + "![Architecture simplifiée d'une application\n" + + "web](https://images.example.com/architecture.png)\n" + + "\n" + + "![](https://images.example.com/background-decoration.png)\n" + + "\n" + + "![](https://images.example.com/product-dashboard.png)\n" + + "\n" + + "## Le développement backend\n" + + "\n" + + "Une application moderne possède généralement une partie backend.\n" + + "\n" + + "Le backend peut notamment gérer :\n" + + "\n" + + "- l'authentification ;\n" + + "- les permissions ;\n" + + "- les données ;\n" + + "- les paiements ;\n" + + "- les emails ;\n" + + "- les tâches asynchrones ;\n" + + "- les fichiers.\n" + + "\n" + + "### Les technologies backend\n" + + "\n" + + "1. PHP avec Laravel ;\n" + + "2. JavaScript ou TypeScript avec Node.js ;\n" + + "3. C# avec ASP.NET Core ;\n" + + "4. Java avec Spring Boot ;\n" + + "5. Python avec Django ou FastAPI ;\n" + + "6. Go ;\n" + + "7. Rust.\n" + + "\n" + + "## Les API\n" + + "\n" + + "Les applications communiquent généralement grâce à des API.\n" + + "\n" + + "### REST\n" + + "\n" + + "``` text\n" + + "GET /api/users\n" + + "GET /api/users/42\n" + + "POST /api/users\n" + + "PATCH /api/users/42\n" + + "DELETE /api/users/42\n" + + "```\n" + + "\n" + + "``` json\n" + + "{\n" + + ' "id": 42,\n' + + ' "name": "Alice",\n' + + ' "email": "alice@example.com"\n' + + "}\n" + + "```\n" + + "\n" + + "### GraphQL\n" + + "\n" + + "[GraphQL](https://graphql.org/) propose une autre approche.\n" + + "\n" + + "### gRPC\n" + + "\n" + + "gRPC est particulièrement utilisé pour les communications entre\n" + + "services.\n" + + "\n" + + "## Les bases de données\n" + + "\n" + + "### Les bases relationnelles\n" + + "\n" + + "- PostgreSQL ;\n" + + "- MySQL ;\n" + + "- MariaDB ;\n" + + "- SQLite.\n" + + "\n" + + "[PostgreSQL](https://www.postgresql.org/) est particulièrement populaire\n" + + "pour les applications web modernes.\n" + + "\n" + + "### Les bases NoSQL\n" + + "\n" + + "MongoDB utilise par exemple des documents.\n" + + "\n" + + "Redis utilise principalement un modèle clé-valeur et est fréquemment\n" + + "utilisé pour le cache.\n" + + "\n" + + "### Les bases analytiques\n" + + "\n" + + "[ClickHouse](https://clickhouse.com/) est une base orientée colonnes\n" + + "particulièrement adaptée aux workloads analytiques.\n" + + "\n" + + "## Les performances\n" + + "\n" + + "Les performances ont un impact direct sur l'expérience utilisateur.\n" + + "\n" + + "### Réduire les ressources\n" + + "\n" + + "- code splitting ;\n" + + "- lazy loading ;\n" + + "- tree shaking ;\n" + + "- compression ;\n" + + "- cache ;\n" + + "- CDN.\n" + + "\n" + + "### Optimiser les images\n" + + "\n" + + "![Comparaison entre plusieurs formats\n" + + "d'image](https://images.example.com/image-formats.avif)\n" + + "\n" + + "### Utiliser le cache\n" + + "\n" + + "1. navigateur ;\n" + + "2. CDN ;\n" + + "3. serveur ;\n" + + "4. application ;\n" + + "5. base de données.\n" + + "\n" + + "## Le référencement naturel\n" + + "\n" + + "Le SEO permet d'améliorer la visibilité d'un site dans les moteurs de\n" + + "recherche.\n" + + "\n" + + "### Le titre de la page\n" + + "\n" + + "Chaque page importante doit posséder un titre descriptif.\n" + + "\n" + + "### La meta description\n" + + "\n" + + "La description fournit un résumé du contenu.\n" + + "\n" + + "### La structure des titres\n" + + "\n" + + "Une page doit posséder une hiérarchie cohérente.\n" + + "\n" + + "#### Exemple de sous-section\n" + + "\n" + + "Cette partie se trouve logiquement sous une section de niveau supérieur.\n" + + "\n" + + "##### Une section encore plus profonde\n" + + "\n" + + "Il est possible d'utiliser plusieurs niveaux lorsque la structure du\n" + + "contenu le nécessite.\n" + + "\n" + + "### Les liens internes\n" + + "\n" + + "[Découvrir nos services](/services)\n" + + "\n" + + "[Consulter notre page de contact](/contact)\n" + + "\n" + + "[Lire notre guide sur les performances](/blog/performance-web)\n" + + "\n" + + "### Les liens externes\n" + + "\n" + + "Consultez la [documentation MDN](https://developer.mozilla.org/).\n" + + "\n" + + "[Documentation inexistante](https://example.invalid/documentation)\n" + + "\n" + + "## L'architecture d'une application moderne\n" + + "\n" + + "``` text\n" + + "Utilisateur\n" + + " |\n" + + " v\n" + + "CDN\n" + + " |\n" + + " v\n" + + "Frontend\n" + + " |\n" + + " v\n" + + "API\n" + + " |\n" + + " +--------> Redis\n" + + " |\n" + + " +--------> PostgreSQL\n" + + " |\n" + + " +--------> Object Storage\n" + + " |\n" + + " +--------> Queue\n" + + " |\n" + + " v\n" + + " Workers\n" + + "```\n" + + "\n" + + "## Le déploiement\n" + + "\n" + + "Une fois l'application développée, elle doit être déployée sur une\n" + + "infrastructure accessible depuis Internet.\n" + + "\n" + + "### Les plateformes cloud\n" + + "\n" + + "Elles peuvent automatiquement gérer :\n" + + "\n" + + "- les builds ;\n" + + "- les certificats HTTPS ;\n" + + "- les domaines ;\n" + + "- les déploiements continus ;\n" + + "- certaines fonctions serveur.\n" + + "\n" + + "### Les VPS\n" + + "\n" + + "Un serveur privé virtuel offre davantage de contrôle.\n" + + "\n" + + "## Docker\n" + + "\n" + + "Docker permet d'exécuter une application dans des conteneurs.\n" + + "\n" + + "``` yaml\n" + + "services:\n" + + " app:\n" + + " build: .\n" + + "\n" + + " postgres:\n" + + " image: postgres:17\n" + + "\n" + + " redis:\n" + + " image: redis:7\n" + + "\n" + + " worker:\n" + + " build: .\n" + + "```\n" + + "\n" + + "## La sécurité\n" + + "\n" + + "### Authentification\n" + + "\n" + + "Les mots de passe ne doivent jamais être enregistrés directement en\n" + + "clair.\n" + + "\n" + + "### Autorisation\n" + + "\n" + + "Être authentifié ne signifie pas automatiquement avoir accès à toutes\n" + + "les ressources.\n" + + "\n" + + "### Validation des données\n" + + "\n" + + "Les données provenant d'un utilisateur doivent toujours être considérées\n" + + "comme non fiables.\n" + + "\n" + + "## Tests\n" + + "\n" + + "### Tests unitaires\n" + + "\n" + + "Les tests unitaires vérifient généralement une petite unité de logique.\n" + + "\n" + + "### Tests d'intégration\n" + + "\n" + + "Les tests d'intégration vérifient le fonctionnement de plusieurs\n" + + "composants ensemble.\n" + + "\n" + + "### Tests end-to-end\n" + + "\n" + + "1. ouvrir la page de connexion ;\n" + + "2. saisir un email ;\n" + + "3. saisir un mot de passe ;\n" + + "4. cliquer sur le bouton de connexion ;\n" + + "5. vérifier que le dashboard apparaît.\n" + + "\n" + + "## Monitoring et observabilité\n" + + "\n" + + "Plusieurs informations peuvent être surveillées :\n" + + "\n" + + "- utilisation CPU ;\n" + + "- mémoire ;\n" + + "- temps de réponse ;\n" + + "- taux d'erreur ;\n" + + "- requêtes par seconde ;\n" + + "- jobs en attente ;\n" + + "- disponibilité des services.\n" + + "\n" + + "## Une architecture doit rester proportionnée\n" + + "\n" + + "> La meilleure architecture n'est pas celle qui utilise le plus de\n" + + "> technologies, mais celle qui répond correctement aux contraintes du\n" + + "> projet.\n" + + "\n" + + "###### Choisir ses technologies\n" + + "\n" + + " -----------------------------------------------------------------------\n" + + " Critère Question\n" + + " ----------------------------------- -----------------------------------\n" + + " Performance Cette technologie répond-elle aux\n" + + " besoins réels ?\n" + + "\n" + + " Écosystème Existe-t-il suffisamment de\n" + + " bibliothèques ?\n" + + "\n" + + " Recrutement Peut-on trouver facilement des\n" + + " développeurs ?\n" + + "\n" + + " Maintenance Le projet sera-t-il maintenable\n" + + " dans plusieurs années ?\n" + + "\n" + + " Documentation La documentation est-elle\n" + + " suffisamment complète ?\n" + + "\n" + + " Sécurité Les mises à jour sont-elles\n" + + " régulières ?\n" + + " -----------------------------------------------------------------------\n" + + "\n" + + "# Conclusion\n" + + "\n" + + "Le développement web moderne couvre un domaine extrêmement large.\n" + + "\n" + + "Un développeur n'a pas besoin de maîtriser immédiatement toutes les\n" + + "technologies existantes. Il est généralement plus important de\n" + + "comprendre les concepts fondamentaux derrière ces outils.\n" + + "\n" + + "HTML reste responsable de la structure.\n" + + "\n" + + "CSS reste responsable de la présentation.\n" + + "\n" + + "JavaScript permet de construire des interactions complexes.\n" + + "\n" + + "Les frameworks facilitent l'organisation des applications.\n" + + "\n" + + "Les bases de données permettent de conserver les informations.\n" + + "\n" + + "Enfin, les performances, l'accessibilité, la sécurité et le\n" + + "référencement doivent être considérés comme des éléments importants du\n" + + "développement d'un produit web.\n" + + "\n" + + "Pour continuer votre apprentissage, consultez notre [guide du\n" + + "frontend](/guides/frontend), notre [guide du backend](/guides/backend)\n" + + "ou [MDN Web Docs](https://developer.mozilla.org/).\n", { + registerDefaultPlugins: false, + plugins: [ + seo({ language: "fra" }), + ], }); -console.log(tree.meta.seo) \ No newline at end of file +console.warn(tree.meta.seo); diff --git a/src/constants.ts b/src/constants.ts index b7c031a..0d0aa2b 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,67 +1,67 @@ export const frenchStopWords = new Set([ - "à", "au", "aux", - "avec", - "ce", "ces", "cette", - "dans", "de", "des", "du", - "elle", "elles", "en", "et", "eux", - "il", "ils", - "je", - "la", "le", "les", "leur", "leurs", "lui", - "ma", "mais", "me", "mes", "moi", "mon", - "ne", "nos", "notre", "nous", - "on", "ou", - "par", "pas", "pour", - "qu", "que", "qui", - "sa", "se", "ses", "son", "sur", - "ta", "te", "tes", "toi", "ton", "tu", - "un", "une", - "vos", "votre", "vous", - "y" + "à", "au", "aux", + "avec", + "ce", "ces", "cette", + "dans", "de", "des", "du", + "elle", "elles", "en", "et", "eux", + "il", "ils", + "je", + "la", "le", "les", "leur", "leurs", "lui", + "ma", "mais", "me", "mes", "moi", "mon", + "ne", "nos", "notre", "nous", + "on", "ou", + "par", "pas", "pour", + "qu", "que", "qui", + "sa", "se", "ses", "son", "sur", + "ta", "te", "tes", "toi", "ton", "tu", + "un", "une", + "vos", "votre", "vous", + "y", ]); export const englishStopWords = new Set([ - "a", "an", "the", - "and", "or", "but", - "as", "at", "by", - "for", "from", - "in", "into", - "of", "on", "onto", - "to", "with", "without", - "about", "above", "after", "before", "below", "between", - "during", "over", "under", + "a", "an", "the", + "and", "or", "but", + "as", "at", "by", + "for", "from", + "in", "into", + "of", "on", "onto", + "to", "with", "without", + "about", "above", "after", "before", "below", "between", + "during", "over", "under", - "i", "me", "my", "mine", - "you", "your", "yours", - "he", "him", "his", - "she", "her", "hers", - "it", "its", - "we", "us", "our", "ours", - "they", "them", "their", "theirs", + "i", "me", "my", "mine", + "you", "your", "yours", + "he", "him", "his", + "she", "her", "hers", + "it", "its", + "we", "us", "our", "ours", + "they", "them", "their", "theirs", - "this", "that", "these", "those", - "who", "whom", "which", "what", - "where", "when", "why", "how", + "this", "that", "these", "those", + "who", "whom", "which", "what", + "where", "when", "why", "how", - "is", "am", "are", - "was", "were", - "be", "been", "being", - "do", "does", "did", - "have", "has", "had", + "is", "am", "are", + "was", "were", + "be", "been", "being", + "do", "does", "did", + "have", "has", "had", - "can", "could", - "will", "would", - "shall", "should", - "may", "might", "must", + "can", "could", + "will", "would", + "shall", "should", + "may", "might", "must", - "not", "no", "nor", - "so", "too", "very", - "if", "then", "than", - "because", "while", + "not", "no", "nor", + "so", "too", "very", + "if", "then", "than", + "because", "while", - "some", "any", "all", - "each", "every", "both", - "few", "more", "most", - "other", "such", + "some", "any", "all", + "each", "every", "both", + "few", "more", "most", + "other", "such", - "here", "there" -]); \ No newline at end of file + "here", "there", +]); diff --git a/src/rules/content.ts b/src/rules/content.ts index 47046ec..357acc6 100644 --- a/src/rules/content.ts +++ b/src/rules/content.ts @@ -1,27 +1,31 @@ -import { Analytics } from "../types.js"; import type { Node } from "comark"; +import type { Analytics } from "../types.js"; + // We exclude this type of word bc it's polute the real word count -const excludeWordCount = new Set(['pre', 'code']); +const excludeWordCount = new Set(["pre", "code"]); export const contentRule = (analytics: Analytics, node: Node, stoppingWords: Set, previousHeading: { - value: string + value: string; }, wordCounts: Map, browse: (node: Node, analytics: Analytics, previousHeading: { value: string }, stoppingWords: Set, wordCounts: Map) => void) => { - for (let i = 2; i < node.length; i++) { - const child = node[i]; - - if (Array.isArray(child)) { - browse(child, analytics, previousHeading, stoppingWords, wordCounts) - } else if (typeof child === "string") { - if (excludeWordCount.has(node[0] as string)) continue; - const words = child.split(/[ .:;?!~,`"&|()—<>{}\[\]\r\n/\\]+/).filter((w) => w !== '') - analytics.content.words += words.length - - words.forEach((word: string) => { - const w = word.toLocaleLowerCase(); - if (stoppingWords.has(w)) return; - wordCounts.set(w, (wordCounts.get(w) ?? 0) + 1) - }) - } + for (let i = 2; i < node.length; i++) { + const child = node[i]; + + if (Array.isArray(child)) { + browse(child, analytics, previousHeading, stoppingWords, wordCounts); + } else if (typeof child === "string") { + if (excludeWordCount.has(node[0] as string)) continue; + + const words = child.split(/[ .:;?!~,`"&|()—<>{}[\]\r\n/\\]+/).filter((w) => w !== ""); + + analytics.content.words += words.length; + + words.forEach((word: string) => { + const w = word.toLocaleLowerCase(); + + if (stoppingWords.has(w)) return; + wordCounts.set(w, (wordCounts.get(w) ?? 0) + 1); + }); } -} \ No newline at end of file + } +}; diff --git a/src/rules/heading.ts b/src/rules/heading.ts index d1d1bf8..d3eb5b7 100644 --- a/src/rules/heading.ts +++ b/src/rules/heading.ts @@ -1,49 +1,48 @@ -import { Analytics } from "../types.js"; -import { createIssue } from "../utils/issue.js"; import type { Node } from "comark"; + +import type { Analytics } from "../types.js"; import { flatten } from "../utils/flatten.js"; +import { createIssue } from "../utils/issue.js"; export const headingRule = (previousHeading: { value: string }, node: Node, analytics: Analytics) => { + const currentHeading = node[0] as string; - let currentHeading = node[0] as string; + const text = flatten(node).trim(); - const text = flatten(node).trim() - if (text.length > 60) { - createIssue({ reason: "heading-too-long", from: currentHeading, text }, analytics) - } + if (text.length > 60) { + createIssue({ reason: "heading-too-long", from: currentHeading, text }, analytics); + } - if (currentHeading === "h1") { - analytics.headings.h1Count++; - } - analytics.headings.count++; + if (currentHeading === "h1") { + analytics.headings.h1Count++; + } + analytics.headings.count++; - if (previousHeading.value) { - isHierarchyValid(previousHeading.value, currentHeading, analytics) - } - previousHeading.value = currentHeading; - -} + if (previousHeading.value) { + isHierarchyValid(previousHeading.value, currentHeading, analytics); + } + previousHeading.value = currentHeading; +}; const isHierarchyValid = (firstValue: string, secondValue: string, analytics: Analytics) => { - - const headingValue: Record = { - "h1": 1, - "h2": 2, - "h3": 3, - "h4": 4, - "h5": 5, - "h6": 6 - } - - if (headingValue[firstValue] === undefined || headingValue[secondValue] === undefined) { - createIssue({reason: "invalid-heading"}, analytics); - analytics.headings.hierarchyValid = false - return; - } - if ((headingValue[secondValue] - headingValue[firstValue]) > 1) { - createIssue({reason: 'heading-hierarchy', from: firstValue, to: secondValue}, analytics) - analytics.headings.hierarchyValid = false; - } - + const headingValue: Record = { + h1: 1, + h2: 2, + h3: 3, + h4: 4, + h5: 5, + h6: 6, + }; + + if (headingValue[firstValue] === undefined || headingValue[secondValue] === undefined) { + createIssue({ reason: "invalid-heading" }, analytics); + analytics.headings.hierarchyValid = false; return; -} \ No newline at end of file + } + if ((headingValue[secondValue] - headingValue[firstValue]) > 1) { + createIssue({ reason: "heading-hierarchy", from: firstValue, to: secondValue }, analytics); + analytics.headings.hierarchyValid = false; + } + + return; +}; diff --git a/src/rules/image.ts b/src/rules/image.ts index b3d55ad..31a312b 100644 --- a/src/rules/image.ts +++ b/src/rules/image.ts @@ -1,15 +1,18 @@ -import { Analytics, ImageMissing, ImageNode } from "../types.js"; +import type { Analytics, ImageNode } from "../types.js"; import { createIssue } from "../utils/issue.js"; export const imageRule = (node: ImageNode, analytics: Analytics) => { - analytics.images.count++; - if (node[1].alt === undefined || node[1].alt === null) { - analytics.images.missingAlt++; - createIssue({reason: "missing-alt", src: node[1].src}, analytics) - } - const { width, height, src } = node[1] - if (!width || !height) { - const missing = !width && !height ? "both" : !width ? "width" : "height" - createIssue({ reason: "missing-dimensions", src, missing }, analytics) - } -} \ No newline at end of file + analytics.images.count++; + if (node[1].alt === undefined || node[1].alt === null) { + analytics.images.missingAlt++; + createIssue({ reason: "missing-alt", src: node[1].src }, analytics); + } + + const { width, height, src } = node[1]; + + if (!width || !height) { + const missing = !width && !height ? "both" : !width ? "width" : "height"; + + createIssue({ reason: "missing-dimensions", src, missing }, analytics); + } +}; diff --git a/src/rules/link.ts b/src/rules/link.ts index f9cfd92..877a240 100644 --- a/src/rules/link.ts +++ b/src/rules/link.ts @@ -1,39 +1,40 @@ -import { Analytics, Issue, LinkNode, LinkType } from "../types.js"; -import { createIssue } from "../utils/issue.js"; +import type { Analytics, Issue, LinkNode, LinkType } from "../types.js"; import { flatten } from "../utils/flatten.js"; +import { createIssue } from "../utils/issue.js"; const linkRegex = new RegExp("^https?:\\/\\/(?:www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\\.[a-zA-Z0-9()]{1,63}\\b[-a-zA-Z0-9()@:%_+.~#?&\\/=]*$"); const mailToRegex = new RegExp("^mailto:", "i"); const telRegex = new RegExp("^tel:", "i"); export const linkRule = (node: LinkNode, analytics: Analytics) => { - analytics.links.count++; - if (node[1].href) { - let link = node[1].href; + analytics.links.count++; + if (node[1].href) { + const link = node[1].href; + + const type = guessLinkType(link); - const type = guessLinkType(link) - if (type === "invalid") createInvalidUrlIssue({reason: "invalid-link", href: link}, analytics); - else if (type === "external") analytics.links.external++ - else if (type === "internal") analytics.links.internal++ - else analytics.links.special[type]++ + if (type === "invalid") createInvalidUrlIssue({ reason: "invalid-link", href: link }, analytics); + else if (type === "external") analytics.links.external++; + else if (type === "internal") analytics.links.internal++; + else analytics.links.special[type]++; + } else { + const text = flatten(node).trim(); - } else { - const text = flatten(node).trim(); - createInvalidUrlIssue({reason:"missing-url", text}, analytics) - } -} + createInvalidUrlIssue({ reason: "missing-url", text }, analytics); + } +}; const guessLinkType = (url: string): LinkType => { - if(url.startsWith("#")) return "anchor" - if(mailToRegex.test(url)) return "emails"; - if(telRegex.test(url)) return "phone"; - if (linkRegex.test(url)) return "external"; - if (/^[a-z][a-z0-9+.-]*:/i.test(url)) return "invalid" - if (url.startsWith("//")) return "external" - return "internal" -} + if (url.startsWith("#")) return "anchor"; + if (mailToRegex.test(url)) return "emails"; + if (telRegex.test(url)) return "phone"; + if (linkRegex.test(url)) return "external"; + if (/^[a-z][a-z0-9+.-]*:/i.test(url)) return "invalid"; + if (url.startsWith("//")) return "external"; + return "internal"; +}; -const createInvalidUrlIssue = (type: Extract, analytics: Analytics) => { - analytics.links.invalid++; - createIssue({...type}, analytics) -} \ No newline at end of file +const createInvalidUrlIssue = (type: Extract, analytics: Analytics) => { + analytics.links.invalid++; + createIssue({ ...type }, analytics); +}; diff --git a/src/types.ts b/src/types.ts index 61773f6..356453d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,118 +1,118 @@ import type { ElementNodeAttributes, Node } from "comark"; /** Available lang for stopping words */ -type Language = "fra" | "eng" +type Language = "fra" | "eng"; -export type ComarkSeoOptions = { - /** +export interface ComarkSeoOptions { + /** * Set to false for disable the plugin * @default true * */ - enabled?: boolean; + enabled?: boolean; - /** If define use the stopping words array for repeatedWords + /** If define use the stopping words array for repeatedWords * @enum {fra,eng} */ - language?: Language + language?: Language; - readingSpeed?: number + readingSpeed?: number; } export interface ComarkSeoMeta { - seo: Analytics + seo: Analytics; } -export type Analytics = { - headings: HeadingAnalytics; - content: ContentAnalytics; - links: LinksAnalytics; - images: ImagesAnalytics; - issues: Issue[]; +export interface Analytics { + headings: HeadingAnalytics; + content: ContentAnalytics; + links: LinksAnalytics; + images: ImagesAnalytics; + issues: Issue[]; } -export type HeadingAnalytics = { - h1Count: number; - count: number; - hierarchyValid: boolean -}; +export interface HeadingAnalytics { + h1Count: number; + count: number; + hierarchyValid: boolean; +} /** A word kept in `repeatedWords`, with the number of times it appears. */ -export type RepeatedWord = { - word: string; - count: number; -}; +export interface RepeatedWord { + word: string; + count: number; +} -export type ContentAnalytics = { - words: number; +export interface ContentAnalytics { + words: number; - /** Words appearing more than once, sorted by descending count then alphabetically. + /** Words appearing more than once, sorted by descending count then alphabetically. * Stop words are excluded when `language` is set. */ - repeatedWords: RepeatedWord[]; + repeatedWords: RepeatedWord[]; - /** How many time your document take min to be read + /** How many time your document take min to be read * @type number * @example 5 * */ - readingTime: number; -}; + readingTime: number; +} -export type LinksAnalytics = { - count: number; - internal: number; - external: number; - special: { - anchor: number; - emails: number; - phone: number; - } - invalid: number; +export interface LinksAnalytics { + count: number; + internal: number; + external: number; + special: { + anchor: number; + emails: number; + phone: number; + }; + invalid: number; } -export type ImagesAnalytics = { - count: number; - missingAlt: number; +export interface ImagesAnalytics { + count: number; + missingAlt: number; } /** * Describe the type of issue your seo can have */ -export type Issue = - | { - reason: "missing-heading-one" -} - | { +export type Issue + = | { + reason: "missing-heading-one"; + } + | { reason: "heading-hierarchy"; from: string; to: string; -} | - { - reason: "invalid-heading"; - } - | { + } + | { + reason: "invalid-heading"; + } + | { reason: "missing-alt"; src: string; -} - | { + } + | { reason: "invalid-link"; href: string; -} - | { + } + | { reason: "multiple-h1"; count: number; -} -| { - reason: "missing-dimensions", - src: string, - missing: "height" | "width" | "both" -} -| { - reason: "heading-too-long", - from: string - text: string -} -| { - reason: "missing-url", - text?: string -} + } + | { + reason: "missing-dimensions"; + src: string; + missing: "height" | "width" | "both"; + } + | { + reason: "heading-too-long"; + from: string; + text: string; + } + | { + reason: "missing-url"; + text?: string; + }; /** Element node whose attributes bag is narrowed to the keys a rule reads. */ export type TypedElementNode = [string, ElementNodeAttributes & A, ...Node[]]; @@ -120,12 +120,11 @@ export type TypedElementNode = [string, ElementNodeAttributes & A, ...Node[]] export type LinkNode = TypedElementNode<{ href?: string }>; export type ImageNode = TypedElementNode<{ - src: string; - alt?: string; - width?: string | number; - height?: string | number; + src: string; + alt?: string; + width?: string | number; + height?: string | number; }>; - -export type ImageMissing = "height" | "width" | "both" -export type LinkType = "external" | "internal" | "anchor" | "emails" | "phone" | "invalid" \ No newline at end of file +export type ImageMissing = "height" | "width" | "both"; +export type LinkType = "external" | "internal" | "anchor" | "emails" | "phone" | "invalid"; diff --git a/src/utils/flatten.ts b/src/utils/flatten.ts index f550fc0..9003edd 100644 --- a/src/utils/flatten.ts +++ b/src/utils/flatten.ts @@ -1,5 +1,6 @@ -import { Node } from "comark"; +import type { Node } from "comark"; export const flatten = (node: Node): string => - typeof node === "string" ? node - : (node as Node[]).slice(2).map(flatten).join("") \ No newline at end of file + typeof node === "string" + ? node + : (node as Node[]).slice(2).map(flatten).join(""); diff --git a/src/utils/issue.ts b/src/utils/issue.ts index 2107b61..517f9cc 100644 --- a/src/utils/issue.ts +++ b/src/utils/issue.ts @@ -1,5 +1,5 @@ -import { Analytics, Issue } from "../types.js"; +import type { Analytics, Issue } from "../types.js"; export const createIssue = (issue: Issue, analytics: Analytics) => { - analytics.issues.push(issue); -} \ No newline at end of file + analytics.issues.push(issue); +}; diff --git a/tsdown.config.ts b/tsdown.config.ts index 7b12c94..fd8ab1c 100644 --- a/tsdown.config.ts +++ b/tsdown.config.ts @@ -1,7 +1,7 @@ -import { defineConfig } from 'tsdown' +import { defineConfig } from "tsdown"; export default defineConfig({ - entry: ['src/index.ts'], - format: ['esm',], - dts: true, -}) + entry: ["src/index.ts"], + format: ["esm"], + dts: true, +}); From 70e4c051a0556fc37365e2473022b5623d184ca7 Mon Sep 17 00:00:00 2001 From: "C.Nelhomme" <64921289+D3ller@users.noreply.github.com> Date: Thu, 15 Oct 2026 23:33:56 +0200 Subject: [PATCH 4/7] build: add husky hooks to lint on commit and test on push --- .husky/pre-commit | 1 + .husky/pre-push | 2 ++ package.json | 8 ++++++- pnpm-lock.yaml | 55 +++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 .husky/pre-commit create mode 100644 .husky/pre-push diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..5ee7abd --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +pnpm exec lint-staged diff --git a/.husky/pre-push b/.husky/pre-push new file mode 100644 index 0000000..4226722 --- /dev/null +++ b/.husky/pre-push @@ -0,0 +1,2 @@ +pnpm typecheck +pnpm test diff --git a/package.json b/package.json index e419959..6df3079 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,8 @@ "test": "vitest run", "test:watch": "vitest", "lint": "eslint .", - "lint:fix": "eslint . --fix" + "lint:fix": "eslint . --fix", + "prepare": "husky" }, "peerDependencies": { "comark": ">=0.4.0" @@ -52,10 +53,15 @@ "comark": "^0.7.0", "eslint": "^10.12.0", "eslint-flat-config-utils": "^3.2.0", + "husky": "^9.1.7", "jiti": "^2.7.0", + "lint-staged": "^17.6.0", "tsdown": "^0.23.0", "tsx": "^4.23.13", "typescript": "^6.0.3", "vitest": "^5.0.5" + }, + "lint-staged": { + "*.{ts,js,mjs}": "eslint --fix" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 30163de..78c7365 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,9 +23,15 @@ importers: eslint-flat-config-utils: specifier: ^3.2.0 version: 3.2.0 + husky: + specifier: ^9.1.7 + version: 9.1.7 jiti: specifier: ^2.7.0 version: 2.7.0 + lint-staged: + specifier: ^17.6.0 + version: 17.6.0 tsdown: specifier: ^0.23.0 version: 0.23.0(tsx@4.23.13)(typescript@6.0.3) @@ -37,7 +43,7 @@ importers: version: 6.0.3 vitest: specifier: ^5.0.5 - version: 5.0.5(@types/node@26.5.1)(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)) + version: 5.0.5(@types/node@26.5.1)(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.1)) packages: @@ -1013,6 +1019,11 @@ packages: resolution: {integrity: sha512-Tz7u1i95/g2x2jz81+x0FBVhBhY5aRTvD3tXXdFaljuNdzDLJ8UGNRrTcj2cgQvAg3iW/h77Fz15nLW0L0CrZw==} engines: {node: '>=20.19.0'} + husky@9.1.7: + resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} + engines: {node: '>=18'} + hasBin: true + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1138,6 +1149,11 @@ packages: linkify-it@5.0.2: resolution: {integrity: sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==} + lint-staged@17.6.0: + resolution: {integrity: sha512-nOhBfYkZEwkFtNzD5pK9s9LkcWoxJ+whLzEnhqi9nl7zTB5n7tg8+9iYgMGx2Wm3VlLu8cbNj0RACzY+nWi5iQ==} + engines: {node: '>=22.22.1'} + hasBin: true + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -1279,6 +1295,10 @@ packages: std-env@4.3.0: resolution: {integrity: sha512-OtU/EgQ1kIm5KwqQpBC6ZEMXrZRui11w8zgfTWp8cdO9B8OaPsbA8bTHO2P+HNo1VlUTGMVBwPhydu6poeXiag==} + string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + tinybench@6.2.2: resolution: {integrity: sha512-nIZ2N2dFpjBsg2hgitKu7mA+FvsIJuGJOwysRngmVRRmWgR/UyPjwJj8c/fT/dhm8EkHnF5EOogRf+0Z2qrimA==} engines: {node: '>=20.0.0'} @@ -1470,6 +1490,11 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + yaml@2.9.1: + resolution: {integrity: sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==} + engines: {node: '>= 14.6'} + hasBin: true + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -1881,14 +1906,14 @@ snapshots: '@typescript-eslint/types': 8.71.2 eslint-visitor-keys: 5.0.1 - '@vitest/mocker@5.0.5(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13))': + '@vitest/mocker@5.0.5(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.1))': dependencies: '@jridgewell/trace-mapping': 0.3.31 '@vitest/spy': 5.0.5 estree-walker: 3.0.3 magic-string: 1.4.3 optionalDependencies: - vite: 8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13) + vite: 8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.1) '@vitest/spy@5.0.5': {} @@ -2229,6 +2254,8 @@ snapshots: domutils: 4.0.2 entities: 8.1.0 + husky@9.1.7: {} + ignore@5.3.2: {} ignore@7.0.12: {} @@ -2317,6 +2344,14 @@ snapshots: dependencies: uc.micro: 2.1.0 + lint-staged@17.6.0: + dependencies: + picomatch: 4.0.7 + string-argv: 0.3.2 + tinyexec: 1.3.1 + optionalDependencies: + yaml: 2.9.1 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 @@ -2466,6 +2501,8 @@ snapshots: std-env@4.3.0: {} + string-argv@0.3.2: {} + tinybench@6.2.2: {} tinyexec@1.3.1: {} @@ -2544,7 +2581,7 @@ snapshots: verkit@0.4.0: {} - vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13): + vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.1): dependencies: lightningcss: 1.33.0 picomatch: 4.0.7 @@ -2557,11 +2594,12 @@ snapshots: fsevents: 2.3.3 jiti: 2.7.0 tsx: 4.23.13 + yaml: 2.9.1 - vitest@5.0.5(@types/node@26.5.1)(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)): + vitest@5.0.5(@types/node@26.5.1)(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.1)): dependencies: '@types/chai': 5.2.3 - '@vitest/mocker': 5.0.5(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)) + '@vitest/mocker': 5.0.5(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.1)) chai: 6.3.0 es-module-lexer: 2.3.2 expect-type: 1.4.0 @@ -2572,7 +2610,7 @@ snapshots: tinybench: 6.2.2 tinyexec: 1.3.1 tinyglobby: 0.2.17 - vite: 8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13) + vite: 8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.1) why-is-node-running: 3.2.1 optionalDependencies: '@types/node': 26.5.1 @@ -2587,6 +2625,9 @@ snapshots: word-wrap@1.2.5: {} + yaml@2.9.1: + optional: true + yocto-queue@0.1.0: {} yuku-ast@0.9.5: From a10836ae5928d13c02c63ca1dd00d67f55d3961d Mon Sep 17 00:00:00 2001 From: "C.Nelhomme" <64921289+D3ller@users.noreply.github.com> Date: Thu, 15 Oct 2026 23:34:17 +0200 Subject: [PATCH 5/7] ci: run lint, typecheck and tests on main --- .github/workflows/ci.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..046e944 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,22 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + - run: pnpm install --frozen-lockfile + - run: pnpm lint + - run: pnpm typecheck + - run: pnpm test From 355f446fc7a39447f572b6ec444b533fa53a665e Mon Sep 17 00:00:00 2001 From: "C.Nelhomme" <64921289+D3ller@users.noreply.github.com> Date: Thu, 15 Oct 2026 23:34:47 +0200 Subject: [PATCH 6/7] chore: release 0.2.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6df3079..8c6f2ec 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "comark-seo", - "version": "0.2.0", + "version": "0.2.1", "description": "Comark plugin that analyses Markdown for SEO", "license": "MIT", "author": "Corentin NELHOMME ", From c9ba3ea1fe527964d7181c35f0ad7fa31b2c0ef2 Mon Sep 17 00:00:00 2001 From: "C.Nelhomme" <64921289+D3ller@users.noreply.github.com> Date: Thu, 15 Oct 2026 23:36:07 +0200 Subject: [PATCH 7/7] build: pin vitest to 5.0.4 to satisfy the release age policy --- package.json | 2 +- pnpm-lock.yaml | 36 ++++++++++++++++++------------------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/package.json b/package.json index 8c6f2ec..5ecd049 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "tsdown": "^0.23.0", "tsx": "^4.23.13", "typescript": "^6.0.3", - "vitest": "^5.0.5" + "vitest": "^5.0.4" }, "lint-staged": { "*.{ts,js,mjs}": "eslint --fix" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 78c7365..fd25a16 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -42,8 +42,8 @@ importers: specifier: ^6.0.3 version: 6.0.3 vitest: - specifier: ^5.0.5 - version: 5.0.5(@types/node@26.5.1)(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.1)) + specifier: ^5.0.4 + version: 5.0.4(@types/node@26.5.1)(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.1)) packages: @@ -590,8 +590,8 @@ packages: resolution: {integrity: sha512-zozlN0UA32bSG2zkKAgQyRYSbEISVoyU6vvkKYo2aSny74D8Jh4e+POkJ6Lk0dlezZi5x7TtD+88Xb06IB8nhg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@vitest/mocker@5.0.5': - resolution: {integrity: sha512-xLL3lkDegJZw+MGoGaCCsFayDZthGgpAtr3Vziyfc4p7xH89K7KRPcRBBh/kEYm0Aqkt5DtTmkYpBtRV/FrHZg==} + '@vitest/mocker@5.0.4': + resolution: {integrity: sha512-tqAlrYWce4iUxhr3ncNohejtCTOcHeE8XWrSNZY3OhPoDn01yeGv+gnaBy64ATp7o6pb03eIbBAjzmibpc9vIQ==} peerDependencies: msw: ^2.4.9 || ^3.0.0 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -601,8 +601,8 @@ packages: vite: optional: true - '@vitest/spy@5.0.5': - resolution: {integrity: sha512-lwJRExuH417257Q5wv9QYugN9IMJkoxcrKrYxGPQkBzl7wlNpTUxD/5yNX4ESKVUIShKPgkGchYPFMWOOk0wzw==} + '@vitest/spy@5.0.4': + resolution: {integrity: sha512-MZKk/gSkm2q+ICobMxCpH1mA+cCAWm8WV7UhxlqGjq/sJ3AGc1BqFOs5CRVXxH78wQtme9q/NAAgBquj4AcyMw==} '@yuku-codegen/binding-android-arm64@0.9.5': resolution: {integrity: sha512-jrOY5WM+AaAqkv51fHP1x28ifto4WgcZVzodLUyMU1jMWn5Sq+VciRdk/n8E0Ey5w4p4cWWE+m5GfXWOYh7Kzw==} @@ -1435,20 +1435,20 @@ packages: yaml: optional: true - vitest@5.0.5: - resolution: {integrity: sha512-cPODOMF8YnkiiYtDdHo6n4wWmBrOBBbOIYH2d33M4l3CdNn72h+qMmO6uXffUN6A5AZFXNND/d+krS9mgkXRfg==} + vitest@5.0.4: + resolution: {integrity: sha512-z0WxZRV2Sg48wF0FSgMq3TFG8JS38/Qr96vZVZdX6+Em9raQTvnXQvdTFJe2m3rfyJnEHeHQ/snceIdi8D1pVg==} engines: {node: ^22.12.0 || ^24.0.0 || >=26.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 5.0.5 - '@vitest/browser-preview': 5.0.5 + '@vitest/browser-playwright': 5.0.4 + '@vitest/browser-preview': 5.0.4 '@vitest/browser-webdriverio': ^5.0.0-beta.5 || >=5.0.0 - '@vitest/coverage-istanbul': 5.0.5 - '@vitest/coverage-v8': 5.0.5 - '@vitest/ui': 5.0.5 + '@vitest/coverage-istanbul': 5.0.4 + '@vitest/coverage-v8': 5.0.4 + '@vitest/ui': 5.0.4 happy-dom: '*' jsdom: '*' vite: ^6.4.0 || ^7.0.0 || ^8.0.0 @@ -1906,16 +1906,16 @@ snapshots: '@typescript-eslint/types': 8.71.2 eslint-visitor-keys: 5.0.1 - '@vitest/mocker@5.0.5(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.1))': + '@vitest/mocker@5.0.4(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.1))': dependencies: '@jridgewell/trace-mapping': 0.3.31 - '@vitest/spy': 5.0.5 + '@vitest/spy': 5.0.4 estree-walker: 3.0.3 magic-string: 1.4.3 optionalDependencies: vite: 8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.1) - '@vitest/spy@5.0.5': {} + '@vitest/spy@5.0.4': {} '@yuku-codegen/binding-android-arm64@0.9.5': optional: true @@ -2596,10 +2596,10 @@ snapshots: tsx: 4.23.13 yaml: 2.9.1 - vitest@5.0.5(@types/node@26.5.1)(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.1)): + vitest@5.0.4(@types/node@26.5.1)(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.1)): dependencies: '@types/chai': 5.2.3 - '@vitest/mocker': 5.0.5(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.1)) + '@vitest/mocker': 5.0.4(vite@8.3.4(@types/node@26.5.1)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.1)) chai: 6.3.0 es-module-lexer: 2.3.2 expect-type: 1.4.0