From 7c2a18dd30d909432167bf760e8311bd7e3af160 Mon Sep 17 00:00:00 2001 From: Frazer Smith Date: Mon, 7 Jul 2025 12:11:26 +0100 Subject: [PATCH] build(deps-dev): migrate to eslint flat config (#654) * build(deps-dev): migrate to eslint flat config * build(deps-dev): remove jest globals * build(deps-dev): group eslint config * build(deps-dev): sort group --- .eslintrc.js | 72 ------------------------------------------ .github/dependabot.yml | 3 +- .vscode/settings.json | 1 + eslint.config.mjs | 43 +++++++++++++++++++++++++ package.json | 43 +++++++++++-------------- src/index.js | 3 +- src/index.test.js | 23 ++++++++++---- 7 files changed, 82 insertions(+), 106 deletions(-) delete mode 100644 .eslintrc.js create mode 100644 eslint.config.mjs diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 24a367c..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,72 +0,0 @@ -"use strict"; - -module.exports = { - env: { - es2023: true, - node: true, - }, - extends: [ - "airbnb-base", - "plugin:@eslint-community/eslint-comments/recommended", - "plugin:jsdoc/recommended", - "plugin:promise/recommended", - "plugin:regexp/recommended", - "plugin:security/recommended-legacy", - "prettier", - ], - overrides: [ - { - extends: ["plugin:jest/recommended", "plugin:jest/style"], - files: ["src/**/*.test.js"], - plugins: ["jest"], - rules: { - "jest/no-duplicate-hooks": "error", - "jest/no-test-return-statement": "error", - "jest/prefer-comparison-matcher": "error", - "jest/prefer-each": "warn", - "jest/prefer-equality-matcher": "error", - "jest/prefer-expect-resolves": "error", - "jest/prefer-hooks-in-order": "error", - "jest/prefer-hooks-on-top": "error", - "jest/prefer-mock-promise-shorthand": "error", - "jest/prefer-spy-on": "error", - "jest/require-top-level-describe": "error", - }, - }, - ], - parserOptions: { - ecmaVersion: 2023, - // Explicitly tell ESLint to parse JavaScript as CommonJS, as airbnb-base sets this to "modules" for ECMAScript - sourceType: "script", - }, - plugins: ["import", "jsdoc", "promise", "regexp", "security"], - root: true, - rules: { - "@eslint-community/eslint-comments/disable-enable-pair": "off", - "@eslint-community/eslint-comments/no-unused-disable": "error", - "@eslint-community/eslint-comments/require-description": "error", - "import/no-extraneous-dependencies": "error", - "jsdoc/check-syntax": "error", - "jsdoc/require-description-complete-sentence": "error", - "jsdoc/require-hyphen-before-param-description": "error", - "no-multiple-empty-lines": ["error", { max: 1 }], - "no-restricted-syntax": [ - "error", - { - selector: "LabeledStatement", - message: - "Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand.", - }, - { - selector: "WithStatement", - message: - "`with` is disallowed in strict mode because it makes code impossible to predict and optimize.", - }, - ], - "prefer-destructuring": ["error", { object: true, array: false }], - "promise/prefer-await-to-callbacks": "warn", - "promise/prefer-await-to-then": "warn", - "security/detect-object-injection": "off", - strict: ["error", "global"], - }, -}; diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 03f2b74..a9c6212 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -20,7 +20,8 @@ updates: - "@commitlint*" eslint: patterns: - - "@eslint-community*" + - "@eslint*" + - "*eslint-config*" - "eslint*" ignore: # Below are dependencies that have migrated to ESM diff --git a/.vscode/settings.json b/.vscode/settings.json index 6c87966..604a67a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,7 @@ { "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true, + "eslint.useFlatConfig": true, "files.eol": "\n", "gitlens.telemetry.enabled": false, "[javascript]": { diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..75d6971 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,43 @@ +import { fileURLToPath, URL } from "node:url"; +import { includeIgnoreFile } from "@eslint/compat"; +import { defineConfig } from "eslint/config"; + +// Configs +import fdawgs from "@fdawgs/eslint-config"; + +// Plugins +import jest from "eslint-plugin-jest"; + +const gitignorePath = fileURLToPath(new URL(".gitignore", import.meta.url)); + +const config = defineConfig([ + // Include ignore file to prevent linting of files in .gitignore + includeIgnoreFile(gitignorePath), + { + files: ["**/*.js", "**/*.jsx"], + extends: [fdawgs], + }, + { + files: ["**/*.test.js"], + ...jest.configs["flat/recommended"], + ...jest.configs["flat/style"], + rules: { + ...jest.configs["flat/recommended"].rules, + ...jest.configs["flat/style"].rules, + "jest/no-duplicate-hooks": "error", + "jest/no-test-return-statement": "error", + "jest/prefer-comparison-matcher": "error", + "jest/prefer-each": "warn", + "jest/prefer-equality-matcher": "error", + "jest/prefer-expect-resolves": "error", + "jest/prefer-hooks-in-order": "error", + "jest/prefer-hooks-on-top": "error", + "jest/prefer-importing-jest-globals": "error", + "jest/prefer-mock-promise-shorthand": "error", + "jest/prefer-spy-on": "error", + "jest/require-top-level-describe": "error", + }, + }, +]); + +export default config; diff --git a/package.json b/package.json index d7ef53e..cb0b66a 100644 --- a/package.json +++ b/package.json @@ -50,17 +50,17 @@ "node": ">=20" }, "scripts": { - "build": "tsc", "build:docs": "jsdoc2md src/index.js > API.md --EOL posix", - "lint": "eslint . --cache --ext js,jsx --ignore-path .gitignore", + "build": "tsc", "lint:fix": "npm run lint -- --fix", "lint:licenses": "licensee --errors-only --production", - "lint:prettier": "prettier . -c -u", "lint:prettier:fix": "prettier . -w -u", + "lint:prettier": "prettier . -c -u", + "lint": "eslint . --cache", "prepare": "husky", - "test": "npm run lint && npm run lint:prettier && npm run test:unit", + "test:unit:coverage": "jest --coverage", "test:unit": "jest", - "test:unit:coverage": "jest --coverage" + "test": "npm run lint && npm run lint:prettier && npm run test:unit" }, "commitlint": { "extends": [ @@ -83,34 +83,29 @@ "statements": 90 } }, + "injectGlobals": false, "testEnvironment": "node", "testTimeout": 60000 }, "devDependencies": { - "@commitlint/cli": "^19.6.1", - "@commitlint/config-conventional": "^19.6.0", - "@eslint-community/eslint-plugin-eslint-comments": "^4.4.1", - "@types/jest": "^30.0.0", - "@types/semver": "^7.5.8", - "eslint": "^8.57.1", - "eslint-config-airbnb-base": "^15.0.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-import": "^2.31.0", - "eslint-plugin-jest": "^28.10.0", - "eslint-plugin-jsdoc": "^50.6.1", - "eslint-plugin-promise": "^7.2.1", - "eslint-plugin-regexp": "^2.7.0", - "eslint-plugin-security": "^3.0.1", - "glob": "^11.0.2", + "@commitlint/cli": "^19.8.1", + "@commitlint/config-conventional": "^19.8.1", + "@eslint/compat": "^1.3.0", + "@fdawgs/eslint-config": "^1.0.3", + "@jest/globals": "^30.0.4", + "@types/semver": "^7.7.0", + "eslint": "^9.30.1", + "eslint-plugin-jest": "^29.0.1", + "glob": "^11.0.3", "husky": "^9.1.7", - "jest": "^30.0.3", + "jest": "^30.0.4", "jsdoc-to-markdown": "^9.1.1", "licensee": "^11.1.1", - "prettier": "^3.4.2", - "typescript": "~5.8.2" + "prettier": "^3.6.2", + "typescript": "~5.8.3" }, "dependencies": { "camelcase": "^6.3.0", - "semver": "^7.6.3" + "semver": "^7.7.2" } } diff --git a/src/index.js b/src/index.js index fd6f5f7..703f060 100644 --- a/src/index.js +++ b/src/index.js @@ -1,10 +1,10 @@ "use strict"; const { execFile, spawn, spawnSync } = require("node:child_process"); +const { normalize, resolve: pathResolve } = require("node:path"); const { promisify } = require("node:util"); const camelCase = require("camelcase"); const { lt } = require("semver"); -const { normalize, resolve: pathResolve } = require("node:path"); const execFileAsync = promisify(execFile); @@ -61,7 +61,6 @@ function parseOptions(acceptedOptions, options, version) { const option = entries[i][1]; const acceptedOption = acceptedOptions[key]; - // eslint-disable-next-line valid-typeof -- `type` is a string if (acceptedOption.type === typeof option) { // Skip boolean options if false if (acceptedOption.type !== "boolean" || option) { diff --git a/src/index.test.js b/src/index.test.js index fa559e2..305c3fd 100644 --- a/src/index.test.js +++ b/src/index.test.js @@ -1,4 +1,4 @@ -/* eslint-disable global-require, security/detect-child-process -- Mocking child_process */ +/* eslint-disable n/global-require, security/detect-child-process -- Mocking child_process */ /* eslint-disable jest/no-conditional-expect -- Depends on the version of the binary */ /* eslint-disable security/detect-non-literal-fs-filename -- Test files are not user-provided */ @@ -6,15 +6,24 @@ const { execFile, spawnSync } = require("node:child_process"); const { access, readFile, unlink } = require("node:fs/promises"); +const { join, normalize, posix } = require("node:path"); const { promisify } = require("node:util"); +const { + afterEach, + beforeAll, + beforeEach, + describe, + expect, + it, + jest, +} = require("@jest/globals"); const { glob } = require("glob"); const { lt } = require("semver"); -const { join, normalize } = require("node:path"); const execFileAsync = promisify(execFile); const { Poppler } = require("./index"); -const testDirectory = `${__dirname}/../test_resources/test_files/`; +const testDirectory = posix.join(__dirname, "../test_resources/test_files/"); const file = `${testDirectory}pdf_1.3_NHS_Constitution.pdf`; const whitespaceFile = `${testDirectory}pdf_1.7_whitespace_example.pdf`; @@ -50,10 +59,10 @@ describe("Node-Poppler module", () => { // Remove leftover test files const files = await glob(`${testDirectory}**/*`, { ignore: [ - `${testDirectory}/pdf_1.3_NHS_Constitution_attached_detach.pdf`, - `${testDirectory}/pdf_1.3_NHS_Constitution.pdf`, - `${testDirectory}/pdf_1.7_NHS_Constitution_Handbook.pdf`, - `${testDirectory}/test.txt`, + `${testDirectory}pdf_1.3_NHS_Constitution_attached_detach.pdf`, + `${testDirectory}pdf_1.3_NHS_Constitution.pdf`, + `${testDirectory}pdf_1.7_NHS_Constitution_Handbook.pdf`, + `${testDirectory}test.txt`, whitespaceFile, ], });