Skip to content

Commit 647ffc4

Browse files
committed
refactor: include create-testing-library-rule
1 parent 644d1c4 commit 647ffc4

File tree

3 files changed

+102
-52
lines changed

3 files changed

+102
-52
lines changed

lib/create-testing-library-rule.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { ESLintUtils, TSESLint } from '@typescript-eslint/experimental-utils';
2+
import { getDocsUrl } from './utils';
3+
import {
4+
detectTestingLibraryUtils,
5+
DetectionHelpers,
6+
} from './detect-testing-library-utils';
7+
8+
type CreateRuleMetaDocs = Omit<TSESLint.RuleMetaDataDocs, 'url'>;
9+
type CreateRuleMeta<TMessageIds extends string> = {
10+
docs: CreateRuleMetaDocs;
11+
} & Omit<TSESLint.RuleMetaData<TMessageIds>, 'docs'>;
12+
13+
export function createTestingLibraryRule<
14+
TOptions extends readonly unknown[],
15+
TMessageIds extends string,
16+
TRuleListener extends TSESLint.RuleListener = TSESLint.RuleListener
17+
>(
18+
config: Readonly<{
19+
name: string;
20+
meta: CreateRuleMeta<TMessageIds>;
21+
defaultOptions: Readonly<TOptions>;
22+
create: (
23+
context: Readonly<TSESLint.RuleContext<TMessageIds, TOptions>>,
24+
optionsWithDefault: Readonly<TOptions>,
25+
detectionHelpers: Readonly<DetectionHelpers>
26+
) => TRuleListener;
27+
}>
28+
) {
29+
const { create, ...remainingConfig } = config;
30+
31+
return ESLintUtils.RuleCreator(getDocsUrl)({
32+
...remainingConfig,
33+
create: detectTestingLibraryUtils<TOptions, TMessageIds, TRuleListener>(
34+
create
35+
),
36+
});
37+
}

lib/detect-testing-library-utils.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils';
2+
3+
export type DetectionHelpers = {
4+
getIsImportingTestingLibrary: () => boolean;
5+
};
6+
7+
/**
8+
* Enhances a given rule `create` with helpers to detect Testing Library utils.
9+
*/
10+
export function detectTestingLibraryUtils<
11+
TOptions extends readonly unknown[],
12+
TMessageIds extends string,
13+
TRuleListener extends TSESLint.RuleListener = TSESLint.RuleListener
14+
>(
15+
ruleCreate: (
16+
context: Readonly<TSESLint.RuleContext<TMessageIds, TOptions>>,
17+
optionsWithDefault: Readonly<TOptions>,
18+
detectionHelpers: Readonly<DetectionHelpers>
19+
) => TRuleListener
20+
) {
21+
return (
22+
context: Readonly<TSESLint.RuleContext<TMessageIds, TOptions>>,
23+
optionsWithDefault: Readonly<TOptions>
24+
): TRuleListener => {
25+
let isImportingTestingLibrary = false;
26+
27+
// TODO: init here options based on shared ESLint config
28+
29+
// helpers for Testing Library detection
30+
const helpers: DetectionHelpers = {
31+
getIsImportingTestingLibrary() {
32+
return isImportingTestingLibrary;
33+
},
34+
};
35+
36+
// instructions for Testing Library detection
37+
const detectionInstructions: TSESLint.RuleListener = {
38+
ImportDeclaration(node: TSESTree.ImportDeclaration) {
39+
isImportingTestingLibrary = /testing-library/g.test(
40+
node.source.value as string
41+
);
42+
},
43+
};
44+
45+
// update given rule to inject Testing Library detection
46+
const ruleInstructions = ruleCreate(context, optionsWithDefault, helpers);
47+
const enhancedRuleInstructions = Object.assign({}, ruleInstructions);
48+
49+
Object.keys(detectionInstructions).forEach((instruction) => {
50+
(enhancedRuleInstructions as TSESLint.RuleListener)[instruction] = (
51+
node
52+
) => {
53+
if (instruction in detectionInstructions) {
54+
detectionInstructions[instruction](node);
55+
}
56+
57+
if (ruleInstructions[instruction]) {
58+
return ruleInstructions[instruction](node);
59+
}
60+
};
61+
});
62+
63+
return enhancedRuleInstructions;
64+
};
65+
}

lib/testing-library-detection.ts

Lines changed: 0 additions & 52 deletions
This file was deleted.

0 commit comments

Comments
 (0)