diff --git a/package.json b/package.json index c735b31..6ad99f2 100644 --- a/package.json +++ b/package.json @@ -100,6 +100,8 @@ "dependencies": { "@eslint/js": "^10.0.1", "@typescript-eslint/utils": "^8.67.0", + "eslint-plugin-jsdoc": "^64.3.9", + "eslint-plugin-tsdoc": "^0.5.2", "ts-api-utils": "^2.5.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c1701da..9881248 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,12 @@ importers: '@typescript-eslint/utils': specifier: ^8.67.0 version: 8.67.0(eslint@10.8.0(jiti@2.6.1))(typescript@6.0.3) + eslint-plugin-jsdoc: + specifier: ^64.3.9 + version: 64.3.9(eslint@10.8.0(jiti@2.6.1))(typescript@6.0.3) + eslint-plugin-tsdoc: + specifier: ^0.5.2 + version: 0.5.2(eslint@10.8.0(jiti@2.6.1))(typescript@6.0.3) ts-api-utils: specifier: ^2.5.0 version: 2.5.0(typescript@6.0.3) @@ -283,6 +289,14 @@ packages: '@emnapi/wasi-threads@2.0.1': resolution: {integrity: sha512-9DsSk+o5NBX0CCJT8s0EROGSGxjR/tKu6aBTaVyq+SjAEQH4XcdcRxPBRzsBLizTTJ49MJjF+jgu3qnO9GLQcQ==} + '@es-joy/jsdoccomment@0.97.0': + resolution: {integrity: sha512-EP8uoFfh6+GsdGCduYtmWAW0h7AO+Ayik9Vh5YbA2r/3N6lmJKkCNZX+q3QBXC1K6ixjQ/9igF2b7WVvLm063g==} + engines: {node: ^22.22.2 || >=24.15.0} + + '@es-joy/resolve.exports@1.2.0': + resolution: {integrity: sha512-Q9hjxWI5xBM+qW2enxfe8wDKdFWMfd0Z29k5ZJnuBqD/CasY5Zryj09aCA6owbGATWz+39p5uIdaHXpopOcG8g==} + engines: {node: '>=10'} + '@eslint-community/eslint-utils@4.10.1': resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -367,6 +381,12 @@ packages: '@loaderkit/resolve@1.0.6': resolution: {integrity: sha512-G8FdIoF5CypfwmD9rl8BXod5HDn8JqB0CCNBXDTaRZ+yRYhARrrSToX1zg1zy9jX3zLqigsELwhT4gNtkdQAUg==} + '@microsoft/tsdoc-config@0.18.1': + resolution: {integrity: sha512-9brPoVdfN9k9g0dcWkFeA7IH9bbcttzDJlXvkf8b2OBzd5MueR1V2wkKBL0abn0otvmkHJC6aapBOTJDDeMCZg==} + + '@microsoft/tsdoc@0.16.0': + resolution: {integrity: sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==} + '@napi-rs/wasm-runtime@1.2.2': resolution: {integrity: sha512-JfB4kuJQjaoHuCTseIINHtHWeJnvgEcxjwA5t/Y00ZgaOO1Crz3fjT/p8kT28zA/Caz7oiUMn3d6H2yOVCVwuw==} engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} @@ -617,6 +637,10 @@ packages: resolution: {integrity: sha512-fCTuZK4QBa+39Oz9l4OGfJfz+GpwCp3AqO7Zch3to99xHPgstVsRFpeQ8LNd2o1Gv8raL2mCFwiaHh7bFSp5DQ==} engines: {node: '>=22'} + '@sindresorhus/base62@1.0.0': + resolution: {integrity: sha512-TeheYy0ILzBEI/CO55CP6zJCSdSWeRtGnHy8U8dWSUH4I68iqTsy7HkMktR4xakThc9jotkPQUXT4ITdbV7cHA==} + engines: {node: '>=18'} + '@sindresorhus/is@4.6.0': resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} engines: {node: '>=10'} @@ -679,6 +703,9 @@ packages: '@types/node@24.13.3': resolution: {integrity: sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==} + '@types/node@26.5.1': + resolution: {integrity: sha512-CzNm2FezW4VR/LjG6yUdiEgLE/rAQ9Slj5gCu/C2VrdcW7I0ahNZ8DRbHT7zOZ6r3ONgd/bsQIeSaoDGrd1C6g==} + '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -697,12 +724,24 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/project-service@8.56.1': + resolution: {integrity: sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/project-service@8.67.0': resolution: {integrity: sha512-cvE8c7ulYeXN9fYuszhCeCsbzyVEXuhrRCybnBre7TUmqb5nRmBfQAwCj0O3WJFDeyAZt4VYv51vMCC9LHSdYw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/project-service@8.70.0': + resolution: {integrity: sha512-hFHbTNqhU9G+2eKFXCBVb1tjFT/LceiJ4+HfLO4pTpDI0KHi6iajpcFFkaSQ9gXmCh7n82A0PthaayEdN6mspQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/rule-tester@8.67.0': resolution: {integrity: sha512-aOPA7+XgoRe4idCQZH9V1+ObHW6wslSp/GWwXoRwsTFUW1AZnHVvcnCFvQwTUdDtOhzwT3F/G2nOls7UuiOBiA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -710,16 +749,36 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/scope-manager@8.56.1': + resolution: {integrity: sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/scope-manager@8.67.0': resolution: {integrity: sha512-EgvsleTwS4E+WzzSvem8fAUubLwatMNF1B5hHSLQxcvs7q2dtRhGyujHwLJSYlG41niJ7GP24Aha2+0mb1b2kg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/scope-manager@8.70.0': + resolution: {integrity: sha512-8nP3Kwh5hlgZ4FicGvmznAmJe8UL4sdU8tLukrPaMuQmDuk4Y8xYfzu/aYZW4xT2JCgc7H/TpDI5cGlxcWJSqQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.56.1': + resolution: {integrity: sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/tsconfig-utils@8.67.0': resolution: {integrity: sha512-vV+LUSv5njUWsknE71fqKTlXUva+R76SaeORd6Zojcunk/6DvKFXONU3BrAs2H49mbygUXt6gbYunzwqNwlhdg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/tsconfig-utils@8.70.0': + resolution: {integrity: sha512-adnkeeNq9Sq1sUf4+FRVc0KdgYghzsgFpZSQVZVvY0LCuUuN0FnQgyGzCJeC4fW1cdXseBAjU2EOqUIjbNcZUw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/type-utils@8.67.0': resolution: {integrity: sha512-aVWDXbRmdXO9siTfX4ditQI1T9+zVcNazT48EJCD0v40/9RIFoUgZ05CmGEq9H2gixRpjUn/iplwvlcvutJW/Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -727,16 +786,43 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/types@8.56.1': + resolution: {integrity: sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/types@8.67.0': resolution: {integrity: sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/types@8.70.0': + resolution: {integrity: sha512-asTOIYhDg4zdzOScCyaytrsV3cR6B4ecPQlXw/dJIm7J/MZTtCtfVII9JD8Geh4jTCrK/Xe6cg5UevoleMcoJQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.56.1': + resolution: {integrity: sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/typescript-estree@8.67.0': resolution: {integrity: sha512-EKQBCE9yNlRJYm7jdTW5AhDacDUmSwQb0FAJAmK2EKYrNXIsa2vxcSZx6PvJ/dEdI6lS+Y9W+EXckLj0iPFGcw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/typescript-estree@8.70.0': + resolution: {integrity: sha512-d9NmHMPEKQ7QCLLm1jI3zmoQBwT5KwFYjXBJ9ymZfKCUU+5rmTRykKAFvH5Qn/ZCds3CEAFS9OC9M/jkl0X2bA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/utils@8.56.1': + resolution: {integrity: sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==} + 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.0.0' + '@typescript-eslint/utils@8.67.0': resolution: {integrity: sha512-U9D1FdwEWBwok3hxxSdhclMb0twvt9QnjIQ0VfQ1AiX2epnpSgv2ubVDsayOFyY8K6FX+AQ7E0FKWVG3iKsj1A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -744,10 +830,25 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/utils@8.70.0': + resolution: {integrity: sha512-oZmtKJz/4fufZ2p3+Cn3ijEojcdfR+1zYDH2xKYrEly0dR/Q/1xUPRCOlKGxod78nWlU2UnDe09GZ3TaknBFGA==} + 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-eslint/visitor-keys@8.56.1': + resolution: {integrity: sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/visitor-keys@8.67.0': resolution: {integrity: sha512-fkv8dHRDqfGtTHuJeebdrQ7cX6Ad4WAS00rgHh9UGvMycF1mjBfsxry1XsLIFhWZ6Judlh6UdzK+TYlbpCXgnA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/visitor-keys@8.70.0': + resolution: {integrity: sha512-BoC8PiO4Hkdo0TVJh9Ntxr5MxPDI7/oFsrygN5ADelFSeXG/qgNuucIGA+L5Z6JpPTE/uRfcTWtscjbUaufepQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@vitest/coverage-v8@4.1.10': resolution: {integrity: sha512-IM49HmthevbgAO4anp1hwtoT9wYe59w0LR00gr+eagHE+ZJ5lK4sLPeO0ubgoJcwLk6dehU3R24N+FbEEKDc8g==} peerDependencies: @@ -942,6 +1043,9 @@ packages: ajv@6.15.0: resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + ajv@8.20.0: resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} @@ -976,6 +1080,10 @@ packages: any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + are-docs-informative@0.1.1: + resolution: {integrity: sha512-sqRsNQBwbKLRX0jV5Cu5uzmtflf892n4Vukz7T659ebL4pz3mpOqCMU7lxMoBTFwnp10E3YB5ZcyHM41W5bcDA==} + engines: {node: '>=18'} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -1164,6 +1272,10 @@ packages: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} + comment-parser@1.4.8: + resolution: {integrity: sha512-rKZTGo4fzKYna8UcL0isTg5wkBNla7bxTypLwZQXjIdi++IdP1OJ41rI5Mti3/jltkPujbu4i9LIARYA+zpotQ==} + engines: {node: '>= 12.0.0'} + compare-func@2.0.0: resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} @@ -1409,6 +1521,12 @@ packages: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} engines: {node: '>=12'} + eslint-plugin-jsdoc@64.3.9: + resolution: {integrity: sha512-iwA1uN5/3X3GH9zdiJq8XvUNuMeLPWriGCLNBt2d/oACwYq41LrAJE2cLvMLc2gcYFutd/XvINp99JGTlxEirA==} + engines: {node: ^22.22.2 || >=24.15.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 + eslint-plugin-jsx-a11y@6.10.2: resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} engines: {node: '>=4.0'} @@ -1427,6 +1545,9 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + eslint-plugin-tsdoc@0.5.2: + resolution: {integrity: sha512-BlvqjWZdBJDIPO/YU3zcPCF23CvjYT3gyu63yo6b609NNV3D1b6zceAREy2xnweuBoDpZcLNuPyAUq9cvx6bbQ==} + eslint-scope@9.1.2: resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} @@ -1718,6 +1839,9 @@ packages: resolution: {integrity: sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==} engines: {node: ^20.17.0 || >=22.9.0} + html-entities@2.6.0: + resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==} + html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} @@ -1959,6 +2083,9 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + jju@1.4.0: + resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} + js-tokens@10.0.0: resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} @@ -1969,6 +2096,10 @@ packages: resolution: {integrity: sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==} hasBin: true + jsdoc-type-pratt-parser@9.2.1: + resolution: {integrity: sha512-V4Ww4EHnTcTLSOMoB0FsF72JhQvcAsriCm/LWnxJeGWoxIjEL2l9na11abQok5SYShq8m0Gl02el/xAbTCulvQ==} + engines: {node: ^22.22.2 || >=24.15.0} + jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -2349,6 +2480,9 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} + object-deep-merge@2.0.1: + resolution: {integrity: sha512-aKttDKcU3pyZqKcCkDhsMn70WmZFG2JGDQLP9EcLyTSIFQRCPWLAmBZRLJnrVUrhPG1jETEEbfdgbNtJf1LyMg==} + object-inspect@1.13.4: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} @@ -2440,6 +2574,9 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-imports-exports@0.2.4: + resolution: {integrity: sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==} + parse-json@4.0.0: resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} engines: {node: '>=4'} @@ -2456,6 +2593,9 @@ packages: resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} engines: {node: '>=18'} + parse-statements@1.0.11: + resolution: {integrity: sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==} + parse5-htmlparser2-tree-adapter@6.0.1: resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} @@ -2605,6 +2745,10 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + reserved-identifiers@1.2.0: + resolution: {integrity: sha512-yE7KUfFvaBFzGPs5H3Ops1RevfUEsDc5Iz65rOwWg4lE8HJSYtle77uul3+573457oHvBKuHYDl/xqUkKpEEdw==} + engines: {node: '>=18'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -2616,6 +2760,11 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolve@1.22.12: + resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} + engines: {node: '>= 0.4'} + hasBin: true + resolve@2.0.0-next.7: resolution: {integrity: sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==} engines: {node: '>= 0.4'} @@ -2760,6 +2909,9 @@ packages: spdx-expression-parse@3.0.1: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + spdx-expression-parse@5.0.0: + resolution: {integrity: sha512-vngmw3Rgn+o2arXNbnZaj5UtOEBuWBfvaI+Wc8GFfykIhA5/vdK9/Sp/XkLv63dykz2rxKDvKEHupF5P0FORcQ==} + spdx-license-ids@3.0.23: resolution: {integrity: sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==} @@ -2910,6 +3062,10 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + to-valid-identifier@1.0.0: + resolution: {integrity: sha512-41wJyvKep3yT2tyPqX/4blcfybknGB4D+oETKLs7Q76UiPqRpUJK3hr1nxelyYO0PHKVzJwlu0aCeEAsGI6rpw==} + engines: {node: '>=20'} + traverse@0.6.8: resolution: {integrity: sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA==} engines: {node: '>= 0.4'} @@ -3037,6 +3193,9 @@ packages: undici-types@7.18.2: resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + undici-types@8.9.0: + resolution: {integrity: sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==} + undici@6.28.0: resolution: {integrity: sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA==} engines: {node: '>=18.17'} @@ -3573,6 +3732,16 @@ snapshots: tslib: 2.8.1 optional: true + '@es-joy/jsdoccomment@0.97.0': + dependencies: + '@types/estree': 1.0.9 + '@typescript-eslint/types': 8.70.0 + comment-parser: 1.4.8 + esquery: 1.7.0 + jsdoc-type-pratt-parser: 9.2.1 + + '@es-joy/resolve.exports@1.2.0': {} + '@eslint-community/eslint-utils@4.10.1(eslint@10.8.0(jiti@2.6.1))': dependencies: eslint: 10.8.0(jiti@2.6.1) @@ -3651,6 +3820,15 @@ snapshots: dependencies: '@braidai/lang': 1.1.2 + '@microsoft/tsdoc-config@0.18.1': + dependencies: + '@microsoft/tsdoc': 0.16.0 + ajv: 8.18.0 + jju: 1.4.0 + resolve: 1.22.12 + + '@microsoft/tsdoc@0.16.0': {} + '@napi-rs/wasm-runtime@1.2.2(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3)': dependencies: '@emnapi/core': 2.0.0-alpha.3 @@ -3920,6 +4098,8 @@ snapshots: '@simple-libs/stream-utils@2.0.0': {} + '@sindresorhus/base62@1.0.0': {} + '@sindresorhus/is@4.6.0': {} '@sindresorhus/merge-streams@4.0.0': {} @@ -3966,6 +4146,10 @@ snapshots: dependencies: undici-types: 7.18.2 + '@types/node@26.5.1': + dependencies: + undici-types: 8.9.0 + '@types/normalize-package-data@2.4.4': {} '@typescript-eslint/eslint-plugin@8.67.0(@typescript-eslint/parser@8.67.0(eslint@10.8.0(jiti@2.6.1))(typescript@6.0.3))(eslint@10.8.0(jiti@2.6.1))(typescript@6.0.3)': @@ -3996,6 +4180,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/project-service@8.56.1(typescript@6.0.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.67.0(typescript@6.0.3) + '@typescript-eslint/types': 8.67.0 + debug: 4.4.3 + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/project-service@8.67.0(typescript@6.0.3)': dependencies: '@typescript-eslint/tsconfig-utils': 8.67.0(typescript@6.0.3) @@ -4005,6 +4198,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/project-service@8.70.0(typescript@6.0.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.70.0(typescript@6.0.3) + '@typescript-eslint/types': 8.70.0 + debug: 4.4.3 + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/rule-tester@8.67.0(eslint@10.8.0(jiti@2.6.1))(typescript@6.0.3)': dependencies: '@typescript-eslint/parser': 8.67.0(eslint@10.8.0(jiti@2.6.1))(typescript@6.0.3) @@ -4019,15 +4221,33 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/scope-manager@8.56.1': + dependencies: + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/visitor-keys': 8.56.1 + '@typescript-eslint/scope-manager@8.67.0': dependencies: '@typescript-eslint/types': 8.67.0 '@typescript-eslint/visitor-keys': 8.67.0 + '@typescript-eslint/scope-manager@8.70.0': + dependencies: + '@typescript-eslint/types': 8.70.0 + '@typescript-eslint/visitor-keys': 8.70.0 + + '@typescript-eslint/tsconfig-utils@8.56.1(typescript@6.0.3)': + dependencies: + typescript: 6.0.3 + '@typescript-eslint/tsconfig-utils@8.67.0(typescript@6.0.3)': dependencies: typescript: 6.0.3 + '@typescript-eslint/tsconfig-utils@8.70.0(typescript@6.0.3)': + dependencies: + typescript: 6.0.3 + '@typescript-eslint/type-utils@8.67.0(eslint@10.8.0(jiti@2.6.1))(typescript@6.0.3)': dependencies: '@typescript-eslint/types': 8.67.0 @@ -4040,8 +4260,27 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/types@8.56.1': {} + '@typescript-eslint/types@8.67.0': {} + '@typescript-eslint/types@8.70.0': {} + + '@typescript-eslint/typescript-estree@8.56.1(typescript@6.0.3)': + dependencies: + '@typescript-eslint/project-service': 8.56.1(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@6.0.3) + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/visitor-keys': 8.56.1 + 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-eslint/typescript-estree@8.67.0(typescript@6.0.3)': dependencies: '@typescript-eslint/project-service': 8.67.0(typescript@6.0.3) @@ -4057,6 +4296,32 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/typescript-estree@8.70.0(typescript@6.0.3)': + dependencies: + '@typescript-eslint/project-service': 8.70.0(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.70.0(typescript@6.0.3) + '@typescript-eslint/types': 8.70.0 + '@typescript-eslint/visitor-keys': 8.70.0 + 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-eslint/utils@8.56.1(eslint@10.8.0(jiti@2.6.1))(typescript@6.0.3)': + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.0(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.56.1 + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/typescript-estree': 8.56.1(typescript@6.0.3) + eslint: 10.8.0(jiti@2.6.1) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/utils@8.67.0(eslint@10.8.0(jiti@2.6.1))(typescript@6.0.3)': dependencies: '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.0(jiti@2.6.1)) @@ -4068,11 +4333,32 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/utils@8.70.0(eslint@10.8.0(jiti@2.6.1))(typescript@6.0.3)': + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.0(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.70.0 + '@typescript-eslint/types': 8.70.0 + '@typescript-eslint/typescript-estree': 8.70.0(typescript@6.0.3) + eslint: 10.8.0(jiti@2.6.1) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.56.1': + dependencies: + '@typescript-eslint/types': 8.56.1 + eslint-visitor-keys: 5.0.1 + '@typescript-eslint/visitor-keys@8.67.0': dependencies: '@typescript-eslint/types': 8.67.0 eslint-visitor-keys: 5.0.1 + '@typescript-eslint/visitor-keys@8.70.0': + dependencies: + '@typescript-eslint/types': 8.70.0 + eslint-visitor-keys: 5.0.1 + '@vitest/coverage-v8@4.1.10(vitest@4.1.10)': dependencies: '@bcoe/v8-coverage': 1.0.2 @@ -4222,6 +4508,13 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ajv@8.18.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.5 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 @@ -4251,6 +4544,8 @@ snapshots: any-promise@1.3.0: {} + are-docs-informative@0.1.1: {} + argparse@2.0.1: {} argue-cli@3.1.0: {} @@ -4456,6 +4751,8 @@ snapshots: commander@10.0.1: {} + comment-parser@1.4.8: {} + compare-func@2.0.0: dependencies: array-ify: 1.0.0 @@ -4750,6 +5047,28 @@ snapshots: escape-string-regexp@5.0.0: {} + eslint-plugin-jsdoc@64.3.9(eslint@10.8.0(jiti@2.6.1))(typescript@6.0.3): + dependencies: + '@es-joy/jsdoccomment': 0.97.0 + '@es-joy/resolve.exports': 1.2.0 + '@typescript-eslint/utils': 8.70.0(eslint@10.8.0(jiti@2.6.1))(typescript@6.0.3) + are-docs-informative: 0.1.1 + comment-parser: 1.4.8 + debug: 4.4.3 + escape-string-regexp: 5.0.0 + eslint: 10.8.0(jiti@2.6.1) + espree: 11.2.0 + esquery: 1.7.0 + html-entities: 2.6.0 + object-deep-merge: 2.0.1 + parse-imports-exports: 0.2.4 + semver: 7.8.5 + spdx-expression-parse: 5.0.0 + to-valid-identifier: 1.0.0 + transitivePeerDependencies: + - supports-color + - typescript + eslint-plugin-jsx-a11y@6.10.2(eslint@10.8.0(jiti@2.6.1)): dependencies: aria-query: 5.3.2 @@ -4802,6 +5121,16 @@ snapshots: string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 + eslint-plugin-tsdoc@0.5.2(eslint@10.8.0(jiti@2.6.1))(typescript@6.0.3): + dependencies: + '@microsoft/tsdoc': 0.16.0 + '@microsoft/tsdoc-config': 0.18.1 + '@typescript-eslint/utils': 8.56.1(eslint@10.8.0(jiti@2.6.1))(typescript@6.0.3) + transitivePeerDependencies: + - eslint + - supports-color + - typescript + eslint-scope@9.1.2: dependencies: '@types/esrecurse': 4.3.1 @@ -5142,6 +5471,8 @@ snapshots: dependencies: lru-cache: 11.5.2 + html-entities@2.6.0: {} + html-escaper@2.0.2: {} http-proxy-agent@9.1.0: @@ -5372,6 +5703,8 @@ snapshots: jiti@2.6.1: {} + jju@1.4.0: {} + js-tokens@10.0.0: {} js-tokens@4.0.0: {} @@ -5380,6 +5713,11 @@ snapshots: dependencies: argparse: 2.0.1 + jsdoc-type-pratt-parser@9.2.1: + dependencies: + '@types/estree': 1.0.9 + '@types/node': 26.5.1 + jsesc@3.1.0: {} json-buffer@3.0.1: {} @@ -5661,6 +5999,8 @@ snapshots: object-assign@4.1.1: {} + object-deep-merge@2.0.1: {} + object-inspect@1.13.4: {} object-keys@1.1.1: {} @@ -5757,6 +6097,10 @@ snapshots: dependencies: callsites: 3.1.0 + parse-imports-exports@0.2.4: + dependencies: + parse-statements: 1.0.11 + parse-json@4.0.0: dependencies: error-ex: 1.3.4 @@ -5777,6 +6121,8 @@ snapshots: parse-ms@4.0.0: {} + parse-statements@1.0.11: {} + parse5-htmlparser2-tree-adapter@6.0.1: dependencies: parse5: 6.0.1 @@ -5926,12 +6272,21 @@ snapshots: require-from-string@2.0.2: {} + reserved-identifiers@1.2.0: {} + resolve-from@4.0.0: {} resolve-from@5.0.0: {} resolve-pkg-maps@1.0.0: {} + resolve@1.22.12: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.16.2 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + resolve@2.0.0-next.7: dependencies: es-errors: 1.3.0 @@ -6136,6 +6491,11 @@ snapshots: spdx-exceptions: 2.5.0 spdx-license-ids: 3.0.23 + spdx-expression-parse@5.0.0: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.23 + spdx-license-ids@3.0.23: {} split2@1.0.0: @@ -6310,6 +6670,11 @@ snapshots: dependencies: is-number: 7.0.0 + to-valid-identifier@1.0.0: + dependencies: + '@sindresorhus/base62': 1.0.0 + reserved-identifiers: 1.2.0 + traverse@0.6.8: {} tree-kill@1.2.2: {} @@ -6438,6 +6803,8 @@ snapshots: undici-types@7.18.2: {} + undici-types@8.9.0: {} + undici@6.28.0: {} undici@7.29.0: {} diff --git a/src/create-config.test.ts b/src/create-config.test.ts index e2f1ba0..4a93534 100644 --- a/src/create-config.test.ts +++ b/src/create-config.test.ts @@ -1,11 +1,12 @@ import type { TSESLint } from '@typescript-eslint/utils'; import { describe, expect, it } from 'vitest'; import { exadevConfig } from './create-config'; +import jsdocAndTsdoc from './jsdoc'; import recommendedTypeChecked from './recommended-type-checked'; describe('exadevConfig', () => { - it('with both features forced off, returns exactly the base recommendedTypeChecked length, regardless of what is installed', () => { - expect(exadevConfig({ react: false, nextjs: false })).toHaveLength(recommendedTypeChecked.length); + it('with both features forced off, returns exactly the base recommendedTypeChecked plus jsdocAndTsdoc length, regardless of what is installed', () => { + expect(exadevConfig({ react: false, nextjs: false })).toHaveLength(recommendedTypeChecked.length + jsdocAndTsdoc.length); }); it('with no args, auto-detects against this repo\'s own real devDependencies (react + hooks + a11y + nextjs all installed for testing)', () => { @@ -13,7 +14,7 @@ describe('exadevConfig', () => { const REACT_FAMILY_BLOCK_COUNT = 4; // react, jsx-runtime, react-hooks, jsx-a11y const NEXTJS_BLOCK_COUNT = 1; const result = exadevConfig(); - expect(result).toHaveLength(recommendedTypeChecked.length + REACT_FAMILY_BLOCK_COUNT + NEXTJS_BLOCK_COUNT); + expect(result).toHaveLength(recommendedTypeChecked.length + jsdocAndTsdoc.length + REACT_FAMILY_BLOCK_COUNT + NEXTJS_BLOCK_COUNT); }); it('appends trailing user configs, in order, after everything else', () => { diff --git a/src/create-config.ts b/src/create-config.ts index 08d7a07..7031a78 100644 --- a/src/create-config.ts +++ b/src/create-config.ts @@ -1,5 +1,6 @@ import type { TSESLint } from '@typescript-eslint/utils'; import type { ConfigArrayValue, PublicConfigArray } from './config-types'; +import jsdocAndTsdoc from './jsdoc'; import { buildNextjsConfig } from './nextjs'; import { buildReactConfig } from './react'; import recommendedTypeChecked from './recommended-type-checked'; @@ -10,9 +11,11 @@ export interface ExadevConfigOptions { readonly nextjs?: boolean; } +// jsdocAndTsdoc is bundled unconditionally, the same way recommendedTypeChecked itself is -- unlike react/nextjs below, it isn't a consumer framework choice with its own optional peer dependency to resolve; both eslint-plugin-jsdoc and eslint-plugin-tsdoc are plain dependencies of this package (see package.json), so every consumer already has them the moment they depend on this package at all. +// // The tri-state per feature threads straight into each builder's own `enabled` option -- true forces on (throwing if the underlying peer isn't resolvable), false forces off (skipping resolution entirely), undefined auto-detects (silently empty if unresolvable). One resolution pass per feature; no separate pre-check gate that would resolve twice. export function exadevConfig(options: ExadevConfigOptions = {}, ...userConfigs: readonly TSESLint.FlatConfig.Config[]): PublicConfigArray { - const built: ConfigArrayValue = [...recommendedTypeChecked, ...buildReactConfig({ enabled: options.react }), ...buildNextjsConfig({ enabled: options.nextjs }), ...userConfigs]; + const built: ConfigArrayValue = [...recommendedTypeChecked, ...jsdocAndTsdoc, ...buildReactConfig({ enabled: options.react }), ...buildNextjsConfig({ enabled: options.nextjs }), ...userConfigs]; return toPublicConfigArray(built); } diff --git a/src/jsdoc.ts b/src/jsdoc.ts new file mode 100644 index 0000000..f3525e9 --- /dev/null +++ b/src/jsdoc.ts @@ -0,0 +1,47 @@ +import jsdoc from 'eslint-plugin-jsdoc'; +import tsdoc from 'eslint-plugin-tsdoc'; +import type { ConfigArrayValue } from './config-types'; + +// eslint-plugin-jsdoc's own `flat/recommended-tsdoc-error` (not the plain `flat/recommended-typescript-error`) is the right base for this package: it is the variant tuned to not fight a TSDoc-flavoured comment style (the `{@link Foo}` inline tag and `@remarks`/`@example` block tags this package's own global comment convention already asks for), where the plain typescript variant instead expects classic JSDoc phrasing. The `-error` suffix (over the bare `flat/recommended-tsdoc`) matches this file's own all-`error` severities elsewhere in the package -- nothing here is a `warn`, so a jsdoc violation should not be the one exception. `flat/recommended-tsdoc-error` is itself a single flat config object, not an array (confirmed directly), hence the object-literal merge below rather than a spread. +const jsdocConfig = jsdoc.configs['flat/recommended-tsdoc-error']; + +// `flat/recommended-tsdoc-error` bundles four rule tiers at once: logical (an existing doc block's own internal consistency, e.g. a documented @param that doesn't exist), contents (validating the substance of an existing tag, e.g. an unresolvable @throws type), stylistic (formatting/alignment of an existing block), and requirements (whether a doc block exists AT ALL, and whether each of its tags is present). Every requirements-tier rule is turned off below: this package's own doc-comment convention already distinguishes a symbol with a real public contract (which gets a doc comment) from one that doesn't (a plain `//`, or nothing) -- see the exported-symbol guidance this package's consumers already follow. Forcing every function everywhere, including private helpers and test files, to carry a JSDoc block is a different, much larger policy this package isn't making by adding these two plugins, and eslint-plugin-jsdoc's own `--fix` for a missing block inserts an empty, contentless `/** */` stub (confirmed directly) -- exactly the kind of comment-for-its-own-sake this package's consumers are supposed to avoid. What stays on is validation of a doc comment that's already there: correct tag names, resolvable types, internally consistent @param/@returns, and (via eslint-plugin-tsdoc below) valid TSDoc syntax. +const REQUIREMENTS_TIER_RULES = [ + 'jsdoc/require-example', + 'jsdoc/require-jsdoc', + 'jsdoc/require-next-type', + 'jsdoc/require-param', + 'jsdoc/require-param-description', + 'jsdoc/require-param-name', + 'jsdoc/require-param-type', + 'jsdoc/require-property', + 'jsdoc/require-property-description', + 'jsdoc/require-property-name', + 'jsdoc/require-property-type', + 'jsdoc/require-returns', + 'jsdoc/require-returns-description', + 'jsdoc/require-returns-type', + 'jsdoc/require-template', + 'jsdoc/require-throws-type', + 'jsdoc/require-yields', + 'jsdoc/require-yields-type', +] as const; + +const jsdocAndTsdoc: ConfigArrayValue = [ + { + ...jsdocConfig, + rules: { + ...jsdocConfig.rules, + ...Object.fromEntries(REQUIREMENTS_TIER_RULES.map((rule) => [rule, 'off'])), + }, + }, + { + // eslint-plugin-tsdoc ships no `configs` export at all (confirmed: its only export is `{ rules: { syntax } }`), so the plugin registration and the rule's severity are both set by hand here rather than spread from a preset. `tsdoc/syntax` validates that a doc comment's tags and inline references actually parse as valid TSDoc -- a check eslint-plugin-jsdoc itself does not perform, since it validates JSDoc's own (looser) grammar, not the TSDoc spec a `{@link}`/`@remarks`-style comment is written against. + plugins: { tsdoc }, + rules: { + 'tsdoc/syntax': 'error', + }, + }, +]; + +export default jsdocAndTsdoc; diff --git a/vitest.config.ts b/vitest.config.ts index a43eabe..126ccf2 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -2,6 +2,8 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { + // @typescript-eslint/rule-tester spins up a real TypeScript program (parse + type-check) per test case for every type-aware custom rule in src/rules/, and each test FILE pays a large, mostly-fixed startup cost the first time it does this (loading the ES2024 lib and @types/node), confirmed directly: a file's first rule-tester case routinely took several seconds while its later cases, reusing the now-warm project service, ran in tens of milliseconds. `fileParallelism: false` was tried specifically to remove file-to-file CPU contention as the suspected cause, on the theory that several files paying that startup cost at once was what pushed individual cases over a short timeout -- it was not: serializing the suite made it roughly 6x slower (~180s vs ~30s) and STILL left two cases failing even with a 10000ms ceiling, since each file's fixed startup cost doesn't shrink by removing overlap, it just stops overlapping. The real, load-bearing fix is the larger timeout below; parallelism stays at vitest's default. + testTimeout: 30_000, setupFiles: ['./vitest.setup.ts'], coverage: { enabled: true,