Skip to content

Commit

Permalink
feat(eslint-plugin): [ban-types] allow banning null and undefined (#821)
Browse files Browse the repository at this point in the history
Co-authored-by: Brad Zacher <brad.zacher@gmail.com>
  • Loading branch information
Validark and bradzacher committed Feb 12, 2020
1 parent ae2754e commit 0b2b887
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 8 deletions.
35 changes: 27 additions & 8 deletions packages/eslint-plugin/src/rules/ban-types.ts
Expand Up @@ -23,7 +23,11 @@ function removeSpaces(str: string): string {
}

function stringifyTypeName(
node: TSESTree.EntityName | TSESTree.TSTypeLiteral,
node:
| TSESTree.EntityName
| TSESTree.TSTypeLiteral
| TSESTree.TSNullKeyword
| TSESTree.TSUndefinedKeyword,
sourceCode: TSESLint.SourceCode,
): string {
return removeSpaces(sourceCode.getText(node));
Expand Down Expand Up @@ -113,18 +117,21 @@ export default util.createRule<Options, MessageIds>({
},
],
create(context, [{ types }]) {
const bannedTypes: Types = Object.keys(types).reduce(
(res, type) => ({ ...res, [removeSpaces(type)]: types[type] }),
{},
const bannedTypes = new Map(
Object.entries(types).map(([type, data]) => [removeSpaces(type), data]),
);

function checkBannedTypes(
typeNode: TSESTree.EntityName | TSESTree.TSTypeLiteral,
typeNode:
| TSESTree.EntityName
| TSESTree.TSTypeLiteral
| TSESTree.TSNullKeyword
| TSESTree.TSUndefinedKeyword,
name = stringifyTypeName(typeNode, context.getSourceCode()),
): void {
const name = stringifyTypeName(typeNode, context.getSourceCode());
const bannedType = bannedTypes.get(name);

if (name in bannedTypes) {
const bannedType = bannedTypes[name];
if (bannedType !== undefined) {
const customMessage = getCustomMessage(bannedType);
const fixWith =
bannedType && typeof bannedType === 'object' && bannedType.fixWith;
Expand All @@ -144,6 +151,18 @@ export default util.createRule<Options, MessageIds>({
}

return {
...(bannedTypes.has('null') && {
TSNullKeyword(node): void {
checkBannedTypes(node, 'null');
},
}),

...(bannedTypes.has('undefined') && {
TSUndefinedKeyword(node): void {
checkBannedTypes(node, 'undefined');
},
}),

TSTypeLiteral(node): void {
if (node.members.length) {
return;
Expand Down
51 changes: 51 additions & 0 deletions packages/eslint-plugin/tests/rules/ban-types.test.ts
Expand Up @@ -24,6 +24,25 @@ const options: InferOptionsTypeFromRule<typeof rule> = [
},
];

const options2: InferOptionsTypeFromRule<typeof rule> = [
{
types: {
null: {
message: 'Use undefined instead.',
fixWith: 'undefined',
},
},
},
];

const options3: InferOptionsTypeFromRule<typeof rule> = [
{
types: {
undefined: null,
},
},
];

ruleTester.run('ban-types', rule, {
valid: [
'let f = Object();', // Should not fail if there is no options set
Expand Down Expand Up @@ -53,6 +72,14 @@ ruleTester.run('ban-types', rule, {
code: 'let a: NS.Bad._',
options,
},
{
code: 'let a: undefined',
options: options2,
},
{
code: 'let a: null',
options: options3,
},
],
invalid: [
{
Expand All @@ -70,6 +97,30 @@ ruleTester.run('ban-types', rule, {
],
options,
},
{
code: 'let a: undefined;',
errors: [
{
messageId: 'bannedTypeMessage',
data: { name: 'undefined', customMessage: '' },
line: 1,
column: 8,
},
],
options: options3,
},
{
code: 'let a: null;',
errors: [
{
messageId: 'bannedTypeMessage',
data: { name: 'null', customMessage: ' Use undefined instead.' },
line: 1,
column: 8,
},
],
options: options2,
},
{
code: 'let aa: Foo;',
errors: [
Expand Down

0 comments on commit 0b2b887

Please sign in to comment.