From 4e7c9be6ff7e2448f4151563d7921cd285c2e349 Mon Sep 17 00:00:00 2001 From: Zach Kirsch Date: Fri, 22 Apr 2022 10:25:21 -0700 Subject: [PATCH] fix(eslint-plugin): [no-namespace] fix false positive for exported namespaces when allowDeclarations=true (#4844) * Add failing test * Fix isDeclaration to look recursively * Add more tests --- .../eslint-plugin/src/rules/no-namespace.ts | 15 +- .../tests/rules/no-namespace.test.ts | 312 ++++++++++++++++++ 2 files changed, 321 insertions(+), 6 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-namespace.ts b/packages/eslint-plugin/src/rules/no-namespace.ts index c8c3ff21395..c7183444e8b 100644 --- a/packages/eslint-plugin/src/rules/no-namespace.ts +++ b/packages/eslint-plugin/src/rules/no-namespace.ts @@ -46,12 +46,15 @@ export default util.createRule({ create(context, [{ allowDeclarations, allowDefinitionFiles }]) { const filename = context.getFilename(); - function isDeclaration(node: TSESTree.TSModuleDeclaration): boolean { - return ( - node.declare === true || - (node.parent!.parent?.type === AST_NODE_TYPES.TSModuleDeclaration && - isDeclaration(node.parent!.parent)) - ); + function isDeclaration(node: TSESTree.Node): boolean { + if ( + node.type === AST_NODE_TYPES.TSModuleDeclaration && + node.declare === true + ) { + return true; + } + + return node.parent != null && isDeclaration(node.parent); } return { diff --git a/packages/eslint-plugin/tests/rules/no-namespace.test.ts b/packages/eslint-plugin/tests/rules/no-namespace.test.ts index 3bb9079b3fc..11d9d1a6fca 100644 --- a/packages/eslint-plugin/tests/rules/no-namespace.test.ts +++ b/packages/eslint-plugin/tests/rules/no-namespace.test.ts @@ -49,6 +49,16 @@ declare namespace foo { namespace bar { namespace baz {} } +} + `, + options: [{ allowDeclarations: true }], + }, + { + code: ` +export declare namespace foo { + export namespace bar { + namespace baz {} + } } `, options: [{ allowDeclarations: true }], @@ -251,5 +261,307 @@ namespace Foo.Bar { }, ], }, + { + code: ` +namespace A { + namespace B { + declare namespace C {} + } +} + `, + errors: [ + { + messageId: 'moduleSyntaxIsPreferred', + line: 2, + column: 1, + }, + { + messageId: 'moduleSyntaxIsPreferred', + line: 3, + column: 3, + }, + ], + options: [{ allowDeclarations: true }], + }, + { + code: ` +namespace A { + namespace B { + export declare namespace C {} + } +} + `, + errors: [ + { + messageId: 'moduleSyntaxIsPreferred', + line: 2, + column: 1, + }, + { + messageId: 'moduleSyntaxIsPreferred', + line: 3, + column: 3, + }, + ], + options: [{ allowDeclarations: true }], + }, + { + code: ` +namespace A { + declare namespace B { + namespace C {} + } +} + `, + errors: [ + { + messageId: 'moduleSyntaxIsPreferred', + line: 2, + column: 1, + }, + ], + options: [{ allowDeclarations: true }], + }, + { + code: ` +namespace A { + export declare namespace B { + namespace C {} + } +} + `, + errors: [ + { + messageId: 'moduleSyntaxIsPreferred', + line: 2, + column: 1, + }, + ], + options: [{ allowDeclarations: true }], + }, + { + code: ` +namespace A { + export declare namespace B { + declare namespace C {} + } +} + `, + errors: [ + { + messageId: 'moduleSyntaxIsPreferred', + line: 2, + column: 1, + }, + ], + options: [{ allowDeclarations: true }], + }, + { + code: ` +namespace A { + export declare namespace B { + export declare namespace C {} + } +} + `, + errors: [ + { + messageId: 'moduleSyntaxIsPreferred', + line: 2, + column: 1, + }, + ], + options: [{ allowDeclarations: true }], + }, + { + code: ` +namespace A { + declare namespace B { + export declare namespace C {} + } +} + `, + errors: [ + { + messageId: 'moduleSyntaxIsPreferred', + line: 2, + column: 1, + }, + ], + options: [{ allowDeclarations: true }], + }, + { + code: ` +namespace A { + export namespace B { + export declare namespace C {} + } +} + `, + errors: [ + { + messageId: 'moduleSyntaxIsPreferred', + line: 2, + column: 1, + }, + { + messageId: 'moduleSyntaxIsPreferred', + line: 3, + column: 10, + }, + ], + options: [{ allowDeclarations: true }], + }, + { + code: ` +export namespace A { + namespace B { + declare namespace C {} + } +} + `, + errors: [ + { + messageId: 'moduleSyntaxIsPreferred', + line: 2, + column: 8, + }, + { + messageId: 'moduleSyntaxIsPreferred', + line: 3, + column: 3, + }, + ], + options: [{ allowDeclarations: true }], + }, + { + code: ` +export namespace A { + namespace B { + export declare namespace C {} + } +} + `, + errors: [ + { + messageId: 'moduleSyntaxIsPreferred', + line: 2, + column: 8, + }, + { + messageId: 'moduleSyntaxIsPreferred', + line: 3, + column: 3, + }, + ], + options: [{ allowDeclarations: true }], + }, + { + code: ` +export namespace A { + declare namespace B { + namespace C {} + } +} + `, + errors: [ + { + messageId: 'moduleSyntaxIsPreferred', + line: 2, + column: 8, + }, + ], + options: [{ allowDeclarations: true }], + }, + { + code: ` +export namespace A { + export declare namespace B { + namespace C {} + } +} + `, + errors: [ + { + messageId: 'moduleSyntaxIsPreferred', + line: 2, + column: 8, + }, + ], + options: [{ allowDeclarations: true }], + }, + { + code: ` +export namespace A { + export declare namespace B { + declare namespace C {} + } +} + `, + errors: [ + { + messageId: 'moduleSyntaxIsPreferred', + line: 2, + column: 8, + }, + ], + options: [{ allowDeclarations: true }], + }, + { + code: ` +export namespace A { + export declare namespace B { + export declare namespace C {} + } +} + `, + errors: [ + { + messageId: 'moduleSyntaxIsPreferred', + line: 2, + column: 8, + }, + ], + options: [{ allowDeclarations: true }], + }, + { + code: ` +export namespace A { + declare namespace B { + export declare namespace C {} + } +} + `, + errors: [ + { + messageId: 'moduleSyntaxIsPreferred', + line: 2, + column: 8, + }, + ], + options: [{ allowDeclarations: true }], + }, + { + code: ` +export namespace A { + export namespace B { + export declare namespace C {} + } +} + `, + errors: [ + { + messageId: 'moduleSyntaxIsPreferred', + line: 2, + column: 8, + }, + { + messageId: 'moduleSyntaxIsPreferred', + line: 3, + column: 10, + }, + ], + options: [{ allowDeclarations: true }], + }, ], });