Repository: JoshuaKGoldberg/eslint-plugin-package-json (ts)

Issue:
🚀 Feature: unify import of recommended config with other plugins
### Bug Report Checklist

- [x] I have tried restarting my IDE and the issue persists.
- [x] I have pulled the latest `main` branch of the repository.
- [x] I have [searched for related issues](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues?q=is%3Aissue) and found none that matched my issue.

### Overview

I would like to import your plugin and use its recommended config like in [other](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config) [ESLint](https://github.com/azat-io/eslint-plugin-perfectionist#flat-config-eslintconfigjs-1) [plugins](https://github.com/jsx-eslint/eslint-plugin-react#flat-configs):

```js
import packageJson from 'eslint-plugin-package-json';

export default [
  packageJson.configs.recommended,
];
```

But I get an error `Cannot read properties of undefined (reading 'recommended')`.

Was there any special reason to do things differently than [ESLint recommends](https://eslint.org/docs/latest/extend/plugin-migration-flat-config#migrating-configs-for-flat-config)?

### Additional Info

_No response_

Pull request description:
feat!: refactor plugin export to conform to latest conventions
## PR Checklist

-   [x] Addresses an existing open issue: fixes #752 
-   [x] That issue was marked as [`status: accepting prs`](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues?q=is%3Aopen+is%3Aissue+label%3A%22status%3A+accepting+prs%22)
-   [x] Steps in [CONTRIBUTING.md](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/blob/main/.github/CONTRIBUTING.md) were taken

## Overview

This change refactors the plugin's exports to conform to the latest standards recommended by the ESLint team.

The plugin is still the default export, but it now has configs attached to it as well, but the legacy rc-based config (now called `'legacy-recommended'`) and the `recommended` flat-config.

For users of the flat config, you'll need to make the following changes.

```diff
- import packageJson from "eslint-plugin-package-json/configs/recommended";
+ import packageJson from "eslint-plugin-package-json";

export default [
-   packageJson,
+   packageJson.configs.recommended,
];
```

For users of the legacy config, you'll need to make the following changes.

```diff
module.exports = {
  overrides: [
    {
-     extends: ["plugin:package-json/recommended"],
+     extends: ["plugin:package-json/legacy-recommended"],
      files: ["package.json"],
      parser: "jsonc-eslint-parser",
    },
  ],
};
```

BREAKING CHANGE

Closes #752 

Patch:
diff --git a/.eslint-doc-generatorrc.js b/.eslint-doc-generatorrc.js
new file mode 100644
index 0000000..cfe70d1
--- /dev/null
+++ b/.eslint-doc-generatorrc.js
@@ -0,0 +1,6 @@
+/** @type {import('eslint-doc-generator').GenerateOptions} */
+const config = {
+	ignoreConfig: ["legacy-recommended"],
+};
+
+module.exports = config;
diff --git a/.github/workflows/lint-eslint-docs.yml b/.github/workflows/lint-eslint-docs.yml
index e9c23e7..eddf79a 100644
--- a/.github/workflows/lint-eslint-docs.yml
+++ b/.github/workflows/lint-eslint-docs.yml
@@ -4,7 +4,6 @@ jobs:
     steps:
       - uses: actions/checkout@v4
       - uses: ./.github/actions/prepare
-      - run: npm run build
       - run: npm run lint:eslint-docs
 
 name: Lint ESLint Docs
diff --git a/README.md b/README.md
index 6a866d8..ec22e9d 100644
--- a/README.md
+++ b/README.md
@@ -34,25 +34,24 @@ This plugin's recommended configuration enables its rules on `**/package.json` f
 In your ESLint configuration file:
 
 ```ts
-import packageJson from "eslint-plugin-package-json/configs/recommended";
+import packageJson from "eslint-plugin-package-json";
 
 export default [
 	// your other ESLint configurations
-	packageJson,
+	packageJson.configs.recommended,
 ];
 ```
 
 If you want to override the recommended rules:
 
 ```ts
-import packageJson from "eslint-plugin-package-json/configs/recommended";
+import packageJson from "eslint-plugin-package-json";
 
 export default [
 	// your other ESLint configurations
+	packageJson.configs.recommended,
 	{
-		...packageJson,
 		rules: {
-			...packageJson.rules,
 			"package-json/valid-package-definition": "off",
 		},
 	},
@@ -75,10 +74,9 @@ Add an override to your ESLint configuration file that specifies `jsonc-eslint-p
 module.exports = {
 	overrides: [
 		{
-			extends: ["plugin:package-json/recommended"],
+			extends: ["plugin:package-json/legacy-recommended"],
 			files: ["package.json"],
 			parser: "jsonc-eslint-parser",
-			plugins: ["package-json"],
 		},
 	],
 };
@@ -91,10 +89,9 @@ See [ESLint's _Configure Rules_ guide](https://eslint.org/docs/latest/use/config
 module.exports = {
 	overrides: [
 		{
-			extends: ["plugin:package-json/recommended"],
+			extends: ["plugin:package-json/legacy-recommended"],
 			files: ["package.json"],
 			parser: "jsonc-eslint-parser",
-			plugins: ["package-json"],
 			rules: {
 				"package-json/valid-package-definition": "error",
 			},
diff --git a/cspell.json b/cspell.json
index ef2592a..22a4d37 100644
--- a/cspell.json
+++ b/cspell.json
@@ -4,6 +4,7 @@
 		".github",
 		"CHANGELOG.md",
 		"coverage",
+		"eslint.config.js",
 		"lib",
 		"node_modules",
 		"pnpm-lock.yaml"
diff --git a/eslint.config.js b/eslint.config.js
index 664a6ec..60e34d8 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -44,6 +44,7 @@ module.exports = tseslint.config(
 				projectService: {
 					allowDefaultProject: [
 						"*.config.*s",
+						".eslint-doc-generatorrc.js",
 						"bin/*.js",
 						"src/tests/*.js",
 					],
diff --git a/package.json b/package.json
index 2fe0a7f..66e7e86 100644
--- a/package.json
+++ b/package.json
@@ -21,14 +21,6 @@
 			},
 			"import": "./lib/index.mjs",
 			"require": "./lib/index.js"
-		},
-		"./configs/recommended": {
-			"types": {
-				"import": "./lib/configs/recommended.d.mts",
-				"require": "./lib/configs/recommended.d.ts"
-			},
-			"import": "./lib/configs/recommended.mjs",
-			"require": "./lib/configs/recommended.js"
 		}
 	},
 	"main": "./lib/index.js",
@@ -48,7 +40,7 @@
 		"should-semantic-release": "should-semantic-release --verbose",
 		"test": "vitest",
 		"tsc": "tsc",
-		"update:eslint-docs": "eslint-doc-generator --rule-doc-title-format name"
+		"update:eslint-docs": "pnpm build && eslint-doc-generator --rule-doc-title-format name"
 	},
 	"lint-staged": {
 		"*": "prettier --ignore-unknown --write"
@@ -78,7 +70,7 @@
 		"console-fail-test": "^0.5.0",
 		"cspell": "^8.3.2",
 		"eslint": "^9.18.0",
-		"eslint-doc-generator": "^2.0.2",
+		"eslint-doc-generator": "^2.1.2",
 		"eslint-plugin-eslint-plugin": "^6.4.0",
 		"eslint-plugin-jsdoc": "^50.6.1",
 		"eslint-plugin-jsonc": "^2.18.2",
@@ -107,7 +99,7 @@
 		"eslint": ">=8.0.0",
 		"jsonc-eslint-parser": "^2.0.0"
 	},
-	"packageManager": "pnpm@10.6.2",
+	"packageManager": "pnpm@10.6.3",
 	"engines": {
 		"node": ">=18"
 	},
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index fac08a2..964986a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -76,8 +76,8 @@ importers:
         specifier: ^9.18.0
         version: 9.22.0(jiti@2.4.2)
       eslint-doc-generator:
-        specifier: ^2.0.2
-        version: 2.1.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
+        specifier: ^2.1.2
+        version: 2.1.2(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
       eslint-plugin-eslint-plugin:
         specifier: ^6.4.0
         version: 6.4.0(eslint@9.22.0(jiti@2.4.2))
@@ -110,7 +110,7 @@ importers:
         version: 2.4.0
       knip:
         specifier: ^5.0.0
-        version: 5.45.0(@types/node@22.13.10)(typescript@5.8.2)
+        version: 5.46.0(@types/node@22.13.10)(typescript@5.8.2)
       lint-staged:
         specifier: ^15.3.0
         version: 15.5.0
@@ -1695,8 +1695,8 @@ packages:
     peerDependencies:
       eslint: '>=6.0.0'
 
-  eslint-doc-generator@2.1.0:
-    resolution: {integrity: sha512-DrHarT83g05wrTJghZ9MWRrbPAheWi1ZhBjtwc4cQzj1nFAZ2KTbOVopct2CQJw2vXe65vrj0gR8oMfckgQQMg==}
+  eslint-doc-generator@2.1.2:
+    resolution: {integrity: sha512-4CzDcFiVaNDxaUYF01bnebGkxKvowp6dyX/USED+4GbKCNTcoopbXZ0Jtb0m4/xYS2ImOajDmgb8HA3njgVMPg==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=22.0.0}
     hasBin: true
     peerDependencies:
@@ -2355,8 +2355,8 @@ packages:
   keyv@4.5.4:
     resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
 
-  knip@5.45.0:
-    resolution: {integrity: sha512-OUyO9FUEVCM6/j0gl+PP/LDeJEs4hIdE8n4vK4xrtjN1g3Qu4Ws1oexbWTCJ+8xt8Tgse4Yvhx96OqF/UVl3Ug==}
+  knip@5.46.0:
+    resolution: {integrity: sha512-WedHSK5xNBWYgm64Rt5B9b0CVXL2kRBcyCeet3NHgdv9en3QE4AWSDPEiX48NoPUBW3h//9S0VwLF5MG/MPi3g==}
     engines: {node: '>=18.18.0'}
     hasBin: true
     peerDependencies:
@@ -5099,7 +5099,7 @@ snapshots:
       eslint: 9.22.0(jiti@2.4.2)
       semver: 7.7.1
 
-  eslint-doc-generator@2.1.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2):
+  eslint-doc-generator@2.1.2(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2):
     dependencies:
       '@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
       ajv: 8.17.1
@@ -5799,7 +5799,7 @@ snapshots:
     dependencies:
       json-buffer: 3.0.1
 
-  knip@5.45.0(@types/node@22.13.10)(typescript@5.8.2):
+  knip@5.46.0(@types/node@22.13.10)(typescript@5.8.2):
     dependencies:
       '@nodelib/fs.walk': 3.0.1
       '@snyk/github-codeowners': 1.1.0
diff --git a/src/configs/recommended.ts b/src/configs/recommended.ts
deleted file mode 100644
index 81598e4..0000000
--- a/src/configs/recommended.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import * as parserJsonc from "jsonc-eslint-parser";
-
-import { plugin, recommendedRuleSettings } from "../plugin.js";
-
-const recommended = {
-	files: ["**/package.json"],
-	languageOptions: {
-		parser: parserJsonc,
-	},
-	name: "package-json/recommended",
-	plugins: {
-		get "package-json"() {
-			return plugin;
-		},
-	},
-	rules: recommendedRuleSettings,
-};
-
-export default recommended;
diff --git a/src/index.ts b/src/index.ts
index 0133423..7a61081 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,12 +1,6 @@
-import { plugin, recommendedRuleSettings } from "./plugin.js";
+import { plugin } from "./plugin.js";
 
 export const rules = plugin.rules;
-
-export const configs = {
-	recommended: {
-		plugins: ["package-json"],
-		rules: recommendedRuleSettings,
-	},
-};
+export const configs = plugin.configs;
 
 export default plugin;
diff --git a/src/plugin.ts b/src/plugin.ts
index 082027a..db84261 100644
--- a/src/plugin.ts
+++ b/src/plugin.ts
@@ -1,3 +1,4 @@
+import * as parserJsonc from "jsonc-eslint-parser";
 import { createRequire } from "node:module";
 
 import type { PackageJsonRuleModule } from "./createRule.js";
@@ -51,16 +52,35 @@ const rules: Record<string, PackageJsonRuleModule> = {
 	},
 };
 
+const recommendedRules = Object.fromEntries(
+	Object.entries(rules)
+		.filter(([, rule]) => rule.meta.docs?.recommended)
+		.map(([name]) => ["package-json/" + name, "error" as const]),
+);
+
 export const plugin = {
+	configs: {
+		"legacy-recommended": {
+			plugins: ["package-json"],
+			rules: recommendedRules,
+		},
+		recommended: {
+			files: ["**/package.json"],
+			languageOptions: {
+				parser: parserJsonc,
+			},
+			name: "package-json/recommended",
+			plugins: {
+				get "package-json"() {
+					return plugin;
+				},
+			},
+			rules: recommendedRules,
+		},
+	},
 	meta: {
 		name,
 		version,
 	},
 	rules,
 };
-
-export const recommendedRuleSettings = Object.fromEntries(
-	Object.entries(rules)
-		.filter(([, rule]) => rule.meta.docs?.recommended)
-		.map(([name]) => ["package-json/" + name, "error" as const]),
-);


Test patch:
diff --git a/src/configs/recommended.test.ts b/src/configs/recommended.test.ts
deleted file mode 100644
index fc3d8c9..0000000
--- a/src/configs/recommended.test.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { describe, expect, it } from "vitest";
-
-import { plugin } from "../plugin.js";
-import recommended from "./recommended.js";
-
-describe("recommended", () => {
-	it("includes the plugin", () => {
-		expect(recommended.plugins["package-json"]).toBe(plugin);
-	});
-});
diff --git a/src/tests/index.test.ts b/src/tests/index.test.ts
index 7afc148..2673162 100644
--- a/src/tests/index.test.ts
+++ b/src/tests/index.test.ts
@@ -3,18 +3,16 @@ import { readFile } from "node:fs/promises";
 import { resolve } from "node:path";
 import { describe, expect, it } from "vitest";
 
-import recommended from "../configs/recommended.js";
-
-const filename = new URL(import.meta.url).pathname;
+import plugin from "../index.js";
 
 describe("configs", () => {
 	it("configs should work properly", async () => {
 		const eslint = new ESLint({
-			baseConfig: recommended as Linter.Config,
+			baseConfig: plugin.configs.recommended as Linter.Config,
 			fix: true,
 		});
 		const code = await readFile(
-			resolve(filename, "../../../package.json"),
+			resolve(import.meta.filename, "../../../package.json"),
 			"utf8",
 		);
 		const result = await eslint.lintText(code, {