diff --git a/.github/configurations/node_linters/eslint.config.mjs b/.github/configurations/node_linters/eslint.config.mjs index 0aef7c5..7e19af7 100644 --- a/.github/configurations/node_linters/eslint.config.mjs +++ b/.github/configurations/node_linters/eslint.config.mjs @@ -1,36 +1,92 @@ -/* -import js from '@eslint/js'; -import pluginJest from 'eslint-plugin-jest'; -import globals from 'globals'; -import { defineConfig, globalIgnores } from 'eslint/config'; -import nextVitals from 'eslint-config-next/core-web-vitals'; -*/ -// Need require relative to the cwd +// Need inport relative to the cwd import path from 'path'; import { createRequire } from 'module'; const requireFromCwd = createRequire(path.resolve(process.cwd(), 'package.json')); const { defineConfig, globalIgnores } = requireFromCwd('eslint/config'); +const { FlatCompat } = requireFromCwd('@eslint/eslintrc'); const js = requireFromCwd('@eslint/js'); +const jsdoc = requireFromCwd('eslint-plugin-jsdoc'); const pluginJest = requireFromCwd('eslint-plugin-jest'); +// const importPlugin = requireFromCwd('eslint-plugin-import'); const globals = requireFromCwd('globals'); const nextVitals = requireFromCwd('eslint-config-next/core-web-vitals'); +// eslint-plugin-import +const compat = new FlatCompat({ + baseDirectory: import.meta.dirname, + resolvePluginsRelativeTo: process.cwd() +}); +const eslintImport = [ + ...compat.config({ + extends: ['plugin:import/recommended'], + settings: { + 'import/resolver': { + next: true, + }, + }, + }), +]; + export default defineConfig([ - globalIgnores(['node_modules/**', '.next/**', 'out/**', 'build/**', 'next-env.d.ts', 'public/sw.js']), + globalIgnores([ + 'node_modules/**', + '.next/**', + 'out/**', + 'build/**', + 'next-env.d.ts', + 'public/sw.js', + '.vscode/**', + '.github/**', + ]), ...nextVitals.map((config) => ({ ...config, - files: ['app/**/*.{js,mjs,cjs,jsx}'], // Specific for next app - })), + files: ['{app,tests}/**/*.{js,mjs,cjs,jsx}'], // Specific for next app + })), + ...eslintImport, // BUG in flat config importPlugin.flatConfigs.recommended (https://github.com/import-js/eslint-plugin-import/issues/3212) { files: ['**/*.{js,mjs,cjs,jsx}'], // For all files - plugins: { js }, - extends: ['js/recommended'], - languageOptions: { globals: globals.node }, - }, { - files: ['**/*.spec.js', '**/*.test.js'], + plugins: { js, jsdoc }, + extends: ['js/recommended', 'jsdoc/flat/recommended'], + languageOptions: { globals: { ...globals.node, ...globals.browser } }, + rules: { + 'prefer-destructuring': [ + 'error', + { + object: true, + array: false, + }, + ], + 'no-console': [ + 'error', + { + allow: ['warn', 'error'], + }, + ], + 'no-unused-vars': [ + 'error', + { + varsIgnorePattern: '^_', + argsIgnorePattern: '^_', + args: 'after-used', + }, + ], + 'no-underscore-dangle': [ + 'error', + { + allowAfterThis: true, + }, + ], + 'jsdoc/require-jsdoc': 0, + 'jsdoc/reject-any-type': 0, + 'jsdoc/reject-function-type': 0, + }, + }, + { + files: ['tests/**/*.{js,mjs,cjs,jsx}', '**/*.spec.js', '**/*.test.js'], plugins: { jest: pluginJest }, + extends: ['jest/recommended'], languageOptions: { globals: pluginJest.environments.globals.globals, }, }, -]); \ No newline at end of file +]); diff --git a/.github/configurations/node_linters/packages-linters.txt b/.github/configurations/node_linters/packages-linters.txt index 35e14b4..9922e5b 100644 --- a/.github/configurations/node_linters/packages-linters.txt +++ b/.github/configurations/node_linters/packages-linters.txt @@ -3,5 +3,9 @@ eslint @eslint/js eslint-config-next eslint-plugin-jest +eslint-plugin-import +eslint-import-resolver-next +eslint-import-resolver-typescript +eslint-plugin-jsdoc stylelint stylelint-config-standard-scss \ No newline at end of file diff --git a/.github/test/node_test/package-lock.json b/.github/test/node_test/package-lock.json index ae7313b..8349c77 100644 --- a/.github/test/node_test/package-lock.json +++ b/.github/test/node_test/package-lock.json @@ -19,7 +19,11 @@ "@testing-library/react": "^16.3.2", "eslint": "^9.39.2", "eslint-config-next": "^16.1.6", + "eslint-import-resolver-next": "^0.6.0", + "eslint-import-resolver-typescript": "^4.4.4", + "eslint-plugin-import": "^2.32.0", "eslint-plugin-jest": "^29.12.2", + "eslint-plugin-jsdoc": "^62.5.4", "jest": "^30.2.0", "jest-environment-jsdom": "^30.2.0", "prettier": "^3.8.1", @@ -833,6 +837,33 @@ "tslib": "^2.4.0" } }, + "node_modules/@es-joy/jsdoccomment": { + "version": "0.84.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.84.0.tgz", + "integrity": "sha512-0xew1CxOam0gV5OMjh2KjFQZsKL2bByX1+q4j3E73MpYIdyUxcZb/xQct9ccUb+ve5KGUYbCUxyPnYB7RbuP+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.8", + "@typescript-eslint/types": "^8.54.0", + "comment-parser": "1.4.5", + "esquery": "^1.7.0", + "jsdoc-type-pratt-parser": "~7.1.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@es-joy/resolve.exports": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@es-joy/resolve.exports/-/resolve.exports-1.2.0.tgz", + "integrity": "sha512-Q9hjxWI5xBM+qW2enxfe8wDKdFWMfd0Z29k5ZJnuBqD/CasY5Zryj09aCA6owbGATWz+39p5uIdaHXpopOcG8g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", @@ -2313,6 +2344,19 @@ "dev": true, "license": "MIT" }, + "node_modules/@sindresorhus/base62": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/base62/-/base62-1.0.0.tgz", + "integrity": "sha512-TeheYy0ILzBEI/CO55CP6zJCSdSWeRtGnHy8U8dWSUH4I68iqTsy7HkMktR4xakThc9jotkPQUXT4ITdbV7cHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@sindresorhus/merge-streams": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", @@ -3219,6 +3263,16 @@ "node": ">= 8" } }, + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -3934,6 +3988,16 @@ "dev": true, "license": "MIT" }, + "node_modules/comment-parser": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.5.tgz", + "integrity": "sha512-aRDkn3uyIlCFfk5NUA+VdwMmMsh8JGhc4hapfV4yxymHGQ3BVskMQfoXGpCo5IoBuQ9tS5iiVKhCpTcB4pW4qw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -4652,6 +4716,41 @@ } } }, + "node_modules/eslint-config-next/node_modules/eslint-import-resolver-typescript": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", + "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.4.0", + "get-tsconfig": "^4.10.0", + "is-bun-module": "^2.0.0", + "stable-hash": "^0.0.5", + "tinyglobby": "^0.2.13", + "unrs-resolver": "^1.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-resolver-typescript" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, "node_modules/eslint-config-next/node_modules/globals": { "version": "16.4.0", "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", @@ -4665,6 +4764,68 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint-import-context": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/eslint-import-context/-/eslint-import-context-0.1.9.tgz", + "integrity": "sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-tsconfig": "^4.10.1", + "stable-hash-x": "^0.2.0" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-context" + }, + "peerDependencies": { + "unrs-resolver": "^1.0.0" + }, + "peerDependenciesMeta": { + "unrs-resolver": { + "optional": true + } + } + }, + "node_modules/eslint-import-resolver-next": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-next/-/eslint-import-resolver-next-0.6.0.tgz", + "integrity": "sha512-W+40rkKo50tmOVvB59RkJHKoqWfBywvJe+c+8NZ7WhoCk68ol9JWmbXXv1i0Y9+74xWcMm2ECObx8tMfjnMtlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bun-module": "^2.0.0", + "js-yaml": "^4.1.0", + "stable-hash": "^0.0.5", + "tinyglobby": "^0.2.13", + "unrs-resolver": "^1.7.2" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/eslint-import-resolver-next/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/eslint-import-resolver-next/node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/eslint-import-resolver-node": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", @@ -4688,22 +4849,22 @@ } }, "node_modules/eslint-import-resolver-typescript": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", - "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.4.4.tgz", + "integrity": "sha512-1iM2zeBvrYmUNTj2vSC/90JTHDth+dfOfiNKkxApWRsTJYNrc8rOdxxIf5vazX+BiAXTeOT0UvWpGI/7qIWQOw==", "dev": true, "license": "ISC", "dependencies": { - "@nolyfill/is-core-module": "1.0.39", - "debug": "^4.4.0", - "get-tsconfig": "^4.10.0", + "debug": "^4.4.1", + "eslint-import-context": "^0.1.8", + "get-tsconfig": "^4.10.1", "is-bun-module": "^2.0.0", - "stable-hash": "^0.0.5", - "tinyglobby": "^0.2.13", - "unrs-resolver": "^1.6.2" + "stable-hash-x": "^0.2.0", + "tinyglobby": "^0.2.14", + "unrs-resolver": "^1.7.11" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^16.17.0 || >=18.6.0" }, "funding": { "url": "https://opencollective.com/eslint-import-resolver-typescript" @@ -4848,6 +5009,92 @@ } } }, + "node_modules/eslint-plugin-jsdoc": { + "version": "62.5.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-62.5.4.tgz", + "integrity": "sha512-U+Q5ppErmC17VFQl542eBIaXcuq975BzoIHBXyx7UQx/i4gyHXxPiBkonkuxWyFA98hGLALLUuD+NJcXqSGKxg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@es-joy/jsdoccomment": "~0.84.0", + "@es-joy/resolve.exports": "1.2.0", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.5", + "debug": "^4.4.3", + "escape-string-regexp": "^4.0.0", + "espree": "^11.1.0", + "esquery": "^1.7.0", + "html-entities": "^2.6.0", + "object-deep-merge": "^2.0.0", + "parse-imports-exports": "^0.2.4", + "semver": "^7.7.3", + "spdx-expression-parse": "^4.0.0", + "to-valid-identifier": "^1.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/eslint-visitor-keys": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.0.tgz", + "integrity": "sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/espree": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.1.0.tgz", + "integrity": "sha512-WFWYhO1fV4iYkqOOvq8FbqIhr2pYfoDY0kCotMkDeNtGpiGGkZ1iov2u8ydjtgM8yF8rzK7oaTbw2NAzbAbehw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/eslint-plugin-jsx-a11y": { "version": "6.10.2", "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", @@ -6002,6 +6249,23 @@ "node": ">=18" } }, + "node_modules/html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], + "license": "MIT" + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -7786,6 +8050,16 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-7.1.1.tgz", + "integrity": "sha512-/2uqY7x6bsrpi3i9LVU6J89352C0rpMk0as8trXxCtvd4kPk1ke/Eyif6wqfSLvoNJqcDG9Vk4UsXgygzCt2xA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/jsdom": { "version": "26.1.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", @@ -8356,6 +8630,13 @@ "node": ">=0.10.0" } }, + "node_modules/object-deep-merge": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/object-deep-merge/-/object-deep-merge-2.0.0.tgz", + "integrity": "sha512-3DC3UMpeffLTHiuXSy/UG4NOIYTLlY9u3V82+djSCLYClWobZiS4ivYzpIUWrRY/nfsJ8cWsKyG3QfyLePmhvg==", + "dev": true, + "license": "MIT" + }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", @@ -8606,6 +8887,16 @@ "node": ">=6" } }, + "node_modules/parse-imports-exports": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz", + "integrity": "sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-statements": "1.0.11" + } + }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -8625,6 +8916,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse-statements": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/parse-statements/-/parse-statements-1.0.11.tgz", + "integrity": "sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==", + "dev": true, + "license": "MIT" + }, "node_modules/parse5": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", @@ -9108,6 +9406,19 @@ "node": ">=0.10.0" } }, + "node_modules/reserved-identifiers": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/reserved-identifiers/-/reserved-identifiers-1.2.0.tgz", + "integrity": "sha512-yE7KUfFvaBFzGPs5H3Ops1RevfUEsDc5Iz65rOwWg4lE8HJSYtle77uul3+573457oHvBKuHYDl/xqUkKpEEdw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/resolve": { "version": "1.22.11", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", @@ -9572,6 +9883,31 @@ "source-map": "^0.6.0" } }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.22", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", + "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", + "dev": true, + "license": "CC0-1.0" + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -9586,6 +9922,16 @@ "dev": true, "license": "MIT" }, + "node_modules/stable-hash-x": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/stable-hash-x/-/stable-hash-x-0.2.0.tgz", + "integrity": "sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", @@ -10630,6 +10976,23 @@ "node": ">=8.0" } }, + "node_modules/to-valid-identifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-valid-identifier/-/to-valid-identifier-1.0.0.tgz", + "integrity": "sha512-41wJyvKep3yT2tyPqX/4blcfybknGB4D+oETKLs7Q76UiPqRpUJK3hr1nxelyYO0PHKVzJwlu0aCeEAsGI6rpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/base62": "^1.0.0", + "reserved-identifiers": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/tough-cookie": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", diff --git a/.github/test/node_test/package.json b/.github/test/node_test/package.json index 8b362cb..717d706 100644 --- a/.github/test/node_test/package.json +++ b/.github/test/node_test/package.json @@ -31,7 +31,11 @@ "@testing-library/react": "^16.3.2", "eslint": "^9.39.2", "eslint-config-next": "^16.1.6", + "eslint-import-resolver-next": "^0.6.0", + "eslint-import-resolver-typescript": "^4.4.4", + "eslint-plugin-import": "^2.32.0", "eslint-plugin-jest": "^29.12.2", + "eslint-plugin-jsdoc": "^62.5.4", "jest": "^30.2.0", "jest-environment-jsdom": "^30.2.0", "prettier": "^3.8.1", diff --git a/configurations/node_linters/eslint.config.mjs b/configurations/node_linters/eslint.config.mjs index 0aef7c5..7e19af7 100644 --- a/configurations/node_linters/eslint.config.mjs +++ b/configurations/node_linters/eslint.config.mjs @@ -1,36 +1,92 @@ -/* -import js from '@eslint/js'; -import pluginJest from 'eslint-plugin-jest'; -import globals from 'globals'; -import { defineConfig, globalIgnores } from 'eslint/config'; -import nextVitals from 'eslint-config-next/core-web-vitals'; -*/ -// Need require relative to the cwd +// Need inport relative to the cwd import path from 'path'; import { createRequire } from 'module'; const requireFromCwd = createRequire(path.resolve(process.cwd(), 'package.json')); const { defineConfig, globalIgnores } = requireFromCwd('eslint/config'); +const { FlatCompat } = requireFromCwd('@eslint/eslintrc'); const js = requireFromCwd('@eslint/js'); +const jsdoc = requireFromCwd('eslint-plugin-jsdoc'); const pluginJest = requireFromCwd('eslint-plugin-jest'); +// const importPlugin = requireFromCwd('eslint-plugin-import'); const globals = requireFromCwd('globals'); const nextVitals = requireFromCwd('eslint-config-next/core-web-vitals'); +// eslint-plugin-import +const compat = new FlatCompat({ + baseDirectory: import.meta.dirname, + resolvePluginsRelativeTo: process.cwd() +}); +const eslintImport = [ + ...compat.config({ + extends: ['plugin:import/recommended'], + settings: { + 'import/resolver': { + next: true, + }, + }, + }), +]; + export default defineConfig([ - globalIgnores(['node_modules/**', '.next/**', 'out/**', 'build/**', 'next-env.d.ts', 'public/sw.js']), + globalIgnores([ + 'node_modules/**', + '.next/**', + 'out/**', + 'build/**', + 'next-env.d.ts', + 'public/sw.js', + '.vscode/**', + '.github/**', + ]), ...nextVitals.map((config) => ({ ...config, - files: ['app/**/*.{js,mjs,cjs,jsx}'], // Specific for next app - })), + files: ['{app,tests}/**/*.{js,mjs,cjs,jsx}'], // Specific for next app + })), + ...eslintImport, // BUG in flat config importPlugin.flatConfigs.recommended (https://github.com/import-js/eslint-plugin-import/issues/3212) { files: ['**/*.{js,mjs,cjs,jsx}'], // For all files - plugins: { js }, - extends: ['js/recommended'], - languageOptions: { globals: globals.node }, - }, { - files: ['**/*.spec.js', '**/*.test.js'], + plugins: { js, jsdoc }, + extends: ['js/recommended', 'jsdoc/flat/recommended'], + languageOptions: { globals: { ...globals.node, ...globals.browser } }, + rules: { + 'prefer-destructuring': [ + 'error', + { + object: true, + array: false, + }, + ], + 'no-console': [ + 'error', + { + allow: ['warn', 'error'], + }, + ], + 'no-unused-vars': [ + 'error', + { + varsIgnorePattern: '^_', + argsIgnorePattern: '^_', + args: 'after-used', + }, + ], + 'no-underscore-dangle': [ + 'error', + { + allowAfterThis: true, + }, + ], + 'jsdoc/require-jsdoc': 0, + 'jsdoc/reject-any-type': 0, + 'jsdoc/reject-function-type': 0, + }, + }, + { + files: ['tests/**/*.{js,mjs,cjs,jsx}', '**/*.spec.js', '**/*.test.js'], plugins: { jest: pluginJest }, + extends: ['jest/recommended'], languageOptions: { globals: pluginJest.environments.globals.globals, }, }, -]); \ No newline at end of file +]); diff --git a/configurations/node_linters/packages-linters.txt b/configurations/node_linters/packages-linters.txt index 35e14b4..9922e5b 100644 --- a/configurations/node_linters/packages-linters.txt +++ b/configurations/node_linters/packages-linters.txt @@ -3,5 +3,9 @@ eslint @eslint/js eslint-config-next eslint-plugin-jest +eslint-plugin-import +eslint-import-resolver-next +eslint-import-resolver-typescript +eslint-plugin-jsdoc stylelint stylelint-config-standard-scss \ No newline at end of file