diff --git a/.gitignore b/.gitignore index 91dfed8..d581b5c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .DS_Store -node_modules \ No newline at end of file +node_modules +/cjs \ No newline at end of file diff --git a/.npmignore b/.npmignore index ef802af..25183e8 100644 --- a/.npmignore +++ b/.npmignore @@ -4,3 +4,4 @@ /tests eslint.config.js prettier.config.js +tsconfig.json \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index ad92582..ec37e69 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "editor.formatOnSave": true + "editor.formatOnSave": true, + "cSpell.words": ["estree"] } diff --git a/eslint.config.js b/eslint.config.js index 18d1c31..ac53525 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -2,6 +2,7 @@ import globals from "globals"; import pluginJs from "@eslint/js"; import eslintPlugin from "eslint-plugin-eslint-plugin"; import nodePlugin from "eslint-plugin-n"; +import avaPlugin from "eslint-plugin-ava"; /** @type import("eslint").Linter.Config[] */ export default [ @@ -15,8 +16,10 @@ export default [ "n/exports-style": ["error", "module.exports"], }, }, + { languageOptions: { ecmaVersion: 2020, sourceType: "module" } }, { - languageOptions: { ecmaVersion: 2021, sourceType: "module" }, - ignores: ["/examples"], + files: ["tests/*.js"], + ...avaPlugin.configs["flat/recommended"], }, + { ignores: ["node_modules", "cjs", "examples"] }, ]; diff --git a/examples/package-lock.json b/examples/package-lock.json index 8f7cc8e..661cb6b 100644 --- a/examples/package-lock.json +++ b/examples/package-lock.json @@ -15,7 +15,7 @@ } }, "..": { - "version": "1.0.0-beta.5", + "version": "1.0.0-beta.6", "dev": true, "license": "Unlicense", "devDependencies": { diff --git a/lib/index.mjs b/lib/index.js similarity index 61% rename from lib/index.mjs rename to lib/index.js index 80cf9a8..589fe60 100644 --- a/lib/index.mjs +++ b/lib/index.js @@ -1,12 +1,10 @@ -import fs from "fs"; -import throwDocumentation from "./rules/require-throws-doc.mjs"; -import throwNaming from "./rules/throw-function-naming.mjs"; +import { readFileSync } from "fs"; +import throwDocumentation from "./rules/require-throws-doc.js"; +import throwNaming from "./rules/throw-function-naming.js"; -const pkg = JSON.parse(fs.readFileSync(new URL("../package.json", import.meta.url), "utf8")); +const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")); -/** - * @type {import("eslint").ESLint.Plugin} - */ +/** @type {import("eslint").ESLint.Plugin} */ const plugin = { meta: { name: pkg.name, diff --git a/lib/rules/reject-documentation.mjs b/lib/rules/reject-documentation.js similarity index 100% rename from lib/rules/reject-documentation.mjs rename to lib/rules/reject-documentation.js diff --git a/lib/rules/require-throws-doc.mjs b/lib/rules/require-throws-doc.js similarity index 87% rename from lib/rules/require-throws-doc.mjs rename to lib/rules/require-throws-doc.js index 44d0c83..3e9f6d0 100644 --- a/lib/rules/require-throws-doc.mjs +++ b/lib/rules/require-throws-doc.js @@ -1,15 +1,13 @@ -import { getThrowTypes } from "../utils.mjs"; +import { getThrowTypes } from "../utils.js"; -/** - * @type {import("eslint").Rule.RuleModule} - */ +/** @type {import("eslint").Rule.RuleModule} */ export default { meta: { type: "suggestion", docs: { description: "enforce JSDoc @throws tag for functions that throw exceptions", category: "Best Practices", - recommended: "warn", + recommended: true, }, messages: { missingThrows: "Function throws '{{type}}' but lacks a @throws tag in JSDoc.", @@ -18,7 +16,7 @@ export default { fixable: "code", }, create(context) { - /** @param {(import("estree").ArrowFunctionExpression | (import("estree").FunctionDeclaration)) & import("eslint").Rule.NodeParentExtension} node */ + /** @param {(import("estree").ArrowFunctionExpression | import("estree").FunctionExpression | import("estree").FunctionDeclaration) & import("eslint").Rule.NodeParentExtension} node */ function checkFunctionForThrowsTag(node) { const sourceCode = context.sourceCode; const jsDocComment = sourceCode.getJSDocComment(node); @@ -28,7 +26,7 @@ export default { // Missing JSDoc @throws if (!jsDocComment) { context.report({ - node: node, + node, messageId: "missingThrows", data: { type: Array.from(throwTypes).join(", ") }, fix(fixer) { @@ -41,7 +39,7 @@ export default { // Calculate indentation const line = sourceCode.lines[node.loc.start.line - 1]; - const indentation = line.match(/^\s*/)[0]; + const indentation = line.match(/^\s*/)?.[0]; const jsDoc = `/**\n${indentation} * @throws {${Array.from(throwTypes).join(", ")}}\n${indentation} */\n${indentation}`; @@ -58,7 +56,7 @@ export default { const isMultiLine = jsDocValue.includes("\n"); context.report({ - node: node, + node, messageId: "missingThrows", data: { type: Array.from(throwTypes).join(", ") }, fix(fixer) { @@ -66,7 +64,7 @@ export default { // Calculate indentation const line = sourceCode.lines[node.loc.start.line - 1]; - const indentation = line.match(/^\s*/)[0]; + const indentation = line.match(/^\s*/)?.[0]; const updatedJsDoc = isMultiLine ? `${jsDocValue}* ${jsDoc}` @@ -81,7 +79,7 @@ export default { if (!throwsTag) { context.report({ - node: node, + node, messageId: "missingThrows", data: { type: Array.from(throwTypes).join(", ") }, }); diff --git a/lib/rules/throw-function-naming.mjs b/lib/rules/throw-function-naming.js similarity index 93% rename from lib/rules/throw-function-naming.mjs rename to lib/rules/throw-function-naming.js index 8cc90d4..88ceb56 100644 --- a/lib/rules/throw-function-naming.mjs +++ b/lib/rules/throw-function-naming.js @@ -1,8 +1,6 @@ -import { hasThrowInBlock } from "../utils.mjs"; +import { hasThrowInBlock } from "../utils.js"; -/** - * @type {import("eslint").Rule.RuleModule} - */ +/** @type {import("eslint").Rule.RuleModule} */ export default { meta: { type: "suggestion", @@ -10,7 +8,7 @@ export default { description: "enforce function names to end with a specified suffix (default to 'OrThrow') if they throw exceptions", category: "Best Practices", - recommended: "error", + recommended: true, }, messages: { missingSuffix: @@ -34,7 +32,7 @@ export default { const options = context.options[0] ?? {}; const suffix = options.suffix ?? "OrThrow"; - /** @param {(import("estree").ArrowFunctionExpression | (import("estree").FunctionDeclaration)) & import("eslint").Rule.NodeParentExtension} node */ + /** @param {(import("estree").ArrowFunctionExpression | import("estree").FunctionExpression | import("estree").FunctionDeclaration) & import("eslint").Rule.NodeParentExtension} node */ function checkFunctionName(node) { const hasThrow = hasThrowInBlock(node.body.body); diff --git a/lib/utils.mjs b/lib/utils.js similarity index 93% rename from lib/utils.mjs rename to lib/utils.js index 91b3382..9c62d55 100644 --- a/lib/utils.mjs +++ b/lib/utils.js @@ -7,7 +7,9 @@ export function getThrowTypes(block = []) { function checkAndAddThrowType(block = []) { const handlerThrowTypes = getThrowTypes(block); if (handlerThrowTypes.size > 0) { - throwTypes.add(...handlerThrowTypes); + for (const type of handlerThrowTypes) { + throwTypes.add(type); + } } } @@ -42,7 +44,10 @@ export function getThrowTypes(block = []) { // Handle IfStatement if (statement.type === "IfStatement") { checkAndAddThrowType([statement.consequent]); - statement.alternate && checkAndAddThrowType([statement.alternate]); + + if (statement.alternate) { + checkAndAddThrowType([statement.alternate]); + } } // Handle DoWhileStatement and WhileStatement @@ -76,7 +81,10 @@ export function getThrowTypes(block = []) { return throwTypes; } -/** @param {import("estree").Statement[]} block */ +/** + * @param {import("estree").Statement[]} block + * @returns {boolean} + */ export function hasThrowInBlock(block = []) { if (!Array.isArray(block)) return false; diff --git a/package-lock.json b/package-lock.json index 2f0f0ed..b4aa8c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,22 +1,24 @@ { "name": "eslint-plugin-throw-aware", - "version": "1.0.0-beta.6", + "version": "1.0.0-beta.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "eslint-plugin-throw-aware", - "version": "1.0.0-beta.6", + "version": "1.0.0-beta.7", "license": "Unlicense", "devDependencies": { "@eslint/js": "^9.10.0", "ava": "^6.1.3", "eslint": "^9.10.0", "eslint-ava-rule-tester": "^5.0.1", + "eslint-plugin-ava": "^15.0.1", "eslint-plugin-eslint-plugin": "^6.2.0", "eslint-plugin-n": "^17.10.2", "globals": "^15.9.0", - "prettier": "^3.3.3" + "prettier": "^3.3.3", + "typescript": "^5.6.2" }, "peerDependencies": { "eslint": ">=9.0.0" @@ -341,9 +343,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", - "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", "dev": true, "license": "MIT", "dependencies": { @@ -384,9 +386,9 @@ } }, "node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "license": "MIT", "engines": { @@ -952,6 +954,19 @@ "dev": true, "license": "MIT" }, + "node_modules/enhance-visitors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/enhance-visitors/-/enhance-visitors-1.0.0.tgz", + "integrity": "sha512-+29eJLiUixTEDRaZ35Vu8jP3gPLNcQQkQkOQjLp2X+6cZGGPDD/uasbFzvLsJKnGZnvmyZ0srxudwOtskHeIDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.13.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/enhanced-resolve": { "version": "5.17.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", @@ -1078,6 +1093,60 @@ "eslint": ">=6.0.0" } }, + "node_modules/eslint-plugin-ava": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-ava/-/eslint-plugin-ava-15.0.1.tgz", + "integrity": "sha512-eRX7mLFPvalGDWztJ4zm+anez2X6J/88r9CqLFfPAIMvFlGyJ+dUoFppoohgUQZLV09mIBNz5guP07zFJOLF8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "enhance-visitors": "^1.0.0", + "eslint-utils": "^3.0.0", + "espree": "^9.0.0", + "espurify": "^2.1.1", + "import-modules": "^2.1.0", + "micro-spelling-correcter": "^1.1.1", + "pkg-dir": "^5.0.0", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": "^18.18 || >=20" + }, + "peerDependencies": { + "eslint": ">=9" + } + }, + "node_modules/eslint-plugin-ava/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-ava/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/eslint-plugin-es-x": { "version": "7.8.0", "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz", @@ -1186,6 +1255,35 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, "node_modules/eslint-visitor-keys": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", @@ -1287,6 +1385,13 @@ "node": ">=4" } }, + "node_modules/espurify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/espurify/-/espurify-2.1.1.tgz", + "integrity": "sha512-zttWvnkhcDyGOhSH4vO2qCBILpdCMv/MX8lp4cqgRkQoDRGK2oZxi2GfWhlP2dIXmk7BaKeOTuzbHhyC68o8XQ==", + "dev": true, + "license": "MIT" + }, "node_modules/esquery": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", @@ -1642,9 +1747,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.0.tgz", - "integrity": "sha512-Pgba6TExTZ0FJAn1qkJAjIeKoDJ3CsI2ChuLohJnZl/tTU8MVrq3b+2t5UOPfRa4RMsorClBjJALkJUMjG1PAw==", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz", + "integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==", "dev": true, "license": "MIT", "dependencies": { @@ -1808,6 +1913,19 @@ "node": ">=4" } }, + "node_modules/import-modules": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-modules/-/import-modules-2.1.0.tgz", + "integrity": "sha512-8HEWcnkbGpovH9yInoisxaSoIg9Brbul+Ju3Kqe2UsYDUBJD/iQjSgEj0zPcTDPKfPp2fs5xlv1i+JSye/m1/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -1934,9 +2052,9 @@ "license": "MIT" }, "node_modules/is-unicode-supported": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.0.0.tgz", - "integrity": "sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", "dev": true, "license": "MIT", "engines": { @@ -2158,6 +2276,13 @@ "node": ">= 8" } }, + "node_modules/micro-spelling-correcter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/micro-spelling-correcter/-/micro-spelling-correcter-1.1.1.tgz", + "integrity": "sha512-lkJ3Rj/mtjlRcHk6YyCbvZhyWTOzdBvTHsxMmZSk5jxN1YyVSQ+JETAom55mdzfcyDrY/49Z7UCW760BK30crg==", + "dev": true, + "license": "CC0-1.0" + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -2540,6 +2665,19 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pkg-dir": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", + "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^5.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/plur": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/plur/-/plur-5.1.0.tgz", @@ -3097,6 +3235,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typescript": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/unicorn-magic": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", diff --git a/package.json b/package.json index 642978f..a38d4a1 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,21 @@ { "name": "eslint-plugin-throw-aware", - "version": "1.0.0-beta.6", + "version": "1.0.0-beta.7", "description": "An ESLint plugin to enforce naming conventions and JSDoc annotations for functions that throw exceptions.", "type": "module", - "module": "lib/index.mjs", + "main": "cjs/index.js", + "module": "lib/index.js", "exports": { - "import": "./lib/index.mjs" + ".": { + "import": "./lib/index.js", + "require": "./cjs/index.js" + } }, "scripts": { - "test": "ava" + "lint": "eslint 'lib/**/*.js'", + "build": "tsc --project tsconfig.json", + "test": "ava", + "prepublishOnly": "rm -rf cjs/ && npm run lint && npm run test && npm run build" }, "repository": { "type": "git", @@ -33,9 +40,11 @@ "ava": "^6.1.3", "eslint": "^9.10.0", "eslint-ava-rule-tester": "^5.0.1", + "eslint-plugin-ava": "^15.0.1", "eslint-plugin-eslint-plugin": "^6.2.0", "eslint-plugin-n": "^17.10.2", "globals": "^15.9.0", - "prettier": "^3.3.3" + "prettier": "^3.3.3", + "typescript": "^5.6.2" } } diff --git a/tests/require-throws-doc.test.mjs b/tests/require-throws-doc.test.js similarity index 97% rename from tests/require-throws-doc.test.mjs rename to tests/require-throws-doc.test.js index d71ddde..75cde22 100644 --- a/tests/require-throws-doc.test.mjs +++ b/tests/require-throws-doc.test.js @@ -1,9 +1,9 @@ import test from "ava"; import AvaRuleTester from "eslint-ava-rule-tester"; -import rule from "../lib/rules/require-throws-doc.mjs"; +import rule from "../lib/rules/require-throws-doc.js"; const ruleTester = new AvaRuleTester(test, { - languageOptions: { ecmaVersion: 2021, sourceType: "module" }, + languageOptions: { ecmaVersion: 2020, sourceType: "module" }, }); ruleTester.run("require-throws-doc", rule, { diff --git a/tests/throw-function-naming.test.js b/tests/throw-function-naming.test.js new file mode 100644 index 0000000..aac5c29 --- /dev/null +++ b/tests/throw-function-naming.test.js @@ -0,0 +1,112 @@ +import test from "ava"; +import AvaRuleTester from "eslint-ava-rule-tester"; +import rule from "../lib/rules/throw-function-naming.js"; + +const ruleTester = new AvaRuleTester(test, { + languageOptions: { ecmaVersion: 2020, sourceType: "module" }, +}); + +ruleTester.run("throw-function-naming", rule, { + /** @type {import("eslint").RuleTester.ValidTestCase[]} */ + valid: [ + { + code: ` + function testOrThrow() { + throw new Error('test'); + } + `, + }, + // Async function that throws error + { + code: ` + async function getDataOrThrow() { + throw new Error("No data"); + } + `, + }, + // Nested function that throws error + // FIXME outerFunction should be renamed to outerFunctionOrThrow too + { + code: ` + function outerFunction() { + function innerFunctionOrThrow() { + throw new Error("Inner error"); + } + innerFunctionOrThrow(); + } + `, + }, + // Function with no JSDoc comments + { + code: ` + function doSomethingOrThrow() { + throw new Error("Something went wrong"); + } + `, + }, + ], + /** @type {import("eslint").RuleTester.InvalidTestCase[]} */ + invalid: [ + { + code: ` + function test() { + throw new Error('test'); + } + `, + errors: [{ messageId: "missingSuffix", data: { name: "test", suffix: "OrThrow" } }], + output: ` + function testOrThrow() { + throw new Error('test'); + } + `, + }, + { + code: ` + function test() { + throw new Error('test'); + } + `, + options: [{ suffix: "MayFail" }], + errors: [{ messageId: "missingSuffix", data: { name: "test", suffix: "MayFail" } }], + output: ` + function testMayFail() { + throw new Error('test'); + } + `, + }, + // Async function without OrThrow suffix + { + code: ` + async function getData() { + throw new Error("No data"); + } + `, + errors: [{ messageId: "missingSuffix", data: { name: "getData", suffix: "OrThrow" } }], + output: ` + async function getDataOrThrow() { + throw new Error("No data"); + } + `, + }, + // Nested function without OrThrow suffix + { + code: ` + function outerFunction() { + function innerFunction() { + throw new Error("Inner error"); + } + innerFunction(); + } + `, + errors: [{ messageId: "missingSuffix", data: { name: "innerFunction", suffix: "OrThrow" } }], + output: ` + function outerFunction() { + function innerFunctionOrThrow() { + throw new Error("Inner error"); + } + innerFunctionOrThrow(); + } + `, + }, + ], +}); diff --git a/tests/throw-function-naming.test.mjs b/tests/throw-function-naming.test.mjs deleted file mode 100644 index e0d014d..0000000 --- a/tests/throw-function-naming.test.mjs +++ /dev/null @@ -1,50 +0,0 @@ -import test from "ava"; -import AvaRuleTester from "eslint-ava-rule-tester"; -import rule from "../lib/rules/throw-function-naming.mjs"; - -const ruleTester = new AvaRuleTester(test, { - languageOptions: { ecmaVersion: 2021, sourceType: "module" }, -}); - -ruleTester.run("throw-function-naming", rule, { - /** @type {import("eslint").RuleTester.ValidTestCase[]} */ - valid: [ - { - code: ` - function testOrThrow() { - throw new Error('test'); - } - `, - }, - ], - /** @type {import("eslint").RuleTester.InvalidTestCase[]} */ - invalid: [ - { - code: ` - function test() { - throw new Error('test'); - } - `, - errors: [{ messageId: "missingSuffix", data: { name: "test", suffix: "OrThrow" } }], - output: ` - function testOrThrow() { - throw new Error('test'); - } - `, - }, - { - code: ` - function test() { - throw new Error('test'); - } - `, - options: [{ suffix: "MayFail" }], - errors: [{ messageId: "missingSuffix", data: { name: "test", suffix: "MayFail" } }], - output: ` - function testMayFail() { - throw new Error('test'); - } - `, - }, - ], -}); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..928df35 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "allowJs": true, + "target": "ES2020", + "module": "CommonJS", + "moduleResolution": "Node10", + "outDir": "cjs", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true + }, + "include": ["lib/**/*.js"], + "exclude": ["node_modules", "examples"] +}