diff --git a/src/Module.ts b/src/Module.ts index c9de0087abc..2ab229477a6 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -9,12 +9,13 @@ import { nodeConstructors } from './ast/nodes'; import ExportAllDeclaration from './ast/nodes/ExportAllDeclaration'; import ExportDefaultDeclaration from './ast/nodes/ExportDefaultDeclaration'; import type ExportNamedDeclaration from './ast/nodes/ExportNamedDeclaration'; -import type Identifier from './ast/nodes/Identifier'; +import Identifier from './ast/nodes/Identifier'; import type ImportDeclaration from './ast/nodes/ImportDeclaration'; +import ImportDefaultSpecifier from './ast/nodes/ImportDefaultSpecifier'; import type ImportExpression from './ast/nodes/ImportExpression'; +import ImportNamespaceSpecifier from './ast/nodes/ImportNamespaceSpecifier'; import Literal from './ast/nodes/Literal'; import type MetaProperty from './ast/nodes/MetaProperty'; -import * as NodeType from './ast/nodes/NodeType'; import Program from './ast/nodes/Program'; import TemplateLiteral from './ast/nodes/TemplateLiteral'; import VariableDeclaration from './ast/nodes/VariableDeclaration'; @@ -880,17 +881,17 @@ export default class Module { return localVariable; } - const importDeclaration = this.importDescriptions.get(name); - if (importDeclaration) { - const otherModule = importDeclaration.module; + const importDescription = this.importDescriptions.get(name); + if (importDescription) { + const otherModule = importDescription.module; - if (otherModule instanceof Module && importDeclaration.name === '*') { + if (otherModule instanceof Module && importDescription.name === '*') { return otherModule.namespace; } const [declaration] = getVariableForExportNameRecursive( otherModule, - importDeclaration.name, + importDescription.name, importerForSideEffects || this, isExportAllSearch, searchedNamesAndModules @@ -898,8 +899,8 @@ export default class Module { if (!declaration) { return this.error( - errorMissingExport(importDeclaration.name, this.id, otherModule.id), - importDeclaration.start + errorMissingExport(importDescription.name, this.id, otherModule.id), + importDescription.start ); } @@ -983,13 +984,13 @@ export default class Module { const source = node.source.value; this.addSource(source, node); - for (const specifier of node.specifiers) { - const name = specifier.exported.name; + for (const { exported, local, start } of node.specifiers) { + const name = exported instanceof Literal ? exported.value : exported.name; this.reexportDescriptions.set(name, { - localName: specifier.local.name, + localName: local instanceof Literal ? local.value : local.name, module: null as never, // filled in later, source, - start: specifier.start + start }); } } else if (node.declaration) { @@ -1012,9 +1013,10 @@ export default class Module { } else { // export { foo, bar, baz } - for (const specifier of node.specifiers) { - const localName = specifier.local.name; - const exportedName = specifier.exported.name; + for (const { local, exported } of node.specifiers) { + // except for reexports, local must be an Identifier + const localName = (local as Identifier).name; + const exportedName = exported instanceof Identifier ? exported.name : exported.value; this.exports.set(exportedName, { identifier: null, localName }); } } @@ -1024,10 +1026,14 @@ export default class Module { const source = node.source.value; this.addSource(source, node); for (const specifier of node.specifiers) { - const isDefault = specifier.type === NodeType.ImportDefaultSpecifier; - const isNamespace = specifier.type === NodeType.ImportNamespaceSpecifier; - - const name = isDefault ? 'default' : isNamespace ? '*' : specifier.imported.name; + const name = + specifier instanceof ImportDefaultSpecifier + ? 'default' + : specifier instanceof ImportNamespaceSpecifier + ? '*' + : specifier.imported instanceof Identifier + ? specifier.imported.name + : specifier.imported.value; this.importDescriptions.set(specifier.local.name, { module: null as never, // filled in later name, diff --git a/src/ast/nodes/ExportSpecifier.ts b/src/ast/nodes/ExportSpecifier.ts index 8c2d1086654..f4dc7a91f7a 100644 --- a/src/ast/nodes/ExportSpecifier.ts +++ b/src/ast/nodes/ExportSpecifier.ts @@ -1,10 +1,11 @@ import type Identifier from './Identifier'; +import type Literal from './Literal'; import type * as NodeType from './NodeType'; import { NodeBase } from './shared/Node'; export default class ExportSpecifier extends NodeBase { - declare exported: Identifier; - declare local: Identifier; + declare exported: Identifier | Literal; + declare local: Identifier | Literal; declare type: NodeType.tExportSpecifier; protected applyDeoptimizations() {} diff --git a/src/ast/nodes/ImportSpecifier.ts b/src/ast/nodes/ImportSpecifier.ts index 723d3244172..d8b589dfcf1 100644 --- a/src/ast/nodes/ImportSpecifier.ts +++ b/src/ast/nodes/ImportSpecifier.ts @@ -1,9 +1,10 @@ import type Identifier from './Identifier'; +import type Literal from './Literal'; import type * as NodeType from './NodeType'; import { NodeBase } from './shared/Node'; export default class ImportSpecifier extends NodeBase { - declare imported: Identifier; + declare imported: Identifier | Literal; declare local: Identifier; declare type: NodeType.tImportSpecifier; diff --git a/test/function/samples/arbitrary-module-namespace-identifiers/_config.js b/test/function/samples/arbitrary-module-namespace-identifiers/_config.js new file mode 100644 index 00000000000..91e53ae26c7 --- /dev/null +++ b/test/function/samples/arbitrary-module-namespace-identifiers/_config.js @@ -0,0 +1,3 @@ +module.exports = { + description: 'supports arbitrary module namespace identifiers' +}; diff --git a/test/function/samples/arbitrary-module-namespace-identifiers/foo.js b/test/function/samples/arbitrary-module-namespace-identifiers/foo.js new file mode 100644 index 00000000000..c9bcef7506a --- /dev/null +++ b/test/function/samples/arbitrary-module-namespace-identifiers/foo.js @@ -0,0 +1,2 @@ +const foo = 42; +export { foo as ' 😆 ' }; diff --git a/test/function/samples/arbitrary-module-namespace-identifiers/main.js b/test/function/samples/arbitrary-module-namespace-identifiers/main.js new file mode 100644 index 00000000000..ed6192936f5 --- /dev/null +++ b/test/function/samples/arbitrary-module-namespace-identifiers/main.js @@ -0,0 +1,3 @@ +import { ' 🙄 ' as foo } from './reexport.js'; + +assert.strictEqual(foo, 42); diff --git a/test/function/samples/arbitrary-module-namespace-identifiers/reexport.js b/test/function/samples/arbitrary-module-namespace-identifiers/reexport.js new file mode 100644 index 00000000000..bbf38851b35 --- /dev/null +++ b/test/function/samples/arbitrary-module-namespace-identifiers/reexport.js @@ -0,0 +1 @@ +export { ' 😆 ' as ' 🙄 ' } from './foo.js';