Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ jobs:
strategy:
matrix:
os: [ ubuntu, windows ]
node-version: [16.x, 18.x, 20.x]
# TODO: We still support Node 16 but can't run ESLint v9 tests with it anymore.
node-version: [18.x, 20.x]

steps:
- uses: actions/checkout@v4
Expand Down
25 changes: 3 additions & 22 deletions eslint-remote-tester.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"use strict";

const fs = require("node:fs");
const { basename, extname } = require("node:path");
const eslintPluginQunitRecommended = require("./lib/configs/recommended");

/** @type {import('eslint-remote-tester').Config} */
module.exports = {
Expand Down Expand Up @@ -33,25 +32,7 @@ module.exports = {
cache: false,

/** ESLint configuration */
eslintrc: {
plugins: ["qunit"],

// Enable all of our rules.
rules: Object.fromEntries(
fs
.readdirSync(`${__dirname}/lib/rules`)
.map(
(filename) =>
`qunit/${basename(filename, extname(filename))}`,
)
.map((ruleName) => [ruleName, "error"]),
),

overrides: [
{
files: ["*.ts", "*.mts", "*.cts"],
parser: "@typescript-eslint/parser",
},
],
eslintConfig: {
...eslintPluginQunitRecommended,
},
};
47 changes: 16 additions & 31 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,28 @@
"use strict";

const js = require("@eslint/js");
const { FlatCompat } = require("@eslint/eslintrc");
const eslintPluginEslintComments = require("@eslint-community/eslint-plugin-eslint-comments/configs");
const eslintPluginEslintPluginAll = require("eslint-plugin-eslint-plugin/configs/all");
const eslintPluginMarkdown = require("eslint-plugin-markdown");
const eslintPluginMocha = require("eslint-plugin-mocha");
const eslintPluginN = require("eslint-plugin-n");
const eslintPluginPrettierRecommended = require("eslint-plugin-prettier/recommended");
const eslintPluginUnicorn = require("eslint-plugin-unicorn");
const globals = require("globals");

const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
});

