diff --git a/.eslint-doc-generatorrc.js b/.eslint-doc-generatorrc.js new file mode 100644 index 0000000..d236862 --- /dev/null +++ b/.eslint-doc-generatorrc.js @@ -0,0 +1,10 @@ +/** @type {import('eslint-doc-generator').GenerateOptions} */ +const config = { + ignoreConfig: [ + 'all', + 'flat/all', + 'flat/recommended', + ], +}; + +module.exports = config; diff --git a/README.md b/README.md index dd77405..7abd300 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,17 @@ This library has a required `peerDependencies` listing for [`ESLint`](https://es ## Usage +> [!NOTE] +> +> `eslint.config.js` is supported, though most of the plugin documentation still +> currently uses `.eslintrc` syntax; compatible versions of configs are available +> prefixed with `flat/` and may be subject to small breaking changes while ESLint +> v9 is being finalized. +> +> Refer to the +> [ESLint documentation on the new configuration file format](https://eslint.org/docs/latest/use/configure/configuration-files-new) +> for more. + Add `jest-dom` to the plugins section of your `.eslintrc.js` configuration file. You can omit the `eslint-plugin-` prefix: @@ -78,8 +89,7 @@ This plugin exports a recommended configuration that enforces good `jest-dom` practices _(you can find more info about enabled rules in [Supported Rules section](#supported-rules))_. -To enable this configuration use the `extends` property in your `.eslintrc.js` -config file: +To enable this configuration with `.eslintrc`, use the `extends` property: ```javascript module.exports = { @@ -90,6 +100,20 @@ module.exports = { }; ``` +To enable this configuration with `eslint.config.js`, use +`jestDom.configs['flat/recommended']`: + +```javascript +module.exports = [ + { + files: [ + /* glob matching your test files */ + ], + ...require("eslint-plugin-jest-dom").configs["flat/recommended"], + }, +]; +``` + ## Supported Rules diff --git a/package.json b/package.json index 1a1cb46..4e81bf8 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "scripts": { "build": "kcd-scripts build", "pregenerate-readme-table": "npm run build", - "generate-readme-table": "eslint-doc-generator --ignore-config all", + "generate-readme-table": "eslint-doc-generator", "lint": "kcd-scripts lint", "lint:generate-readme-table": "npm run generate-readme-table -- --check", "setup": "npm install && npm run validate -s", diff --git a/src/__tests__/index.test.js b/src/__tests__/index.test.js index ef29c50..af8e8d9 100644 --- a/src/__tests__/index.test.js +++ b/src/__tests__/index.test.js @@ -1,22 +1,81 @@ -import { generateRecommendedConfig, rules } from "../"; +import plugin, { configs, rules } from "../"; + +it("includes the configs and rules on the plugin", () => { + expect(plugin).toHaveProperty("configs", configs); + expect(plugin).toHaveProperty("rules", rules); +}); it("should have all the rules", () => { - expect(Object.keys(rules).length).toBeGreaterThan(0); + expect(Object.keys(rules)).toHaveLength(11); }); -it.each(Object.keys(rules))("%s should export required fields", (ruleName) => { - const rule = rules[ruleName]; - expect(rule).toHaveProperty("create", expect.any(Function)); - expect(rule.meta.docs.url).not.toBe(""); - expect(rule.meta.docs.category).toBe("Best Practices"); - expect(rule.meta.docs.description).not.toBe(""); +it.each(Object.entries(rules))( + "%s should export required fields", + (name, rule) => { + expect(rule).toHaveProperty("create", expect.any(Function)); + expect(rule.meta.docs.url).not.toBe(""); + expect(rule.meta.docs.category).toBe("Best Practices"); + expect(rule.meta.docs.description).not.toBe(""); + } +); + +it("has the expected recommended config", () => { + expect(configs.recommended).toMatchInlineSnapshot(` + Object { + plugins: Array [ + jest-dom, + ], + rules: Object { + jest-dom/prefer-checked: error, + jest-dom/prefer-empty: error, + jest-dom/prefer-enabled-disabled: error, + jest-dom/prefer-focus: error, + jest-dom/prefer-in-document: error, + jest-dom/prefer-required: error, + jest-dom/prefer-to-have-attribute: error, + jest-dom/prefer-to-have-class: error, + jest-dom/prefer-to-have-style: error, + jest-dom/prefer-to-have-text-content: error, + jest-dom/prefer-to-have-value: error, + }, + } + `); }); -it("should have a recommended config with recommended rules", () => { - expect( - generateRecommendedConfig({ - good: { meta: { docs: { recommended: true } } }, - bad: { meta: { docs: { recommended: false } } }, - }) - ).toEqual({ "jest-dom/good": "error" }); +it("has the expected recommended flat config", () => { + const expectJestDomPlugin = expect.objectContaining({ + meta: { + name: "eslint-plugin-jest-dom", + version: expect.any(String), + }, + }); + + expect(configs["flat/recommended"]).toMatchInlineSnapshot( + { plugins: { "jest-dom": expectJestDomPlugin } }, + ` + Object { + plugins: Object { + jest-dom: ObjectContaining { + meta: Object { + name: eslint-plugin-jest-dom, + version: Any, + }, + }, + }, + rules: Object { + jest-dom/prefer-checked: error, + jest-dom/prefer-empty: error, + jest-dom/prefer-enabled-disabled: error, + jest-dom/prefer-focus: error, + jest-dom/prefer-in-document: error, + jest-dom/prefer-required: error, + jest-dom/prefer-to-have-attribute: error, + jest-dom/prefer-to-have-class: error, + jest-dom/prefer-to-have-style: error, + jest-dom/prefer-to-have-text-content: error, + jest-dom/prefer-to-have-value: error, + }, + } + ` + ); }); diff --git a/src/index.js b/src/index.js index cbde69b..0741088 100644 --- a/src/index.js +++ b/src/index.js @@ -8,39 +8,58 @@ //------------------------------------------------------------------------------ import requireIndex from "requireindex"; +import { + name as packageName, + version as packageVersion, +} from "../package.json"; //------------------------------------------------------------------------------ // Plugin Definition //------------------------------------------------------------------------------ -// import all rules in src/rules +// import all rules in src/rules and re-export them for .eslintrc configs export const rules = requireIndex(`${__dirname}/rules`); -export const generateRecommendedConfig = (allRules) => - Object.entries(allRules).reduce( - (memo, [name, rule]) => ({ - ...memo, - ...(rule.meta.docs.recommended ? { [`jest-dom/${name}`]: "error" } : {}), - }), - {} - ); - -export const generateAllRulesConfig = (allRules) => - Object.entries(allRules).reduce( - (memo, [name]) => ({ - ...memo, - ...{ [`jest-dom/${name}`]: "error" }, - }), - {} - ); - -export const configs = { - recommended: { - plugins: ["jest-dom"], - rules: generateRecommendedConfig(rules), +const allRules = Object.entries(rules).reduce( + (memo, [name]) => ({ + ...memo, + ...{ [`jest-dom/${name}`]: "error" }, + }), + {} +); + +const recommendedRules = allRules; + +const plugin = { + meta: { + name: packageName, + version: packageVersion, }, - all: { - plugins: ["jest-dom"], - rules: generateAllRulesConfig(rules), + configs: { + recommended: { + plugins: ["jest-dom"], + rules: recommendedRules, + }, + all: { + plugins: ["jest-dom"], + rules: allRules, + }, }, + rules, +}; + +plugin.configs["flat/recommended"] = { + plugins: { "jest-dom": plugin }, + rules: recommendedRules, }; +plugin.configs["flat/all"] = { + plugins: { "jest-dom": plugin }, + rules: allRules, +}; + +export default plugin; + +// explicitly export config to allow using this plugin in CJS-based +// eslint.config.js files without needing to deal with the .default +// and also retain backwards compatibility with `.eslintrc` configs +export const configs = plugin.configs;