|
2 | 2 | * @fileoverview An ESLint plugin for linting ESLint plugins |
3 | 3 | * @author Teddy Katz |
4 | 4 | */ |
| 5 | +import { createRequire } from 'node:module'; |
5 | 6 |
|
6 | | -// ------------------------------------------------------------------------------ |
7 | | -// Requirements |
8 | | -// ------------------------------------------------------------------------------ |
| 7 | +import type { ESLint, Linter, Rule } from 'eslint'; |
9 | 8 |
|
10 | | -import packageMetadata from '../package.json' with { type: 'json' }; |
11 | 9 | import consistentOutput from './rules/consistent-output.js'; |
12 | 10 | import fixerReturn from './rules/fixer-return.js'; |
13 | 11 | import metaPropertyOrdering from './rules/meta-property-ordering.js'; |
@@ -41,20 +39,56 @@ import requireMetaType from './rules/require-meta-type.js'; |
41 | 39 | import testCasePropertyOrdering from './rules/test-case-property-ordering.js'; |
42 | 40 | import testCaseShorthandStrings from './rules/test-case-shorthand-strings.js'; |
43 | 41 |
|
| 42 | +const require = createRequire(import.meta.url); |
| 43 | + |
| 44 | +const packageMetadata = require("../package.json") as { |
| 45 | + name: string; |
| 46 | + version: string; |
| 47 | +}; |
| 48 | + |
44 | 49 | const PLUGIN_NAME = packageMetadata.name.replace(/^eslint-plugin-/, ''); |
| 50 | +const CONFIG_NAMES = [ |
| 51 | + 'all', |
| 52 | + 'all-type-checked', |
| 53 | + 'recommended', |
| 54 | + 'rules', |
| 55 | + 'tests', |
| 56 | + 'rules-recommended', |
| 57 | + 'tests-recommended', |
| 58 | +] as const; |
| 59 | +type ConfigName = (typeof CONFIG_NAMES)[number]; |
45 | 60 |
|
46 | | -const configFilters = { |
47 | | - all: (rule) => !rule.meta.docs.requiresTypeChecking, |
| 61 | +const configFilters: Record<ConfigName, (rule: Rule.RuleModule) => boolean> = { |
| 62 | + all: (rule: Rule.RuleModule) => |
| 63 | + !( |
| 64 | + rule.meta?.docs && |
| 65 | + 'requiresTypeChecking' in rule.meta.docs && |
| 66 | + rule.meta.docs.requiresTypeChecking |
| 67 | + ), |
48 | 68 | 'all-type-checked': () => true, |
49 | | - recommended: (rule) => rule.meta.docs.recommended, |
50 | | - rules: (rule) => rule.meta.docs.category === 'Rules', |
51 | | - tests: (rule) => rule.meta.docs.category === 'Tests', |
52 | | - 'rules-recommended': (rule) => |
| 69 | + recommended: (rule: Rule.RuleModule) => !!rule.meta?.docs?.recommended, |
| 70 | + rules: (rule: Rule.RuleModule) => rule.meta?.docs?.category === 'Rules', |
| 71 | + tests: (rule: Rule.RuleModule) => rule.meta?.docs?.category === 'Tests', |
| 72 | + 'rules-recommended': (rule: Rule.RuleModule) => |
53 | 73 | configFilters.recommended(rule) && configFilters.rules(rule), |
54 | | - 'tests-recommended': (rule) => |
| 74 | + 'tests-recommended': (rule: Rule.RuleModule) => |
55 | 75 | configFilters.recommended(rule) && configFilters.tests(rule), |
56 | 76 | }; |
57 | 77 |
|
| 78 | +const createConfig = (configName: ConfigName): Linter.Config => ({ |
| 79 | + name: `${PLUGIN_NAME}/${configName}`, |
| 80 | + plugins: { |
| 81 | + get [PLUGIN_NAME](): ESLint.Plugin { |
| 82 | + return plugin; |
| 83 | + }, |
| 84 | + }, |
| 85 | + rules: Object.fromEntries( |
| 86 | + (Object.keys(allRules) as (keyof typeof allRules)[]) |
| 87 | + .filter((ruleName) => configFilters[configName](allRules[ruleName])) |
| 88 | + .map((ruleName) => [`${PLUGIN_NAME}/${ruleName}`, 'error']), |
| 89 | + ), |
| 90 | +}); |
| 91 | + |
58 | 92 | // ------------------------------------------------------------------------------ |
59 | 93 | // Plugin Definition |
60 | 94 | // ------------------------------------------------------------------------------ |
@@ -93,34 +127,23 @@ const allRules = { |
93 | 127 | 'require-meta-type': requireMetaType, |
94 | 128 | 'test-case-property-ordering': testCasePropertyOrdering, |
95 | 129 | 'test-case-shorthand-strings': testCaseShorthandStrings, |
96 | | -}; |
| 130 | +} satisfies Record<string, Rule.RuleModule>; |
97 | 131 |
|
98 | | -/** @type {import("eslint").ESLint.Plugin} */ |
99 | 132 | const plugin = { |
100 | 133 | meta: { |
101 | 134 | name: packageMetadata.name, |
102 | 135 | version: packageMetadata.version, |
103 | 136 | }, |
104 | 137 | rules: allRules, |
105 | | - configs: {}, // assigned later |
106 | | -}; |
107 | | - |
108 | | -// configs |
109 | | -Object.assign( |
110 | | - plugin.configs, |
111 | | - Object.keys(configFilters).reduce((configs, configName) => { |
112 | | - return Object.assign(configs, { |
113 | | - [configName]: { |
114 | | - name: `${PLUGIN_NAME}/${configName}`, |
115 | | - plugins: { [PLUGIN_NAME]: plugin }, |
116 | | - rules: Object.fromEntries( |
117 | | - Object.keys(allRules) |
118 | | - .filter((ruleName) => configFilters[configName](allRules[ruleName])) |
119 | | - .map((ruleName) => [`${PLUGIN_NAME}/${ruleName}`, 'error']), |
120 | | - ), |
121 | | - }, |
122 | | - }); |
123 | | - }, {}), |
124 | | -); |
| 138 | + configs: { |
| 139 | + all: createConfig('all'), |
| 140 | + 'all-type-checked': createConfig('all-type-checked'), |
| 141 | + recommended: createConfig('recommended'), |
| 142 | + rules: createConfig('rules'), |
| 143 | + tests: createConfig('tests'), |
| 144 | + 'rules-recommended': createConfig('rules-recommended'), |
| 145 | + 'tests-recommended': createConfig('tests-recommended'), |
| 146 | + }, |
| 147 | +} satisfies ESLint.Plugin; |
125 | 148 |
|
126 | 149 | export default plugin; |
0 commit comments