From 5ff7e7f9a1ef59b0d01e1e9b3ee7041f9622fb6d Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Mon, 7 Apr 2025 21:08:29 -0700 Subject: [PATCH] Updated to eslint 9 This isn't officially compatible with the oldest version of Node that Jasmine supports, but it works. If it stops working, we can always disable linting in CI builds on older Node versions. --- .editorconfig | 2 +- eslint.config.mjs | 54 +++++++++++++++++++ package.json | 7 ++- spec/core/EnvSpec.js | 1 - spec/core/QueueRunnerSpec.js | 8 --- spec/core/SpySpec.js | 6 --- spec/core/integration/EnvSpec.js | 14 ++--- spec/core/integration/SpecRunningSpec.js | 1 - spec/core/matchers/matchersUtilSpec.js | 5 -- spec/core/matchers/toEqualSpec.js | 1 - .../toHaveNoOtherSpyInteractionsSpec.js | 2 +- .../matchers/toHaveSpyInteractionsSpec.js | 2 +- spec/support/ci.js | 1 + src/core/Deprecator.js | 2 + src/core/Env.js | 2 + src/core/PrettyPrinter.js | 2 + src/core/QueueRunner.js | 2 + src/core/SpyRegistry.js | 1 + src/core/matchers/toBeInstanceOf.js | 1 + src/html/HtmlReporter.js | 2 + 20 files changed, 80 insertions(+), 36 deletions(-) create mode 100644 eslint.config.mjs diff --git a/.editorconfig b/.editorconfig index 12562f79..0ba33458 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,6 +3,6 @@ charset = utf-8 end_of_line = lf insert_final_newline = true -[*.{js, json, sh, yml}] +[*.{js, mjs, json, sh, yml}] indent_style = space indent_size = 2 diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 00000000..afe200f2 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,54 @@ +import { defineConfig } from "eslint/config"; +import globals from "globals"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import js from "@eslint/js"; +import { FlatCompat } from "@eslint/eslintrc"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + allConfig: js.configs.all +}); + +export default defineConfig([{ + extends: compat.extends("plugin:compat/recommended"), + + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + }, + + ecmaVersion: 2018, + sourceType: "commonjs", + }, + + rules: { + curly: "error", + + quotes: ["error", "single", { + avoidEscape: true, + }], + + "no-unused-vars": ["error", { + args: "none", + }], + + "no-implicit-globals": "error", + "block-spacing": "error", + "func-call-spacing": ["error", "never"], + "key-spacing": "error", + "no-tabs": "error", + "no-trailing-spaces": "error", + "no-whitespace-before-property": "error", + semi: ["error", "always"], + "space-before-blocks": "error", + "no-eval": "error", + "no-var": "error", + "no-debugger": "error", + "no-console": "error", + }, +}]); diff --git a/package.json b/package.json index 2188cf2e..a7938fe7 100644 --- a/package.json +++ b/package.json @@ -34,9 +34,12 @@ "package.json" ], "devDependencies": { - "eslint": "^8.36.0", - "eslint-plugin-compat": "^4.0.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "^9.24.0", + "eslint": "^9.24.0", + "eslint-plugin-compat": "^6.0.2", "glob": "^10.2.3", + "globals": "^16.0.0", "grunt": "^1.0.4", "grunt-cli": "^1.3.2", "grunt-contrib-compress": "^2.0.0", diff --git a/spec/core/EnvSpec.js b/spec/core/EnvSpec.js index f9f74ef3..a3753f77 100644 --- a/spec/core/EnvSpec.js +++ b/spec/core/EnvSpec.js @@ -205,7 +205,6 @@ describe('Env', function() { it('throws an error when given arguments', function() { expect(function() { - // eslint-disable-next-line no-unused-vars env.describe('done method', function(done) {}); }).toThrowError('describe does not expect any arguments'); }); diff --git a/spec/core/QueueRunnerSpec.js b/spec/core/QueueRunnerSpec.js index 0e8b2690..847d5716 100644 --- a/spec/core/QueueRunnerSpec.js +++ b/spec/core/QueueRunnerSpec.js @@ -239,7 +239,6 @@ describe('QueueRunner', function() { it("sets a timeout if requested for asynchronous functions so they don't go on forever", function() { const timeout = 3, - // eslint-disable-next-line no-unused-vars beforeFn = { fn: function(done) {}, type: 'before', timeout: timeout }, queueableFn = { fn: jasmine.createSpy('fn'), type: 'queueable' }, onComplete = jasmine.createSpy('onComplete'), @@ -287,7 +286,6 @@ describe('QueueRunner', function() { }); it('by default does not set a timeout for asynchronous functions', function() { - // eslint-disable-next-line no-unused-vars const beforeFn = { fn: function(done) {} }, queueableFn = { fn: jasmine.createSpy('fn') }, onComplete = jasmine.createSpy('onComplete'), @@ -310,7 +308,6 @@ describe('QueueRunner', function() { it('clears the timeout when an async function throws an exception, to prevent additional exception reporting', function() { const queueableFn = { - // eslint-disable-next-line no-unused-vars fn: function(done) { throw new Error('error!'); } @@ -409,7 +406,6 @@ describe('QueueRunner', function() { it('continues running functions when an exception is thrown in async code without timing out', function() { const queueableFn = { - // eslint-disable-next-line no-unused-vars fn: function(done) { throwAsync(); }, @@ -461,7 +457,6 @@ describe('QueueRunner', function() { it('handles a global error event with a message but no error', function() { const queueableFn = { - // eslint-disable-next-line no-unused-vars fn: function(done) { const currentHandler = globalErrors.pushListener.calls.mostRecent() .args[0]; @@ -641,7 +636,6 @@ describe('QueueRunner', function() { it('issues an error if the function also takes a parameter', function() { const queueableFn = { - // eslint-disable-next-line no-unused-vars fn: function(done) { return new StubPromise(); } @@ -666,7 +660,6 @@ describe('QueueRunner', function() { }); it('issues a more specific error if the function is `async`', function() { - // eslint-disable-next-line no-unused-vars async function fn(done) {} const onException = jasmine.createSpy('onException'), queueRunner = new jasmineUnderTest.QueueRunner({ @@ -720,7 +713,6 @@ describe('QueueRunner', function() { it('continues running the functions even after an exception is thrown in an async spec', function() { const queueableFn = { - // eslint-disable-next-line no-unused-vars fn: function(done) { throw new Error('error'); } diff --git a/spec/core/SpySpec.js b/spec/core/SpySpec.js index 2390b4fc..323bd5ca 100644 --- a/spec/core/SpySpec.js +++ b/spec/core/SpySpec.js @@ -97,17 +97,11 @@ describe('Spies', function() { it('preserves arity of original function', function() { const functions = [ function nullary() {}, - // eslint-disable-next-line no-unused-vars function unary(arg) {}, - // eslint-disable-next-line no-unused-vars function binary(arg1, arg2) {}, - // eslint-disable-next-line no-unused-vars function ternary(arg1, arg2, arg3) {}, - // eslint-disable-next-line no-unused-vars function quaternary(arg1, arg2, arg3, arg4) {}, - // eslint-disable-next-line no-unused-vars function quinary(arg1, arg2, arg3, arg4, arg5) {}, - // eslint-disable-next-line no-unused-vars function senary(arg1, arg2, arg3, arg4, arg5, arg6) {} ]; diff --git a/spec/core/integration/EnvSpec.js b/spec/core/integration/EnvSpec.js index e50647e5..f5d2940f 100644 --- a/spec/core/integration/EnvSpec.js +++ b/spec/core/integration/EnvSpec.js @@ -1071,7 +1071,6 @@ describe('Env integration', function() { env.describe('my suite', function() { env.it('my spec', function() {}); - // eslint-disable-next-line no-unused-vars env.afterAll(function(afterAllDone) { throw error; }); @@ -1569,7 +1568,6 @@ describe('Env integration', function() { env.addReporter(reporter); jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = 8414; - // eslint-disable-next-line no-unused-vars env.it("async spec that doesn't call done", function(underTestCallback) { env.expect(true).toBeTruthy(); jasmine.clock().tick(8416); @@ -1642,13 +1640,13 @@ describe('Env integration', function() { realSetTimeout(function() { try { jasmine.clock().tick(10); + // eslint-disable-next-line no-unused-vars } catch (e) { // don't worry if the clock is already uninstalled } }, 100); }); env.describe('beforeAll', function() { - // eslint-disable-next-line no-unused-vars env.beforeAll(function(innerDone) { realSetTimeout(function() { jasmine.clock().tick(5001); @@ -1664,7 +1662,6 @@ describe('Env integration', function() { }); env.describe('afterAll', function() { - // eslint-disable-next-line no-unused-vars env.afterAll(function(innerDone) { realSetTimeout(function() { jasmine.clock().tick(2001); @@ -1680,7 +1677,6 @@ describe('Env integration', function() { }); env.describe('beforeEach', function() { - // eslint-disable-next-line no-unused-vars env.beforeEach(function(innerDone) { realSetTimeout(function() { jasmine.clock().tick(1001); @@ -1696,7 +1692,6 @@ describe('Env integration', function() { }); env.describe('afterEach', function() { - // eslint-disable-next-line no-unused-vars env.afterEach(function(innerDone) { realSetTimeout(function() { jasmine.clock().tick(4001); @@ -1713,7 +1708,6 @@ describe('Env integration', function() { env.it( 'it times out', - // eslint-disable-next-line no-unused-vars function(innerDone) { realSetTimeout(function() { jasmine.clock().tick(6001); @@ -2699,7 +2693,6 @@ describe('Env integration', function() { env.addReporter(reporter); env.describe('async suite', function() { - // eslint-disable-next-line no-unused-vars env.afterAll(function(innerDone) { setTimeout(function() { throw new Error('suite'); @@ -2712,7 +2705,6 @@ describe('Env integration', function() { env.describe('suite', function() { env.it( 'async spec', - // eslint-disable-next-line no-unused-vars function(innerDone) { setTimeout(function() { throw new Error('spec'); @@ -4362,6 +4354,7 @@ describe('Env integration', function() { env.it('a spec', function() { try { env.throwUnless(1).toEqual(1); + // eslint-disable-next-line no-unused-vars } catch (e) { threw = true; } @@ -4375,6 +4368,7 @@ describe('Env integration', function() { env.it('a spec', function() { try { env.throwUnless(1).toEqual(2); + // eslint-disable-next-line no-unused-vars } catch (e) {} }); @@ -4418,6 +4412,7 @@ describe('Env integration', function() { env.it('a spec', async function() { try { await env.throwUnlessAsync(Promise.resolve()).toBeResolved(); + // eslint-disable-next-line no-unused-vars } catch (e) { threw = true; } @@ -4431,6 +4426,7 @@ describe('Env integration', function() { env.it('a spec', async function() { try { await env.throwUnlessAsync(Promise.resolve()).toBeRejected(); + // eslint-disable-next-line no-unused-vars } catch (e) {} }); diff --git a/spec/core/integration/SpecRunningSpec.js b/spec/core/integration/SpecRunningSpec.js index 32439a3a..a680949a 100644 --- a/spec/core/integration/SpecRunningSpec.js +++ b/spec/core/integration/SpecRunningSpec.js @@ -866,7 +866,6 @@ describe('spec running', function() { const actions = []; env.describe('Something', function() { - // eslint-disable-next-line no-unused-vars env.beforeEach(function(innerDone) { actions.push('beforeEach'); }, 1); diff --git a/spec/core/matchers/matchersUtilSpec.js b/spec/core/matchers/matchersUtilSpec.js index 798fbe94..27460933 100644 --- a/spec/core/matchers/matchersUtilSpec.js +++ b/spec/core/matchers/matchersUtilSpec.js @@ -830,9 +830,7 @@ describe('matchersUtil', function() { const matchersUtil = new jasmineUnderTest.MatchersUtil(); const a1 = new TypedArrayCtor(2); const a2 = new TypedArrayCtor(2); - // eslint-disable-next-line compat/compat a1[0] = a2[0] = BigInt(0); - // eslint-disable-next-line compat/compat a1[1] = a2[1] = BigInt(1); expect(matchersUtil.equals(a1, a2)).toBe(true); } @@ -843,7 +841,6 @@ describe('matchersUtil', function() { const matchersUtil = new jasmineUnderTest.MatchersUtil(); const a1 = new TypedArrayCtor(2); const a2 = new TypedArrayCtor(1); - // eslint-disable-next-line compat/compat a1[0] = a1[1] = a2[0] = BigInt(0); expect(matchersUtil.equals(a1, a2)).toBe(false); }); @@ -855,9 +852,7 @@ describe('matchersUtil', function() { const matchersUtil = new jasmineUnderTest.MatchersUtil(); const a1 = new TypedArrayCtor(2); const a2 = new TypedArrayCtor(2); - // eslint-disable-next-line compat/compat a1[0] = a1[1] = a2[0] = BigInt(0); - // eslint-disable-next-line compat/compat a2[1] = BigInt(1); expect(matchersUtil.equals(a1, a2)).toBe(false); } diff --git a/spec/core/matchers/toEqualSpec.js b/spec/core/matchers/toEqualSpec.js index 868bd2f5..55b5d9d9 100644 --- a/spec/core/matchers/toEqualSpec.js +++ b/spec/core/matchers/toEqualSpec.js @@ -1,4 +1,3 @@ -/* eslint-disable compat/compat */ describe('toEqual', function() { 'use strict'; diff --git a/spec/core/matchers/toHaveNoOtherSpyInteractionsSpec.js b/spec/core/matchers/toHaveNoOtherSpyInteractionsSpec.js index 8f41b34b..ddb669c4 100644 --- a/spec/core/matchers/toHaveNoOtherSpyInteractionsSpec.js +++ b/spec/core/matchers/toHaveNoOtherSpyInteractionsSpec.js @@ -85,7 +85,7 @@ describe('toHaveNoOtherSpyInteractions', function() { ); }); - it(`throws an error if a non-object is passed`, function() { + it('throws an error if a non-object is passed', function() { let matcher = jasmineUnderTest.matchers.toHaveNoOtherSpyInteractions(); expect(function() { diff --git a/spec/core/matchers/toHaveSpyInteractionsSpec.js b/spec/core/matchers/toHaveSpyInteractionsSpec.js index 3d0e577c..d5b71f83 100755 --- a/spec/core/matchers/toHaveSpyInteractionsSpec.js +++ b/spec/core/matchers/toHaveSpyInteractionsSpec.js @@ -70,7 +70,7 @@ describe('toHaveSpyInteractions', function() { ); }); - it(`throws an error if a non-object is passed`, function() { + it('throws an error if a non-object is passed', function() { let matcher = jasmineUnderTest.matchers.toHaveSpyInteractions(); expect(function() { diff --git a/spec/support/ci.js b/spec/support/ci.js index 6757446d..5a9ccb2e 100644 --- a/spec/support/ci.js +++ b/spec/support/ci.js @@ -8,6 +8,7 @@ config.clearReporters = true; config.jasmineCore = jasmineCore; jasmineBrowser.runSpecs(config).catch(function(error) { + // eslint-disable-next-line no-console console.error(error); process.exit(1); }); diff --git a/src/core/Deprecator.js b/src/core/Deprecator.js index 65fc6e38..59726da8 100644 --- a/src/core/Deprecator.js +++ b/src/core/Deprecator.js @@ -36,6 +36,7 @@ getJasmineRequireObj().Deprecator = function(j$) { Deprecator.prototype.log_ = function(runnable, deprecation, options) { if (j$.isError_(deprecation)) { + // eslint-disable-next-line no-console console.error(deprecation); return; } @@ -58,6 +59,7 @@ getJasmineRequireObj().Deprecator = function(j$) { context += '\n' + verboseNote; } + // eslint-disable-next-line no-console console.error('DEPRECATION: ' + deprecation + context); }; diff --git a/src/core/Env.js b/src/core/Env.js index d546dc4e..a15a0a18 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -385,7 +385,9 @@ getJasmineRequireObj().Env = function(j$) { // If we get here, all results have been reported and there's nothing we // can do except log the result and hope the user sees it. + // eslint-disable-next-line no-console console.error('Jasmine received a result after the suite finished:'); + // eslint-disable-next-line no-console console.error(expectationResult); } diff --git a/src/core/PrettyPrinter.js b/src/core/PrettyPrinter.js index bc6b2224..9a098f21 100644 --- a/src/core/PrettyPrinter.js +++ b/src/core/PrettyPrinter.js @@ -58,6 +58,7 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) { ) { try { this.emitScalar(value.toString()); + // eslint-disable-next-line no-unused-vars } catch (e) { this.emitScalar('has-invalid-toString-method'); } @@ -304,6 +305,7 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) { value.toString !== Object.prototype.toString && value.toString() !== Object.prototype.toString.call(value) ); + // eslint-disable-next-line no-unused-vars } catch (e) { // The custom toString() threw. return true; diff --git a/src/core/QueueRunner.js b/src/core/QueueRunner.js index 034233e6..007c5e8f 100644 --- a/src/core/QueueRunner.js +++ b/src/core/QueueRunner.js @@ -22,6 +22,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { } function fallbackOnMultipleDone() { + // eslint-disable-next-line no-console console.error( new Error( "An asynchronous function called its 'done' " + @@ -135,6 +136,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { // Any error we catch here is probably due to a bug in Jasmine, // and it's not likely to end up anywhere useful if we let it // propagate. Log it so it can at least show up when debugging. + // eslint-disable-next-line no-console console.error(error); } } diff --git a/src/core/SpyRegistry.js b/src/core/SpyRegistry.js index ba129924..fece1b44 100644 --- a/src/core/SpyRegistry.js +++ b/src/core/SpyRegistry.js @@ -252,6 +252,7 @@ getJasmineRequireObj().SpyRegistry = function(j$) { let value; try { value = obj[prop]; + // eslint-disable-next-line no-unused-vars } catch (e) { return false; } diff --git a/src/core/matchers/toBeInstanceOf.js b/src/core/matchers/toBeInstanceOf.js index 5e0156ee..fba86e9c 100644 --- a/src/core/matchers/toBeInstanceOf.js +++ b/src/core/matchers/toBeInstanceOf.js @@ -31,6 +31,7 @@ getJasmineRequireObj().toBeInstanceOf = function(j$) { try { expectedMatcher = new j$.Any(expected); pass = expectedMatcher.asymmetricMatch(actual); + // eslint-disable-next-line no-unused-vars } catch (error) { throw new Error( usageError('Expected value is not a constructor function') diff --git a/src/html/HtmlReporter.js b/src/html/HtmlReporter.js index 43053fbd..63c5813e 100644 --- a/src/html/HtmlReporter.js +++ b/src/html/HtmlReporter.js @@ -122,8 +122,10 @@ jasmineRequire.HtmlReporter = function(j$) { if (noExpectations(result)) { const noSpecMsg = "Spec '" + result.fullName + "' has no expectations."; if (result.status === 'failed') { + // eslint-disable-next-line no-console console.error(noSpecMsg); } else { + // eslint-disable-next-line no-console console.warn(noSpecMsg); } }