module.exports = [
...compat.extends(
"plugin:eslint-comments/recommended",
"plugin:node/recommended",
"plugin:prettier/recommended",
"plugin:unicorn/recommended",
),
js.configs.recommended,

eslintPluginEslintComments.recommended,
eslintPluginEslintPluginAll,
eslintPluginN.configs["flat/recommended"],
eslintPluginPrettierRecommended,
eslintPluginUnicorn.configs["flat/recommended"],

// Apply mocha config only to tests.
...compat
.extends("plugin:mocha/recommended")
.map((config) => ({ ...config, files: ["tests/**/*.js"] })),
{
...eslintPluginMocha.configs.flat.recommended,
files: ["tests/**/*.js"],
},

{
languageOptions: {
Expand Down Expand Up @@ -136,14 +134,6 @@ module.exports = [
"spaced-comment": ["error", "always", { exceptions: ["-"] }],
strict: ["error", "global"],
"use-isnan": "error",
"valid-jsdoc": [
"error",
{
prefer: {
return: "returns",
},
},
],
"valid-typeof": "error",
yoda: ["error", "never"],

Expand Down Expand Up @@ -172,8 +162,8 @@ module.exports = [
],
"eslint-plugin/require-meta-schema-description": "off", // TODO: enable this.

// eslint-plugin-node
"node/no-missing-require": [
// eslint-plugin-n
"n/no-missing-require": [
"error",
{
allowModules: ["@typescript-eslint/parser"],
Expand Down Expand Up @@ -207,11 +197,6 @@ module.exports = [
{
// Markdown code samples.
files: ["**/*.md/*.js", "**/*.md/*.javascript"],
languageOptions: {
parserOptions: {
sourceType: "module",
},
},
rules: {
eqeqeq: "off",
"guard-for-in": "off",
Expand Down
18 changes: 18 additions & 0 deletions lib/rules/no-compare-relation-boolean.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,24 @@ module.exports = {
messageId: "redundantComparison",
fix(fixer) {
const sourceCode = context.getSourceCode();
/* istanbul ignore next */
if (callExprNode.type !== "CallExpression") {
return null;
}
/* istanbul ignore next */
if (callExprNode.callee.type !== "MemberExpression") {
return null;
}
/* istanbul ignore next */
if (callExprNode.callee.object.type !== "Identifier") {
return null;
}
/* istanbul ignore next */
if (
callExprNode.callee.property.type !== "Identifier"
) {
return null;
}
Comment on lines +85 to +102
Copy link
Member Author

@bmish bmish Jun 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixes an actual crash caught by eslint-remote-tester:

Repository: l10n-tw/canvas-lms
[143](https://github.com/qunitjs/eslint-plugin-qunit/actions/runs/15812921911/job/44566834381?pr=573#step:5:144)
Rule: qunit/no-compare-relation-boolean
[144](https://github.com/qunitjs/eslint-plugin-qunit/actions/runs/15812921911/job/44566834381?pr=573#step:5:145)
Message: Cannot read properties of undefined (reading 'name')
[145](https://github.com/qunitjs/eslint-plugin-qunit/actions/runs/15812921911/job/44566834381?pr=573#step:5:146)
Occurred while linting /home/runner/work/eslint-plugin-qunit/eslint-plugin-qunit/node_modules/eslint-remote-tester/.cache-eslint-remote-tester/l10n-tw/canvas-lms/spec/javascripts/jsx/shared/helpers/JQuerySelectorCacheSpec.js:38
[146](https://github.com/qunitjs/eslint-plugin-qunit/actions/runs/15812921911/job/44566834381?pr=573#step:5:147)
Rule: "qunit/no-compare-relation-boolean"
[147](https://github.com/qunitjs/eslint-plugin-qunit/actions/runs/15812921911/job/44566834381?pr=573#step:5:148)
Path: l10n-tw/canvas-lms/spec/javascripts/jsx/shared/helpers/JQuerySelectorCacheSpec.js
[148](https://github.com/qunitjs/eslint-plugin-qunit/actions/runs/15812921911/job/44566834381?pr=573#step:5:149)
Link: https://github.com/l10n-tw/canvas-lms/blob/HEAD/spec/javascripts/jsx/shared/helpers/JQuerySelectorCacheSpec.js#L38
[149](https://github.com/qunitjs/eslint-plugin-qunit/actions/runs/15812921911/job/44566834381?pr=573#step:5:150)

[150](https://github.com/qunitjs/eslint-plugin-qunit/actions/runs/15812921911/job/44566834381?pr=573#step:5:151)
  36 |     test('returns a jquery selector', () => {
[151](https://github.com/qunitjs/eslint-plugin-qunit/actions/runs/15812921911/job/44566834381?pr=573#step:5:152)
  37 |       const response = selectorCache.get('#foo')
[152](https://github.com/qunitjs/eslint-plugin-qunit/actions/runs/15812921911/job/44566834381?pr=573#step:5:153)
> 38 |       strictEqual(response instanceof $, true)
[153](https://github.com/qunitjs/eslint-plugin-qunit/actions/runs/15812921911/job/44566834381?pr=573#step:5:154)
  39 |     })
[154](https://github.com/qunitjs/eslint-plugin-qunit/actions/runs/15812921911/job/44566834381?pr=573#step:5:155)
  40 |
[155](https://github.com/qunitjs/eslint-plugin-qunit/actions/runs/15812921911/job/44566834381?pr=573#step:5:156)
  41 |     test('returns the selector for the given element', () => {

This fix is pulled from the TypeScript PR: #571

const assertionVariableName =
callExprNode.callee.object.name;

Expand Down
7 changes: 6 additions & 1 deletion lib/rules/no-setup-teardown.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,12 @@ module.exports = {
};

function checkModuleHook(propertyNode) {
if (replacements.hasOwnProperty(propertyNode.key.name)) {
if (
Object.prototype.hasOwnProperty.call(
replacements,
propertyNode.key.name,
)
) {
context.report({
node: propertyNode,
messageId: "noSetupTeardown",
Expand Down
Loading