Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Esprima/Esprima.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<NeutralLanguage>en-US</NeutralLanguage>
<BuildNumber Condition="'$(BuildNumber)' == ''">0</BuildNumber>
<Authors>Sebastien Ros</Authors>
<TargetFrameworks>net461;netstandard2.0</TargetFrameworks>
<TargetFrameworks>net461;netstandard2.0;net5.0</TargetFrameworks>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can now use net6.0 too

<AssemblyOriginatorKeyFile>../Esprima.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
<PackageId>Esprima</PackageId>
Expand Down
1 change: 1 addition & 0 deletions src/Esprima/JavascriptParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Esprima.Ast;
using Range = Esprima.Ast.Range;

namespace Esprima
{
Expand Down
118 changes: 118 additions & 0 deletions src/Esprima/Utils/AstJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#if NET5_0_OR_GREATER
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using Esprima.Ast;

namespace Esprima.Utils
{
public class AstJsonConverter : JsonConverter<object>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we keep this sealed until someone asks for it to be opened, generally I guess we should be able to reproduce the original JSON AST for this to be "feature-complete".

{
public override bool CanConvert(Type typeToConvert)
{
return typeof(Node).IsAssignableFrom(typeToConvert);
}

public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var propertyBag = new Dictionary<string, object>();
reader.Read();
while (true)
{
if (reader.TokenType != JsonTokenType.PropertyName && reader.TokenType != JsonTokenType.String)
{
break;
}

var name = reader.GetString();
reader.Read();

object value = null;
if (reader.TokenType == JsonTokenType.String)
{
value = reader.GetString();
reader.Read();
}
else if (reader.TokenType == JsonTokenType.Number)
{
value = reader.GetDouble();
reader.Read();
}
else if (reader.TokenType == JsonTokenType.True)
{
value = true;
reader.Read();
}
else if (reader.TokenType == JsonTokenType.False)
{
value = false;
reader.Read();
}
else if (reader.TokenType == JsonTokenType.Null)
{
value = null;
reader.Read();
}
else if (reader.TokenType == JsonTokenType.StartArray)
{
var values = new List<Node>();
reader.Read();
while (true)
{
if (reader.TokenType == JsonTokenType.EndArray)
break;
var v = (Node) JsonSerializer.Deserialize(ref reader, typeof(Node), options);
reader.Read();
values.Add(v);
}
reader.Read();
}
else if (reader.TokenType == JsonTokenType.StartObject)
{
value = JsonSerializer.Deserialize(ref reader, typeof(Node), options);
reader.Read();
}
else
{
reader.Read();
}
propertyBag.Add(name, value);
}

var type = (string)propertyBag["type"];
switch (type)
{
case "AssignmentExpression":
return new AssignmentExpression((string) propertyBag["op"], (Expression) propertyBag["left"], (Expression) propertyBag["right"]);
case "ArrayExpression":
return new ArrayExpression(NodeList.Create(((List<Node>) propertyBag["elements"]).Cast<Expression>()));
case "BlockStatement":
return new BlockStatement(NodeList.Create(((List<Node>) propertyBag["elements"]).Cast<Statement>()));
case "BinaryExpression":
return new BinaryExpression((string) propertyBag["op"], (Expression) propertyBag["left"], (Expression) propertyBag["right"]);
case "Identifier":
return new Identifier((string) propertyBag["name"]);
case "Literal":
{
var value = propertyBag["value"];
if (value is bool)
return new Literal((bool) value, (string) propertyBag["raw"]);
if (value is double)
return new Literal((double) value, (string) propertyBag["raw"]);
return new Literal((string) value, (string) propertyBag["raw"]);
}
}
return null;
}

public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
{
throw new NotImplementedException();
}


}
}
#endif
37 changes: 37 additions & 0 deletions test/Esprima.Tests/JsonTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#if NET5_0_OR_GREATER
using System.Text.Json;
using Esprima.Ast;
using Esprima.Utils;
using Xunit;

namespace Esprima.Tests
{
public class JsonTest
{
[Fact]
public void JsonToAstParserTest()
{
var parser = new JavaScriptParser(@"if (true) { p(); }
switch(foo) {
case 'A':
p();
break;
}
switch(foo) {
default:
p();
break;
}
for (var a = []; ; ) { }
for (var elem of list) { }
");
var program = parser.ParseScript();
var json = AstJson.ToJsonString(program);

var op = new JsonSerializerOptions();
op.Converters.Add(new AstJsonConverter());
var ast = JsonSerializer.Deserialize<Node>(json, op);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should the result be asserted? some acceptance criteria library probably could help here for text matching / diffing.

}
}
}
#endif