Skip to content

Commit e352a34

Browse files
committed
Merge branch 'main' into recommended-rules-v7
* main: feat: migrate package to TypeScript and publish types (eslint-community#534) build: convert eslint-remote-tester config to typescript (eslint-community#533) refactor: remove context compat functions (eslint-community#532) build: migrate eslint.config.js to typescript (eslint-community#531)
2 parents 0751183 + 95b859a commit e352a34

File tree

85 files changed

+2119
-1311
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+2119
-1311
lines changed

.github/workflows/main.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,13 @@ jobs:
4545
node-version: 'lts/*'
4646
- run: npm install
4747
- run: npm run test:remote
48+
49+
typecheck:
50+
runs-on: ubuntu-latest
51+
steps:
52+
- uses: actions/checkout@v4
53+
- uses: actions/setup-node@v4
54+
with:
55+
node-version: 'lts/*'
56+
- run: npm install
57+
- run: npm run typecheck

.github/workflows/release-please.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ jobs:
3838
if: ${{ steps.release.outputs.release_created }}
3939
- run: |
4040
npm install --force
41+
npm run build
4142
npm publish --provenance
4243
env:
4344
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

.gitignore

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
.idea
2-
coverage
1+
.idea/
2+
coverage/
33
.vscode
44
node_modules/
55
npm-debug.log
66
yarn.lock
77
.eslintcache
8+
dist/
89

910
# eslint-remote-tester
1011
eslint-remote-tester-results

eslint-remote-tester.config.mjs renamed to eslint-remote-tester.config.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
import eslintPlugin from 'eslint-plugin-eslint-plugin';
21
import tsparser from '@typescript-eslint/parser';
2+
import type { Config } from 'eslint-remote-tester';
3+
4+
// @ts-expect-error - eslint-plugin is not typed yet
5+
import eslintPlugin from './lib/index.js';
36

4-
/** @type {import('eslint-remote-tester').Config} */
57
export default {
68
/** Repositories to scan */
79
repositories: [
@@ -43,6 +45,7 @@ export default {
4345
cache: false,
4446

4547
/** ESLint configuration */
48+
// @ts-expect-error - eslint-plugin is not typed yet
4649
eslintConfig: [
4750
{
4851
files: ['**/*.{js,mjs,cjs,ts,mts,cts}'],
@@ -56,4 +59,4 @@ export default {
5659
},
5760
},
5861
],
59-
};
62+
} satisfies Config;

eslint.config.js renamed to eslint.config.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import path from 'node:path';
22
import { fileURLToPath } from 'node:url';
33
import js from '@eslint/js';
44
import { FlatCompat } from '@eslint/eslintrc';
5+
import { defineConfig } from 'eslint/config';
56
import markdown from 'eslint-plugin-markdown';
67
import pluginN from 'eslint-plugin-n';
78
import eslintPlugin from './lib/index.js';
@@ -12,10 +13,10 @@ const compat = new FlatCompat({
1213
recommendedConfig: js.configs.recommended,
1314
});
1415

15-
export default [
16+
export default defineConfig([
1617
// Global ignores
1718
{
18-
ignores: ['node_modules', 'coverage'],
19+
ignores: ['node_modules', 'coverage', 'dist'],
1920
},
2021
// Global settings
2122
{
@@ -39,7 +40,6 @@ export default [
3940
'unicorn/no-array-reduce': 'off',
4041
'unicorn/no-null': 'off',
4142
'unicorn/prefer-module': 'off',
42-
'unicorn/prefer-node-protocol': 'off', // TODO: enable once we drop support for Node 14.17.
4343
'unicorn/prevent-abbreviations': 'off',
4444
},
4545
},
@@ -82,4 +82,4 @@ export default [
8282
'unicorn/filename-case': 'off',
8383
},
8484
},
85-
];
85+
]);

lib/index.js renamed to lib/index.ts

Lines changed: 56 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@
22
* @fileoverview An ESLint plugin for linting ESLint plugins
33
* @author Teddy Katz
44
*/
5+
import { createRequire } from 'node:module';
56

6-
// ------------------------------------------------------------------------------
7-
// Requirements
8-
// ------------------------------------------------------------------------------
7+
import type { ESLint, Linter, Rule } from 'eslint';
98

10-
import packageMetadata from '../package.json' with { type: 'json' };
119
import consistentOutput from './rules/consistent-output.js';
1210
import fixerReturn from './rules/fixer-return.js';
1311
import metaPropertyOrdering from './rules/meta-property-ordering.js';
@@ -41,20 +39,56 @@ import requireMetaType from './rules/require-meta-type.js';
4139
import testCasePropertyOrdering from './rules/test-case-property-ordering.js';
4240
import testCaseShorthandStrings from './rules/test-case-shorthand-strings.js';
4341

42+
const require = createRequire(import.meta.url);
43+
44+
const packageMetadata = require("../package.json") as {
45+
name: string;
46+
version: string;
47+
};
48+
4449
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];
4560

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+
),
4868
'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) =>
5373
configFilters.recommended(rule) && configFilters.rules(rule),
54-
'tests-recommended': (rule) =>
74+
'tests-recommended': (rule: Rule.RuleModule) =>
5575
configFilters.recommended(rule) && configFilters.tests(rule),
5676
};
5777

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+
5892
// ------------------------------------------------------------------------------
5993
// Plugin Definition
6094
// ------------------------------------------------------------------------------
@@ -93,34 +127,23 @@ const allRules = {
93127
'require-meta-type': requireMetaType,
94128
'test-case-property-ordering': testCasePropertyOrdering,
95129
'test-case-shorthand-strings': testCaseShorthandStrings,
96-
};
130+
} satisfies Record<string, Rule.RuleModule>;
97131

