diff --git a/CHANGELOG.md b/CHANGELOG.md index 739701677..63de41cd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ## [Unreleased] ### Added -- [`no-named-default`, `no-default-export`, `prefer-default-export`, `no-named-export`, `export`, `named`, `namespace`]: support arbitrary module namespace names ([#2358], thanks [@sosukesuzuki]) +- [`no-named-default`, `no-default-export`, `prefer-default-export`, `no-named-export`, `export`, `named`, `namespace`, `no-unused-modules`]: support arbitrary module namespace names ([#2358], thanks [@sosukesuzuki]) ### Changed - [Tests] `no-nodejs-modules`: add tests for node protocol URL ([#2367], thanks [@sosukesuzuki]) diff --git a/src/ExportMap.js b/src/ExportMap.js index f11a8752f..7425dce44 100644 --- a/src/ExportMap.js +++ b/src/ExportMap.js @@ -593,7 +593,7 @@ ExportMap.parse = function (path, content, context) { importedSpecifiers.add(specifier.type); } if (specifier.type === 'ImportSpecifier') { - importedSpecifiers.add(specifier.imported.name); + importedSpecifiers.add(specifier.imported.name || specifier.imported.value); } // import { type Foo } (Flow) diff --git a/src/rules/no-unused-modules.js b/src/rules/no-unused-modules.js index 9891d4097..efc216994 100644 --- a/src/rules/no-unused-modules.js +++ b/src/rules/no-unused-modules.js @@ -604,7 +604,7 @@ module.exports = { if (specifiers.length > 0) { specifiers.forEach(specifier => { if (specifier.exported) { - newExportIdentifiers.add(specifier.exported.name); + newExportIdentifiers.add(specifier.exported.name || specifier.exported.value); } }); } @@ -715,8 +715,8 @@ module.exports = { if (astNode.source) { resolvedPath = resolve(astNode.source.raw.replace(/('|")/g, ''), context); astNode.specifiers.forEach(specifier => { - const name = specifier.local.name; - if (specifier.local.name === DEFAULT) { + const name = specifier.local.name || specifier.local.value; + if (name === DEFAULT) { newDefaultImports.add(resolvedPath); } else { newImports.set(name, resolvedPath); @@ -753,7 +753,7 @@ module.exports = { specifier.type === IMPORT_NAMESPACE_SPECIFIER) { return; } - newImports.set(specifier.imported.name, resolvedPath); + newImports.set(specifier.imported.name || specifier.imported.value, resolvedPath); }); } }); @@ -942,7 +942,7 @@ module.exports = { }, 'ExportNamedDeclaration': node => { node.specifiers.forEach(specifier => { - checkUsage(node, specifier.exported.name); + checkUsage(node, specifier.exported.name || specifier.exported.value); }); forEachDeclarationIdentifier(node.declaration, (name) => { checkUsage(node, name); diff --git a/tests/files/no-unused-modules/arbitrary-module-namespace-identifier-name-a.js b/tests/files/no-unused-modules/arbitrary-module-namespace-identifier-name-a.js new file mode 100644 index 000000000..7ad810de8 --- /dev/null +++ b/tests/files/no-unused-modules/arbitrary-module-namespace-identifier-name-a.js @@ -0,0 +1,2 @@ +const foo = 333 +export { foo as "foo" } diff --git a/tests/files/no-unused-modules/arbitrary-module-namespace-identifier-name-b.js b/tests/files/no-unused-modules/arbitrary-module-namespace-identifier-name-b.js new file mode 100644 index 000000000..fa7652725 --- /dev/null +++ b/tests/files/no-unused-modules/arbitrary-module-namespace-identifier-name-b.js @@ -0,0 +1 @@ +import { "foo" as foo } from "./arbitrary-module-namespace-identifier-name-a.js" diff --git a/tests/files/no-unused-modules/arbitrary-module-namespace-identifier-name-c.js b/tests/files/no-unused-modules/arbitrary-module-namespace-identifier-name-c.js new file mode 100644 index 000000000..7ad810de8 --- /dev/null +++ b/tests/files/no-unused-modules/arbitrary-module-namespace-identifier-name-c.js @@ -0,0 +1,2 @@ +const foo = 333 +export { foo as "foo" } diff --git a/tests/src/rules/no-unused-modules.js b/tests/src/rules/no-unused-modules.js index 6f87058c4..8610ff4aa 100644 --- a/tests/src/rules/no-unused-modules.js +++ b/tests/src/rules/no-unused-modules.js @@ -1,4 +1,4 @@ -import { test, testFilePath, getTSParsers } from '../utils'; +import { test, testVersion, testFilePath, getTSParsers } from '../utils'; import jsxConfig from '../../../config/react'; import typescriptConfig from '../../../config/typescript'; @@ -1261,3 +1261,33 @@ describe('support (nested) destructuring assignment', () => { invalid: [], }); }); + +describe('support ES2022 Arbitrary module namespace identifier names', () => { + ruleTester.run('no-unused-module', rule, { + valid: [].concat( + testVersion('>= 8.7', () => ({ + options: unusedExportsOptions, + code: `import { "foo" as foo } from "./arbitrary-module-namespace-identifier-name-a"`, + parserOptions: { ecmaVersion: 2022 }, + filename: testFilePath('./no-unused-modules/arbitrary-module-namespace-identifier-name-b.js'), + })), + testVersion('>= 8.7', () => ({ + options: unusedExportsOptions, + code: 'const foo = 333;\nexport { foo as "foo" }', + parserOptions: { ecmaVersion: 2022 }, + filename: testFilePath('./no-unused-modules/arbitrary-module-namespace-identifier-name-a.js'), + })), + ), + invalid: [].concat( + testVersion('>= 8.7', () => ({ + options: unusedExportsOptions, + code: 'const foo = 333\nexport { foo as "foo" }', + parserOptions: { ecmaVersion: 2022 }, + filename: testFilePath('./no-unused-modules/arbitrary-module-namespace-identifier-name-c.js'), + errors: [ + error(`exported declaration 'foo' not used within other modules`), + ], + })), + ), + }); +});