Skip to content

Commit e325b72

Browse files
golopotbradzacher
authored andcommitted
feat(eslint-plugin): [ban-types] Support namespaced type (#616)
1 parent 606fc70 commit e325b72

File tree

2 files changed

+119
-36
lines changed

2 files changed

+119
-36
lines changed

packages/eslint-plugin/src/rules/ban-types.ts

+41-36
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
import {
2-
TSESLint,
3-
TSESTree,
4-
AST_NODE_TYPES,
5-
} from '@typescript-eslint/experimental-utils';
1+
import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils';
62
import * as util from '../util';
73

84
type Options = [
@@ -20,6 +16,31 @@ type Options = [
2016
];
2117
type MessageIds = 'bannedTypeMessage';
2218

19+
function stringifyTypeName(
20+
node: TSESTree.EntityName,
21+
sourceCode: TSESLint.SourceCode,
22+
): string {
23+
return sourceCode.getText(node).replace(/ /g, '');
24+
}
25+
26+
function getCustomMessage(
27+
bannedType: null | string | { message?: string; fixWith?: string },
28+
) {
29+
if (bannedType === null) {
30+
return '';
31+
}
32+
33+
if (typeof bannedType === 'string') {
34+
return ` ${bannedType}`;
35+
}
36+
37+
if (bannedType.message) {
38+
return ` ${bannedType.message}`;
39+
}
40+
41+
return '';
42+
}
43+
2344
export default util.createRule<Options, MessageIds>({
2445
name: 'ban-types',
2546
meta: {
@@ -87,39 +108,23 @@ export default util.createRule<Options, MessageIds>({
87108
],
88109
create(context, [{ types: bannedTypes }]) {
89110
return {
90-
'TSTypeReference Identifier'(node: TSESTree.Identifier) {
91-
if (
92-
node.parent &&
93-
node.parent.type !== AST_NODE_TYPES.TSQualifiedName
94-
) {
95-
if (node.name in bannedTypes) {
96-
let customMessage = '';
97-
const bannedCfgValue = bannedTypes[node.name];
111+
TSTypeReference({ typeName }) {
112+
const name = stringifyTypeName(typeName, context.getSourceCode());
98113

99-
let fix: TSESLint.ReportFixFunction | null = null;
114+
if (name in bannedTypes) {
115+
const bannedType = bannedTypes[name];
116+
const customMessage = getCustomMessage(bannedType);
117+
const fixWith = bannedType && (bannedType as any).fixWith;
100118

101-
if (typeof bannedCfgValue === 'string') {
102-
customMessage += ` ${bannedCfgValue}`;
103-
} else if (bannedCfgValue !== null) {
104-
if (bannedCfgValue.message) {
105-
customMessage += ` ${bannedCfgValue.message}`;
106-
}
107-
if (bannedCfgValue.fixWith) {
108-
const fixWith = bannedCfgValue.fixWith;
109-
fix = fixer => fixer.replaceText(node, fixWith);
110-
}
111-
}
112-
113-
context.report({
114-
node,
115-
messageId: 'bannedTypeMessage',
116-
data: {
117-
name: node.name,
118-
customMessage,
119-
},
120-
fix,
121-
});
122-
}
119+
context.report({
120+
node: typeName,
121+
messageId: 'bannedTypeMessage',
122+
data: {
123+
name: name,
124+
customMessage,
125+
},
126+
fix: fixWith ? fixer => fixer.replaceText(typeName, fixWith) : null,
127+
});
123128
}
124129
},
125130
};

packages/eslint-plugin/tests/rules/ban-types.test.ts

+78
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ const options: InferOptionsTypeFromRule<typeof rule> = [
1616
Object: "Use '{}' instead.",
1717
Array: null,
1818
F: null,
19+
'NS.Bad': {
20+
message: 'Use NS.Good instead.',
21+
fixWith: 'NS.Good',
22+
},
1923
},
2024
},
2125
];
@@ -39,6 +43,14 @@ ruleTester.run('ban-types', rule, {
3943
code: 'let e: foo.String;',
4044
options,
4145
},
46+
{
47+
code: 'let a: _.NS.Bad',
48+
options,
49+
},
50+
{
51+
code: 'let a: NS.Bad._',
52+
options,
53+
},
4254
],
4355
invalid: [
4456
{
@@ -56,6 +68,25 @@ ruleTester.run('ban-types', rule, {
5668
],
5769
options,
5870
},
71+
{
72+
code: 'let aa: Foo;',
73+
errors: [
74+
{
75+
messageId: 'bannedTypeMessage',
76+
data: {
77+
name: 'Foo',
78+
customMessage: '',
79+
},
80+
},
81+
],
82+
options: [
83+
{
84+
types: {
85+
Foo: { message: '' },
86+
},
87+
},
88+
],
89+
},
5990
{
6091
code: 'let b: {c: String};',
6192
output: 'let b: {c: string};',
@@ -217,5 +248,52 @@ class Foo<F = string> extends Bar<string> implements Baz<Object> {
217248
],
218249
options,
219250
},
251+
{
252+
code: 'let a: NS.Bad;',
253+
output: 'let a: NS.Good;',
254+
errors: [
255+
{
256+
messageId: 'bannedTypeMessage',
257+
data: {
258+
name: 'NS.Bad',
259+
customMessage: ' Use NS.Good instead.',
260+
},
261+
line: 1,
262+
column: 8,
263+
},
264+
],
265+
options,
266+
},
267+
{
268+
code: `
269+
let a: NS.Bad<Foo>;
270+
let b: Foo<NS.Bad>;
271+
`,
272+
output: `
273+
let a: NS.Good<Foo>;
274+
let b: Foo<NS.Good>;
275+
`,
276+
errors: [
277+
{
278+
messageId: 'bannedTypeMessage',
279+
data: {
280+
name: 'NS.Bad',
281+
customMessage: ' Use NS.Good instead.',
282+
},
283+
line: 2,
284+
column: 8,
285+
},
286+
{
287+
messageId: 'bannedTypeMessage',
288+
data: {
289+
name: 'NS.Bad',
290+
customMessage: ' Use NS.Good instead.',
291+
},
292+
line: 3,
293+
column: 12,
294+
},
295+
],
296+
options,
297+
},
220298
],
221299
});

0 commit comments

Comments
 (0)