From 1daa41bb2ac6e0bffdb0f2f64258f3f9b22537c2 Mon Sep 17 00:00:00 2001 From: Levi Buzolic Date: Thu, 15 Aug 2024 21:48:25 +1000 Subject: [PATCH] Update formatting following Biomes rules --- biome.json | 18 +- eslint.config.js | 32 ++-- index.js | 6 +- package.json | 83 +++++---- rules/no-only-tests.js | 237 ++++++++++++------------ tests.js | 396 +++++++++++++++++++++-------------------- tsconfig.json | 36 ++-- 7 files changed, 405 insertions(+), 403 deletions(-) diff --git a/biome.json b/biome.json index f4a1db5..7889a97 100644 --- a/biome.json +++ b/biome.json @@ -1,11 +1,11 @@ { - "$schema": "https://biomejs.dev/schemas/1.8.3/schema.json", - "organizeImports": { "enabled": true }, - "linter": { - "enabled": true, - "rules": { "recommended": true } - }, - "formatter": { - "enabled": true - } + "$schema": "https://biomejs.dev/schemas/1.8.3/schema.json", + "organizeImports": { "enabled": true }, + "linter": { + "enabled": true, + "rules": { "recommended": true } + }, + "formatter": { + "enabled": true + } } diff --git a/eslint.config.js b/eslint.config.js index b38b052..066cb16 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,20 +1,20 @@ -const plugin = require('./index'); -const js = require('@eslint/js'); +const plugin = require("./index"); +const js = require("@eslint/js"); /** @type {import('eslint').Linter.Config} */ module.exports = [ - js.configs.recommended, - { - files: ['**/*.js'], - languageOptions: { - sourceType: 'commonjs', - ecmaVersion: 'latest', - }, - plugins: { - 'no-only-tests': plugin, - }, - rules: { - 'no-only-tests/no-only-tests': 'error', - }, - }, + js.configs.recommended, + { + files: ["**/*.js"], + languageOptions: { + sourceType: "commonjs", + ecmaVersion: "latest", + }, + plugins: { + "no-only-tests": plugin, + }, + rules: { + "no-only-tests/no-only-tests": "error", + }, + }, ]; diff --git a/index.js b/index.js index 24cc6d3..4c750f0 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ module.exports = { - rules: { - 'no-only-tests': require('./rules/no-only-tests'), - }, + rules: { + "no-only-tests": require("./rules/no-only-tests"), + }, }; diff --git a/package.json b/package.json index 3a087ee..0f222d8 100644 --- a/package.json +++ b/package.json @@ -1,45 +1,42 @@ { - "name": "eslint-plugin-no-only-tests", - "version": "4.0.0", - "description": "ESLint rule for .only blocks in mocha tests", - "keywords": [ - "eslint", - "eslintplugin", - "eslint-plugin", - "mocha", - "rule", - "only", - "describe", - "it", - "fixture" - ], - "author": "Levi Buzolic", - "main": "index.js", - "files": [ - "index.js", - "rules/" - ], - "scripts": { - "test": "node tests.js" - }, - "devDependencies": { - "@biomejs/biome": "^1.8.3", - "@types/eslint": "^9.6.0", - "@types/eslint__js": "^8.42.3", - "@types/node": "^22.3.0", - "eslint": ">=9.0.0", - "typescript": "^5.5.4" - }, - "engines": { - "node": ">=5.0.0" - }, - "license": "MIT", - "repository": { - "type": "git", - "url": "git@github.com:levibuzolic/eslint-plugin-no-only-tests.git" - }, - "bugs": { - "url": "https://github.com/levibuzolic/no-only-tests/issues" - }, - "homepage": "https://github.com/levibuzolic/no-only-tests#readme" + "name": "eslint-plugin-no-only-tests", + "version": "4.0.0", + "description": "ESLint rule for .only blocks in mocha tests", + "keywords": [ + "eslint", + "eslintplugin", + "eslint-plugin", + "mocha", + "rule", + "only", + "describe", + "it", + "fixture" + ], + "author": "Levi Buzolic", + "main": "index.js", + "files": ["index.js", "rules/"], + "scripts": { + "test": "node tests.js" + }, + "devDependencies": { + "@biomejs/biome": "^1.8.3", + "@types/eslint": "^9.6.0", + "@types/eslint__js": "^8.42.3", + "@types/node": "^22.3.0", + "eslint": ">=9.0.0", + "typescript": "^5.5.4" + }, + "engines": { + "node": ">=5.0.0" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "git@github.com:levibuzolic/eslint-plugin-no-only-tests.git" + }, + "bugs": { + "url": "https://github.com/levibuzolic/no-only-tests/issues" + }, + "homepage": "https://github.com/levibuzolic/no-only-tests#readme" } diff --git a/rules/no-only-tests.js b/rules/no-only-tests.js index 2fb8455..758a165 100644 --- a/rules/no-only-tests.js +++ b/rules/no-only-tests.js @@ -7,119 +7,121 @@ /** @type {Options} */ const defaultOptions = { - block: [ - 'describe', - 'it', - 'context', - 'test', - 'tape', - 'fixture', - 'serial', - 'Feature', - 'Scenario', - 'Given', - 'And', - 'When', - 'Then', - ], - focus: ['only'], - functions: [], - fix: false, + block: [ + "describe", + "it", + "context", + "test", + "tape", + "fixture", + "serial", + "Feature", + "Scenario", + "Given", + "And", + "When", + "Then", + ], + focus: ["only"], + functions: [], + fix: false, }; /** @type {import('eslint').Rule.RuleModule} */ module.exports = { - meta: { - docs: { - description: 'disallow .only blocks in tests', - category: 'Possible Errors', - recommended: true, - url: 'https://github.com/levibuzolic/eslint-plugin-no-only-tests', - }, - fixable: 'code', - schema: [ - { - type: 'object', - properties: { - block: { - type: 'array', - items: { - type: 'string', - }, - uniqueItems: true, - default: defaultOptions.block, - }, - focus: { - type: 'array', - items: { - type: 'string', - }, - uniqueItems: true, - default: defaultOptions.focus, - }, - functions: { - type: 'array', - items: { - type: 'string', - }, - uniqueItems: true, - default: defaultOptions.functions, - }, - fix: { - type: 'boolean', - default: defaultOptions.fix, - }, - }, - additionalProperties: false, - }, - ], - }, - create(context) { - /** @type {Options} */ - const options = Object.assign({}, defaultOptions, context.options[0]); - const blocks = options.block || []; - const focus = options.focus || []; - const functions = options.functions || []; - const fix = !!options.fix; + meta: { + docs: { + description: "disallow .only blocks in tests", + category: "Possible Errors", + recommended: true, + url: "https://github.com/levibuzolic/eslint-plugin-no-only-tests", + }, + fixable: "code", + schema: [ + { + type: "object", + properties: { + block: { + type: "array", + items: { + type: "string", + }, + uniqueItems: true, + default: defaultOptions.block, + }, + focus: { + type: "array", + items: { + type: "string", + }, + uniqueItems: true, + default: defaultOptions.focus, + }, + functions: { + type: "array", + items: { + type: "string", + }, + uniqueItems: true, + default: defaultOptions.functions, + }, + fix: { + type: "boolean", + default: defaultOptions.fix, + }, + }, + additionalProperties: false, + }, + ], + }, + create(context) { + /** @type {Options} */ + const options = Object.assign({}, defaultOptions, context.options[0]); + const blocks = options.block || []; + const focus = options.focus || []; + const functions = options.functions || []; + const fix = !!options.fix; - return { - Identifier(node) { - if (functions.length && functions.indexOf(node.name) > -1) { - context.report({ - node, - message: `${node.name} not permitted`, - }); - } + return { + Identifier(node) { + if (functions.length && functions.indexOf(node.name) > -1) { + context.report({ + node, + message: `${node.name} not permitted`, + }); + } - const parentObject = 'object' in node.parent ? node.parent.object : undefined; - if (parentObject == null) return; - if (focus.indexOf(node.name) === -1) return; + const parentObject = + "object" in node.parent ? node.parent.object : undefined; + if (parentObject == null) return; + if (focus.indexOf(node.name) === -1) return; - const callPath = getCallPath(node.parent).join('.'); + const callPath = getCallPath(node.parent).join("."); - // comparison guarantees that matching is done with the beginning of call path - if ( - blocks.find(block => { - // Allow wildcard tail matching of blocks when ending in a `*` - if (block.endsWith('*')) return callPath.startsWith(block.replace(/\*$/, '')); - return callPath.startsWith(`${block}.`); - }) - ) { - const rangeStart = node.range?.[0]; - const rangeEnd = node.range?.[1]; + // comparison guarantees that matching is done with the beginning of call path + if ( + blocks.find((block) => { + // Allow wildcard tail matching of blocks when ending in a `*` + if (block.endsWith("*")) + return callPath.startsWith(block.replace(/\*$/, "")); + return callPath.startsWith(`${block}.`); + }) + ) { + const rangeStart = node.range?.[0]; + const rangeEnd = node.range?.[1]; - context.report({ - node, - message: `${callPath} not permitted`, - fix: - fix && rangeStart != null && rangeEnd != null - ? fixer => fixer.removeRange([rangeStart - 1, rangeEnd]) - : undefined, - }); - } - }, - }; - }, + context.report({ + node, + message: `${callPath} not permitted`, + fix: + fix && rangeStart != null && rangeEnd != null + ? (fixer) => fixer.removeRange([rangeStart - 1, rangeEnd]) + : undefined, + }); + } + }, + }; + }, }; /** @@ -129,17 +131,18 @@ module.exports = { * @returns */ function getCallPath(node, path = []) { - if (node) { - const nodeName = - 'name' in node && node.name - ? node.name - : 'property' in node && node.property && 'name' in node.property - ? node.property?.name - : undefined; - if ('object' in node && node.object && nodeName) return getCallPath(node.object, [nodeName, ...path]); - if ('callee' in node && node.callee) return getCallPath(node.callee, path); - if (nodeName) return [nodeName, ...path]; - return path; - } - return path; + if (node) { + const nodeName = + "name" in node && node.name + ? node.name + : "property" in node && node.property && "name" in node.property + ? node.property?.name + : undefined; + if ("object" in node && node.object && nodeName) + return getCallPath(node.object, [nodeName, ...path]); + if ("callee" in node && node.callee) return getCallPath(node.callee, path); + if (nodeName) return [nodeName, ...path]; + return path; + } + return path; } diff --git a/tests.js b/tests.js index 9d940c6..8c20f5a 100644 --- a/tests.js +++ b/tests.js @@ -1,203 +1,205 @@ -const rules = require('./index').rules; -const RuleTester = require('eslint').RuleTester; +const rules = require("./index").rules; +const RuleTester = require("eslint").RuleTester; const ruleTester = new RuleTester(); -ruleTester.run('no-only-tests', rules['no-only-tests'], { - valid: [ - 'describe("Some describe block", function() {});', - 'it("Some assertion", function() {});', - 'xit.only("Some assertion", function() {});', - 'xdescribe.only("Some describe block", function() {});', - 'xcontext.only("A context block", function() {});', - 'xtape.only("A tape block", function() {});', - 'xtest.only("A test block", function() {});', - 'other.only("An other block", function() {});', - 'testResource.only("A test resource block", function() {});', - 'var args = {only: "test"};', - 'it("should pass meta only through", function() {});', - 'obscureTestBlock.only("An obscure testing library test works unless options are supplied", function() {});', - { - options: [{block: ['it']}], - code: 'test.only("Options will exclude this from being caught", function() {});', - }, - { - options: [{focus: ['focus']}], - code: 'test.only("Options will exclude this from being caught", function() {});', - }, - { - options: [{functions: ['fit', 'xit']}], - code: 'it("Options will exclude this from being caught", function() {});', - }, - ], +ruleTester.run("no-only-tests", rules["no-only-tests"], { + valid: [ + 'describe("Some describe block", function() {});', + 'it("Some assertion", function() {});', + 'xit.only("Some assertion", function() {});', + 'xdescribe.only("Some describe block", function() {});', + 'xcontext.only("A context block", function() {});', + 'xtape.only("A tape block", function() {});', + 'xtest.only("A test block", function() {});', + 'other.only("An other block", function() {});', + 'testResource.only("A test resource block", function() {});', + 'var args = {only: "test"};', + 'it("should pass meta only through", function() {});', + 'obscureTestBlock.only("An obscure testing library test works unless options are supplied", function() {});', + { + options: [{ block: ["it"] }], + code: 'test.only("Options will exclude this from being caught", function() {});', + }, + { + options: [{ focus: ["focus"] }], + code: 'test.only("Options will exclude this from being caught", function() {});', + }, + { + options: [{ functions: ["fit", "xit"] }], + code: 'it("Options will exclude this from being caught", function() {});', + }, + ], - invalid: [ - { - code: 'describe.only("Some describe block", function() {});', - errors: [{message: 'describe.only not permitted'}], - }, - { - code: 'it.only("Some assertion", function() {});', - errors: [{message: 'it.only not permitted'}], - }, - { - code: 'context.only("Some context", function() {});', - errors: [{message: 'context.only not permitted'}], - }, - { - code: 'test.only("Some test", function() {});', - errors: [{message: 'test.only not permitted'}], - }, - { - code: 'tape.only("A tape", function() {});', - errors: [{message: 'tape.only not permitted'}], - }, - { - code: 'fixture.only("A fixture", function() {});', - errors: [{message: 'fixture.only not permitted'}], - }, - { - code: 'serial.only("A serial test", function() {});', - errors: [{message: 'serial.only not permitted'}], - }, - { - options: [{block: ['obscureTestBlock']}], - code: 'obscureTestBlock.only("An obscure testing library test", function() {});', - errors: [{message: 'obscureTestBlock.only not permitted'}], - }, - { - options: [{block: ['ava.default']}], - code: 'ava.default.only("Block with dot", function() {});', - errors: [{message: 'ava.default.only not permitted'}], - }, - { - code: 'it.default.before(console.log).only("Some describe block", function() {});', - errors: [{message: 'it.default.before.only not permitted'}], - }, - { - options: [{focus: ['focus']}], - code: 'test.focus("An alternative focus function", function() {});', - errors: [{message: 'test.focus not permitted'}], - }, - // As above, but with fix: true option to enable auto-fixing - { - options: [{fix: true}], - code: 'describe.only("Some describe block", function() {});', - output: 'describe("Some describe block", function() {});', - errors: [{message: 'describe.only not permitted'}], - }, - { - options: [{fix: true}], - code: 'it.only("Some assertion", function() {});', - output: 'it("Some assertion", function() {});', - errors: [{message: 'it.only not permitted'}], - }, - { - options: [{fix: true}], - code: 'context.only("Some context", function() {});', - output: 'context("Some context", function() {});', - errors: [{message: 'context.only not permitted'}], - }, - { - options: [{fix: true}], - code: 'test.only("Some test", function() {});', - output: 'test("Some test", function() {});', - errors: [{message: 'test.only not permitted'}], - }, - { - options: [{fix: true}], - code: 'tape.only("A tape", function() {});', - output: 'tape("A tape", function() {});', - errors: [{message: 'tape.only not permitted'}], - }, - { - options: [{fix: true}], - code: 'fixture.only("A fixture", function() {});', - output: 'fixture("A fixture", function() {});', - errors: [{message: 'fixture.only not permitted'}], - }, - { - options: [{fix: true}], - code: 'serial.only("A serial test", function() {});', - output: 'serial("A serial test", function() {});', - errors: [{message: 'serial.only not permitted'}], - }, - { - options: [{block: ['obscureTestBlock'], fix: true}], - code: 'obscureTestBlock.only("An obscure testing library test", function() {});', - output: 'obscureTestBlock("An obscure testing library test", function() {});', - errors: [{message: 'obscureTestBlock.only not permitted'}], - }, - { - options: [{block: ['ava.default'], fix: true}], - code: 'ava.default.only("Block with dot", function() {});', - output: 'ava.default("Block with dot", function() {});', - errors: [{message: 'ava.default.only not permitted'}], - }, - { - options: [{fix: true}], - code: 'it.default.before(console.log).only("Some describe block", function() {});', - errors: [{message: 'it.default.before.only not permitted'}], - output: 'it.default.before(console.log)("Some describe block", function() {});', - }, - { - options: [{focus: ['focus'], fix: true}], - code: 'test.focus("An alternative focus function", function() {});', - output: 'test("An alternative focus function", function() {});', - errors: [{message: 'test.focus not permitted'}], - }, - { - options: [{block: ['test*']}], - code: 'testResource.only("A test resource block", function() {});', - errors: [{message: 'testResource.only not permitted'}], - }, - { - options: [{fix: true}], - code: 'Feature.only("Some Feature", function() {});', - output: 'Feature("Some Feature", function() {});', - errors: [{message: 'Feature.only not permitted'}], - }, - { - options: [{fix: true}], - code: 'Scenario.only("Some Scenario", function() {});', - output: 'Scenario("Some Scenario", function() {});', - errors: [{message: 'Scenario.only not permitted'}], - }, - { - options: [{fix: true}], - code: 'Given.only("Some assertion", function() {});', - output: 'Given("Some assertion", function() {});', - errors: [{message: 'Given.only not permitted'}], - }, - { - options: [{fix: true}], - code: 'And.only("Some assertion", function() {});', - output: 'And("Some assertion", function() {});', - errors: [{message: 'And.only not permitted'}], - }, - { - options: [{fix: true}], - code: 'When.only("Some assertion", function() {});', - output: 'When("Some assertion", function() {});', - errors: [{message: 'When.only not permitted'}], - }, - { - options: [{fix: true}], - code: 'Then.only("Some assertion", function() {});', - output: 'Then("Some assertion", function() {});', - errors: [{message: 'Then.only not permitted'}], - }, - { - options: [{functions: ['fit', 'xit']}], - code: 'xit("No skipped tests", function() {});', - errors: [{message: 'xit not permitted'}], - }, - { - options: [{functions: ['fit', 'xit'], fix: true}], - code: 'xit("No skipped tests", function() {});', - errors: [{message: 'xit not permitted'}], - }, - ], + invalid: [ + { + code: 'describe.only("Some describe block", function() {});', + errors: [{ message: "describe.only not permitted" }], + }, + { + code: 'it.only("Some assertion", function() {});', + errors: [{ message: "it.only not permitted" }], + }, + { + code: 'context.only("Some context", function() {});', + errors: [{ message: "context.only not permitted" }], + }, + { + code: 'test.only("Some test", function() {});', + errors: [{ message: "test.only not permitted" }], + }, + { + code: 'tape.only("A tape", function() {});', + errors: [{ message: "tape.only not permitted" }], + }, + { + code: 'fixture.only("A fixture", function() {});', + errors: [{ message: "fixture.only not permitted" }], + }, + { + code: 'serial.only("A serial test", function() {});', + errors: [{ message: "serial.only not permitted" }], + }, + { + options: [{ block: ["obscureTestBlock"] }], + code: 'obscureTestBlock.only("An obscure testing library test", function() {});', + errors: [{ message: "obscureTestBlock.only not permitted" }], + }, + { + options: [{ block: ["ava.default"] }], + code: 'ava.default.only("Block with dot", function() {});', + errors: [{ message: "ava.default.only not permitted" }], + }, + { + code: 'it.default.before(console.log).only("Some describe block", function() {});', + errors: [{ message: "it.default.before.only not permitted" }], + }, + { + options: [{ focus: ["focus"] }], + code: 'test.focus("An alternative focus function", function() {});', + errors: [{ message: "test.focus not permitted" }], + }, + // As above, but with fix: true option to enable auto-fixing + { + options: [{ fix: true }], + code: 'describe.only("Some describe block", function() {});', + output: 'describe("Some describe block", function() {});', + errors: [{ message: "describe.only not permitted" }], + }, + { + options: [{ fix: true }], + code: 'it.only("Some assertion", function() {});', + output: 'it("Some assertion", function() {});', + errors: [{ message: "it.only not permitted" }], + }, + { + options: [{ fix: true }], + code: 'context.only("Some context", function() {});', + output: 'context("Some context", function() {});', + errors: [{ message: "context.only not permitted" }], + }, + { + options: [{ fix: true }], + code: 'test.only("Some test", function() {});', + output: 'test("Some test", function() {});', + errors: [{ message: "test.only not permitted" }], + }, + { + options: [{ fix: true }], + code: 'tape.only("A tape", function() {});', + output: 'tape("A tape", function() {});', + errors: [{ message: "tape.only not permitted" }], + }, + { + options: [{ fix: true }], + code: 'fixture.only("A fixture", function() {});', + output: 'fixture("A fixture", function() {});', + errors: [{ message: "fixture.only not permitted" }], + }, + { + options: [{ fix: true }], + code: 'serial.only("A serial test", function() {});', + output: 'serial("A serial test", function() {});', + errors: [{ message: "serial.only not permitted" }], + }, + { + options: [{ block: ["obscureTestBlock"], fix: true }], + code: 'obscureTestBlock.only("An obscure testing library test", function() {});', + output: + 'obscureTestBlock("An obscure testing library test", function() {});', + errors: [{ message: "obscureTestBlock.only not permitted" }], + }, + { + options: [{ block: ["ava.default"], fix: true }], + code: 'ava.default.only("Block with dot", function() {});', + output: 'ava.default("Block with dot", function() {});', + errors: [{ message: "ava.default.only not permitted" }], + }, + { + options: [{ fix: true }], + code: 'it.default.before(console.log).only("Some describe block", function() {});', + errors: [{ message: "it.default.before.only not permitted" }], + output: + 'it.default.before(console.log)("Some describe block", function() {});', + }, + { + options: [{ focus: ["focus"], fix: true }], + code: 'test.focus("An alternative focus function", function() {});', + output: 'test("An alternative focus function", function() {});', + errors: [{ message: "test.focus not permitted" }], + }, + { + options: [{ block: ["test*"] }], + code: 'testResource.only("A test resource block", function() {});', + errors: [{ message: "testResource.only not permitted" }], + }, + { + options: [{ fix: true }], + code: 'Feature.only("Some Feature", function() {});', + output: 'Feature("Some Feature", function() {});', + errors: [{ message: "Feature.only not permitted" }], + }, + { + options: [{ fix: true }], + code: 'Scenario.only("Some Scenario", function() {});', + output: 'Scenario("Some Scenario", function() {});', + errors: [{ message: "Scenario.only not permitted" }], + }, + { + options: [{ fix: true }], + code: 'Given.only("Some assertion", function() {});', + output: 'Given("Some assertion", function() {});', + errors: [{ message: "Given.only not permitted" }], + }, + { + options: [{ fix: true }], + code: 'And.only("Some assertion", function() {});', + output: 'And("Some assertion", function() {});', + errors: [{ message: "And.only not permitted" }], + }, + { + options: [{ fix: true }], + code: 'When.only("Some assertion", function() {});', + output: 'When("Some assertion", function() {});', + errors: [{ message: "When.only not permitted" }], + }, + { + options: [{ fix: true }], + code: 'Then.only("Some assertion", function() {});', + output: 'Then("Some assertion", function() {});', + errors: [{ message: "Then.only not permitted" }], + }, + { + options: [{ functions: ["fit", "xit"] }], + code: 'xit("No skipped tests", function() {});', + errors: [{ message: "xit not permitted" }], + }, + { + options: [{ functions: ["fit", "xit"], fix: true }], + code: 'xit("No skipped tests", function() {});', + errors: [{ message: "xit not permitted" }], + }, + ], }); /* global process */ -process.stderr.write('\n✅ Tests completed successfully\n'); +process.stderr.write("\n✅ Tests completed successfully\n"); diff --git a/tsconfig.json b/tsconfig.json index 89a0b30..e7bb6c3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,20 +1,20 @@ { - "compilerOptions": { - /* Base Options: */ - "esModuleInterop": true, - "skipLibCheck": true, - "target": "es2022", - "allowJs": true, - "checkJs": true, - "resolveJsonModule": true, - "moduleDetection": "force", - "isolatedModules": true, - "verbatimModuleSyntax": true, - "strict": true, - "noUncheckedIndexedAccess": true, - "noImplicitOverride": true, - "module": "preserve", - "noEmit": true, - "lib": ["es2022"] - } + "compilerOptions": { + /* Base Options: */ + "esModuleInterop": true, + "skipLibCheck": true, + "target": "es2022", + "allowJs": true, + "checkJs": true, + "resolveJsonModule": true, + "moduleDetection": "force", + "isolatedModules": true, + "verbatimModuleSyntax": true, + "strict": true, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, + "module": "preserve", + "noEmit": true, + "lib": ["es2022"] + } }