98-
/** @type {import("eslint").ESLint.Plugin} */
99132
const plugin = {
100133
meta: {
101134
name: packageMetadata.name,
102135
version: packageMetadata.version,
103136
},
104137
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;
125148

126149
export default plugin;

lib/rules/consistent-output.js renamed to lib/rules/consistent-output.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@
22
* @fileoverview Enforce consistent use of `output` assertions in rule tests
33
* @author Teddy Katz
44
*/
5+
import type { Rule } from 'eslint';
56

6-
import * as utils from '../utils.js';
7+
import { getKeyName, getTestInfo } from '../utils.js';
8+
9+
const keyNameMapper = (property: Parameters<typeof getKeyName>[0]) =>
10+
getKeyName(property);
711

812
// ------------------------------------------------------------------------------
913
// Rule Definition
1014
// ------------------------------------------------------------------------------
11-
12-
/** @type {import('eslint').Rule.RuleModule} */
13-
const rule = {
15+
const rule: Rule.RuleModule = {
1416
meta: {
1517
type: 'suggestion',
1618
docs: {
@@ -20,7 +22,7 @@ const rule = {
2022
recommended: false,
2123
url: 'https://github.com/eslint-community/eslint-plugin-eslint-plugin/tree/HEAD/docs/rules/consistent-output.md',
2224
},
23-
fixable: null, // or "code" or "whitespace"
25+
fixable: undefined, // or "code" or "whitespace"
2426
schema: [
2527
{
2628
type: 'string',
@@ -37,20 +39,18 @@ const rule = {
3739
},
3840

3941
create(context) {
40-
// ----------------------------------------------------------------------
41-
// Public
42-
// ----------------------------------------------------------------------
43-
const always = context.options[0] && context.options[0] === 'always';
42+
const always: boolean =
43+
context.options[0] && context.options[0] === 'always';
4444

4545
return {
4646
Program(ast) {
47-
utils.getTestInfo(context, ast).forEach((testRun) => {
47+
getTestInfo(context, ast).forEach((testRun) => {
4848
const readableCases = testRun.invalid.filter(
49-
(testCase) => testCase.type === 'ObjectExpression',
49+
(testCase) => testCase?.type === 'ObjectExpression',
5050
);
5151
const casesWithoutOutput = readableCases.filter(
5252
(testCase) =>
53-
!testCase.properties.map(utils.getKeyName).includes('output'),
53+
!testCase.properties.map(keyNameMapper).includes('output'),
5454
);
5555

5656
if (

0 commit comments

Comments
 (0)