diff --git a/packages/eslint-plugin/docs/rules/no-namespace.md b/packages/eslint-plugin/docs/rules/no-namespace.md index d82ad724b7b..b155c2aeb30 100644 --- a/packages/eslint-plugin/docs/rules/no-namespace.md +++ b/packages/eslint-plugin/docs/rules/no-namespace.md @@ -51,6 +51,14 @@ Examples of **correct** code for the `{ "allowDeclarations": true }` option: declare module 'foo' {} declare module foo {} declare namespace foo {} + +declare global { + namespace foo {} +} + +declare module foo { + namespace foo {} +} ``` Examples of **incorrect** code for the `{ "allowDeclarations": false }` option: diff --git a/packages/eslint-plugin/src/rules/no-namespace.ts b/packages/eslint-plugin/src/rules/no-namespace.ts index 3698b4f941b..f8cc05b1047 100644 --- a/packages/eslint-plugin/src/rules/no-namespace.ts +++ b/packages/eslint-plugin/src/rules/no-namespace.ts @@ -50,6 +50,14 @@ 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)) + ); + } + return { "TSModuleDeclaration[global!=true][id.type='Identifier']"( node: TSESTree.TSModuleDeclaration, @@ -58,7 +66,7 @@ export default util.createRule({ (node.parent && node.parent.type === AST_NODE_TYPES.TSModuleDeclaration) || (allowDefinitionFiles && util.isDefinitionFile(filename)) || - (allowDeclarations && node.declare === true) + (allowDeclarations && isDeclaration(node)) ) { return; } diff --git a/packages/eslint-plugin/tests/rules/no-namespace.test.ts b/packages/eslint-plugin/tests/rules/no-namespace.test.ts index e175f5895df..3bb9079b3fc 100644 --- a/packages/eslint-plugin/tests/rules/no-namespace.test.ts +++ b/packages/eslint-plugin/tests/rules/no-namespace.test.ts @@ -17,6 +17,42 @@ ruleTester.run('no-namespace', rule, { code: 'declare namespace foo {}', options: [{ allowDeclarations: true }], }, + { + code: ` +declare global { + namespace foo {} +} + `, + options: [{ allowDeclarations: true }], + }, + { + code: ` +declare module foo { + namespace bar {} +} + `, + options: [{ allowDeclarations: true }], + }, + { + code: ` +declare global { + namespace foo { + namespace bar {} + } +} + `, + options: [{ allowDeclarations: true }], + }, + { + code: ` +declare namespace foo { + namespace bar { + namespace baz {} + } +} + `, + options: [{ allowDeclarations: true }], + }, { filename: 'test.d.ts', code: 'namespace foo {}', @@ -71,6 +107,28 @@ ruleTester.run('no-namespace', rule, { }, ], }, + { + code: 'module foo {}', + options: [{ allowDeclarations: true }], + errors: [ + { + messageId: 'moduleSyntaxIsPreferred', + line: 1, + column: 1, + }, + ], + }, + { + code: 'namespace foo {}', + options: [{ allowDeclarations: true }], + errors: [ + { + messageId: 'moduleSyntaxIsPreferred', + line: 1, + column: 1, + }, + ], + }, { code: 'declare module foo {}', errors: [