diff --git a/src/Esprima/Ast/ExportAllDeclaration.cs b/src/Esprima/Ast/ExportAllDeclaration.cs
index d09499f8..0ecb976e 100644
--- a/src/Esprima/Ast/ExportAllDeclaration.cs
+++ b/src/Esprima/Ast/ExportAllDeclaration.cs
@@ -5,13 +5,17 @@ namespace Esprima.Ast
public sealed class ExportAllDeclaration : ExportDeclaration
{
public readonly Literal Source;
- public readonly Identifier? Exported;
+
+ ///
+ /// Identifier | StringLiteral
+ ///
+ public readonly Expression? Exported;
public ExportAllDeclaration(Literal source) : this(source, null)
{
}
- public ExportAllDeclaration(Literal source, Identifier? exported) : base(Nodes.ExportAllDeclaration)
+ public ExportAllDeclaration(Literal source, Expression? exported) : base(Nodes.ExportAllDeclaration)
{
Source = source;
Exported = exported;
diff --git a/src/Esprima/Ast/ExportSpecifier.cs b/src/Esprima/Ast/ExportSpecifier.cs
index 01feeeca..a684a354 100644
--- a/src/Esprima/Ast/ExportSpecifier.cs
+++ b/src/Esprima/Ast/ExportSpecifier.cs
@@ -4,10 +4,17 @@ namespace Esprima.Ast
{
public sealed class ExportSpecifier : Statement
{
- public readonly Identifier Exported;
- public readonly Identifier Local;
+ ///
+ /// Identifier | StringLiteral
+ ///
+ public readonly Expression Exported;
- public ExportSpecifier(Identifier local, Identifier exported) : base(Nodes.ExportSpecifier)
+ ///
+ /// Identifier | StringLiteral
+ ///
+ public readonly Expression Local;
+
+ public ExportSpecifier(Expression local, Expression exported) : base(Nodes.ExportSpecifier)
{
Exported = exported;
Local = local;
diff --git a/src/Esprima/Ast/ImportDeclarationSpecifier.cs b/src/Esprima/Ast/ImportDeclarationSpecifier.cs
index 51820fae..1db2d068 100644
--- a/src/Esprima/Ast/ImportDeclarationSpecifier.cs
+++ b/src/Esprima/Ast/ImportDeclarationSpecifier.cs
@@ -2,11 +2,14 @@
{
public abstract class ImportDeclarationSpecifier : Declaration
{
- protected ImportDeclarationSpecifier(Nodes type) : base(type)
+ ///
+ /// Identifier | StringLiteral
+ ///
+ public readonly Expression Local;
+
+ protected ImportDeclarationSpecifier(Expression local, Nodes type) : base(type)
{
+ Local = local;
}
-
- public Identifier Local => LocalId;
- protected abstract Identifier LocalId { get; }
}
}
diff --git a/src/Esprima/Ast/ImportDefaultSpecifier.cs b/src/Esprima/Ast/ImportDefaultSpecifier.cs
index 7cf3e163..42694fa8 100644
--- a/src/Esprima/Ast/ImportDefaultSpecifier.cs
+++ b/src/Esprima/Ast/ImportDefaultSpecifier.cs
@@ -4,12 +4,8 @@ namespace Esprima.Ast
{
public sealed class ImportDefaultSpecifier : ImportDeclarationSpecifier
{
- public new readonly Identifier Local;
- protected override Identifier LocalId => Local;
-
- public ImportDefaultSpecifier(Identifier local) : base(Nodes.ImportDefaultSpecifier)
+ public ImportDefaultSpecifier(Identifier local) : base(local, Nodes.ImportDefaultSpecifier)
{
- Local = local;
}
public override NodeCollection ChildNodes => new(Local);
diff --git a/src/Esprima/Ast/ImportNamespaceSpecifier.cs b/src/Esprima/Ast/ImportNamespaceSpecifier.cs
index cd181f92..848edfad 100644
--- a/src/Esprima/Ast/ImportNamespaceSpecifier.cs
+++ b/src/Esprima/Ast/ImportNamespaceSpecifier.cs
@@ -4,12 +4,8 @@ namespace Esprima.Ast
{
public sealed class ImportNamespaceSpecifier : ImportDeclarationSpecifier
{
- public new readonly Identifier Local;
- protected override Identifier LocalId => Local;
-
- public ImportNamespaceSpecifier(Identifier local) : base(Nodes.ImportNamespaceSpecifier)
+ public ImportNamespaceSpecifier(Identifier local) : base(local, Nodes.ImportNamespaceSpecifier)
{
- Local = local;
}
public override NodeCollection ChildNodes => new(Local);
diff --git a/src/Esprima/Ast/ImportSpecifier.cs b/src/Esprima/Ast/ImportSpecifier.cs
index 9ea30047..f92356f1 100644
--- a/src/Esprima/Ast/ImportSpecifier.cs
+++ b/src/Esprima/Ast/ImportSpecifier.cs
@@ -4,14 +4,13 @@ namespace Esprima.Ast
{
public sealed class ImportSpecifier : ImportDeclarationSpecifier
{
- public new readonly Identifier Local;
- protected override Identifier LocalId => Local;
+ ///
+ /// Identifier | StringLiteral
+ ///
+ public readonly Expression Imported;
- public readonly Identifier Imported;
-
- public ImportSpecifier(Identifier local, Identifier imported) : base(Nodes.ImportSpecifier)
+ public ImportSpecifier(Expression local, Expression imported) : base(local, Nodes.ImportSpecifier)
{
- Local = local;
Imported = imported;
}
diff --git a/src/Esprima/JavascriptParser.cs b/src/Esprima/JavascriptParser.cs
index 52e274db..bf8d3346 100644
--- a/src/Esprima/JavascriptParser.cs
+++ b/src/Esprima/JavascriptParser.cs
@@ -4672,7 +4672,8 @@ private ImportSpecifier ParseImportSpecifier()
{
var node = CreateNode();
- Identifier local, imported;
+ Expression local;
+ Expression imported;
if (_lookahead.Type == TokenType.Identifier)
{
@@ -4686,7 +4687,10 @@ private ImportSpecifier ParseImportSpecifier()
}
else
{
- imported = ParseIdentifierName();
+ imported = this._lookahead.Type == TokenType.StringLiteral
+ ? ParseModuleSpecifier()
+ : ParseIdentifierName();
+
local = imported;
if (MatchContextualKeyword("as"))
{
@@ -4824,12 +4828,17 @@ private ExportSpecifier ParseExportSpecifier()
{
var node = CreateNode();
- var local = ParseIdentifierName();
+ Expression local = this._lookahead.Type == TokenType.StringLiteral
+ ? ParseModuleSpecifier()
+ : ParseIdentifierName();
+
var exported = local;
if (MatchContextualKeyword("as"))
{
NextToken();
- exported = ParseIdentifierName();
+ exported = this._lookahead.Type == TokenType.StringLiteral
+ ? ParseModuleSpecifier()
+ : ParseIdentifierName();
}
return Finalize(node, new ExportSpecifier(local, exported));
@@ -4898,11 +4907,13 @@ private ExportDeclaration ParseExportDeclaration()
NextToken();
//export * as ns from 'foo'
- Identifier? exported = null;
+ Expression? exported = null;
if (MatchContextualKeyword("as"))
{
NextToken();
- exported = ParseIdentifierName();
+ exported = this._lookahead.Type == TokenType.StringLiteral
+ ? ParseModuleSpecifier()
+ : ParseIdentifierName();
}
if (!MatchContextualKeyword("from"))
diff --git a/test/Esprima.Tests/ParserTests.cs b/test/Esprima.Tests/ParserTests.cs
index 083595d9..25dd283e 100644
--- a/test/Esprima.Tests/ParserTests.cs
+++ b/test/Esprima.Tests/ParserTests.cs
@@ -104,6 +104,16 @@ public void ShouldParseNumericLiterals(object expected, string source)
Assert.Equal(expected, literal.NumericValue);
}
+ [Theory]
+ [InlineData("export { Mercury as \"☿\" } from \"./export-expname_FIXTURE.js\";")]
+ [InlineData("export * as \"All\" from \"./export-expname_FIXTURE.js\";")]
+ [InlineData("export { \"☿\" as Ami } from \"./export-expname_FIXTURE.js\"")]
+ [InlineData("import { \"☿\" as Ami } from \"./export-expname_FIXTURE.js\";")]
+ public void ShouldParseModuleImportExportWithStringIdentifiers(string source)
+ {
+ new JavaScriptParser(source).ParseModule();
+ }
+
[Fact]
public void ShouldParseClassInheritance()
{