Skip to content

Commit e27403f

Browse files
committed
chore: add generate-configs script
1 parent 50c2d90 commit e27403f

File tree

7 files changed

+99
-11
lines changed

7 files changed

+99
-11
lines changed

lib/configs/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
SupportedTestingFramework,
99
} from '../utils';
1010

11-
type LinterConfigRules = Record<string, TSESLint.Linter.RuleEntry>;
11+
export type LinterConfigRules = Record<string, TSESLint.Linter.RuleEntry>;
1212

1313
const configsDir = __dirname;
1414

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,25 @@
11
import { ESLintUtils, TSESLint } from '@typescript-eslint/experimental-utils';
22

3-
import { getDocsUrl } from '../utils';
3+
import { getDocsUrl, TestingLibraryRuleMeta } from '../utils';
44

55
import {
66
DetectionOptions,
77
detectTestingLibraryUtils,
88
EnhancedRuleCreate,
99
} from './detect-testing-library-utils';
1010

11-
// These 2 types are copied from @typescript-eslint/experimental-utils
12-
type CreateRuleMetaDocs = Omit<TSESLint.RuleMetaDataDocs, 'url'>;
13-
type CreateRuleMeta<TMessageIds extends string> = {
14-
docs: CreateRuleMetaDocs;
15-
} & Omit<TSESLint.RuleMetaData<TMessageIds>, 'docs'>;
16-
1711
export function createTestingLibraryRule<
1812
TOptions extends readonly unknown[],
1913
TMessageIds extends string,
2014
TRuleListener extends TSESLint.RuleListener = TSESLint.RuleListener
2115
>({
2216
create,
2317
detectionOptions = {},
18+
meta,
2419
...remainingConfig
2520
}: Readonly<{
2621
name: string;
27-
meta: CreateRuleMeta<TMessageIds>;
22+
meta: TestingLibraryRuleMeta<TMessageIds>;
2823
defaultOptions: Readonly<TOptions>;
2924
detectionOptions?: Partial<DetectionOptions>;
3025
create: EnhancedRuleCreate<TOptions, TMessageIds, TRuleListener>;
@@ -35,5 +30,12 @@ export function createTestingLibraryRule<
3530
create,
3631
detectionOptions
3732
),
33+
meta: {
34+
...meta,
35+
docs: {
36+
...meta.docs,
37+
recommended: false,
38+
},
39+
},
3840
});
3941
}

lib/rules/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import { join, parse } from 'path';
33

44
import { TSESLint } from '@typescript-eslint/experimental-utils';
55

6-
import { importDefault } from '../utils';
6+
import { importDefault, TestingLibraryRuleMeta } from '../utils';
77

8-
type RuleModule = TSESLint.RuleModule<string, unknown[]>;
8+
type RuleModule = TSESLint.RuleModule<string, unknown[]> & {
9+
meta: TestingLibraryRuleMeta<string>;
10+
};
911

1012
const rulesDir = __dirname;
1113
const excludedFiles = ['index'];

lib/utils/types.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
import type { TSESLint } from '@typescript-eslint/experimental-utils';
2+
3+
// These 2 types are copied from @typescript-eslint/experimental-utils' CreateRuleMeta
4+
// and modified to our needs
5+
type TestingLibraryRuleMetaDocs = Omit<
6+
TSESLint.RuleMetaDataDocs,
7+
'recommended' | 'url'
8+
> & {
9+
recommended: Record<
10+
SupportedTestingFramework,
11+
TSESLint.RuleMetaDataDocs['recommended']
12+
>;
13+
};
14+
export type TestingLibraryRuleMeta<TMessageIds extends string> = {
15+
docs: TestingLibraryRuleMetaDocs;
16+
} & Omit<TSESLint.RuleMetaData<TMessageIds>, 'docs'>;
17+
118
export const SUPPORTED_TESTING_FRAMEWORKS = [
219
'dom',
320
'angular',

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"postbuild": "cpy README.md ./dist && cpy package.json ./dist && cpy LICENSE ./dist",
3030
"format": "prettier --write .",
3131
"format:check": "prettier --check .",
32+
"generate:configs": "ts-node tools/generate-configs",
3233
"lint": "eslint . --max-warnings 0 --ext .js,.ts",
3334
"lint:fix": "npm run lint -- --fix",
3435
"test": "jest",

tools/generate-configs/index.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import type { LinterConfigRules } from '../../lib/configs';
2+
import rules from '../../lib/rules';
3+
import {
4+
SUPPORTED_TESTING_FRAMEWORKS,
5+
SupportedTestingFramework,
6+
} from '../../lib/utils';
7+
8+
import { LinterConfig, writeConfig } from './utils';
9+
10+
const RULE_NAME_PREFIX = 'testing-library/';
11+
12+
const getRecommendedRulesForTestingFramework = (
13+
framework: SupportedTestingFramework
14+
): LinterConfigRules =>
15+
Object.entries(rules)
16+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
17+
.filter(([_, { meta: { docs } }]) => Boolean(docs.recommended[framework]))
18+
.reduce(
19+
(allRules, [ruleName, { meta }]) => ({
20+
...allRules,
21+
[ruleName.split(RULE_NAME_PREFIX)[0]]: meta.docs.recommended[framework],
22+
}),
23+
{}
24+
);
25+
26+
SUPPORTED_TESTING_FRAMEWORKS.forEach((framework) => {
27+
const specificFrameworkConfig: LinterConfig = {
28+
plugins: ['testing-library'],
29+
rules: getRecommendedRulesForTestingFramework(framework),
30+
};
31+
32+
writeConfig(specificFrameworkConfig, framework);
33+
});

tools/generate-configs/utils.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { writeFileSync } from 'fs';
2+
import { resolve } from 'path';
3+
4+
import type { TSESLint } from '@typescript-eslint/experimental-utils';
5+
import { format, resolveConfig } from 'prettier';
6+
7+
const prettierConfig = resolveConfig.sync(__dirname);
8+
9+
export type LinterConfig = TSESLint.Linter.Config;
10+
11+
const addAutoGeneratedComment = (code: string) =>
12+
[
13+
'// THIS CODE WAS AUTOMATICALLY GENERATED',
14+
'// DO NOT EDIT THIS CODE BY HAND',
15+
'// YOU CAN REGENERATE IT USING yarn generate:configs',
16+
'',
17+
code,
18+
].join('\n');
19+
20+
/**
21+
* Helper function writes configuration.
22+
*/
23+
export const writeConfig = (config: LinterConfig, configName: string): void => {
24+
// note: we use `export =` because ESLint will import these configs via a commonjs import
25+
const code = `export = ${JSON.stringify(config)};`;
26+
const configStr = format(addAutoGeneratedComment(code), {
27+
parser: 'typescript',
28+
...prettierConfig,
29+
});
30+
const filePath = resolve(__dirname, `../../lib/configs/${configName}.ts`);
31+
32+
writeFileSync(filePath, configStr);
33+
};

0 commit comments

Comments
 (0)