Skip to content

Commit

Permalink
[dotnet] Move devtools generator to System.Text.Json, update to .NE…
Browse files Browse the repository at this point in the history
…T 8 (#15061)
  • Loading branch information
RenderMichael authored Jan 12, 2025
1 parent 040b9ba commit 6da3095
Show file tree
Hide file tree
Showing 16 changed files with 122 additions and 126 deletions.
4 changes: 2 additions & 2 deletions third_party/dotnet/devtools/src/generator/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ load("//dotnet:defs.bzl", "csharp_binary", "framework")
csharp_binary(
name = "generator",
srcs = glob(["**/*.cs"]),
nullable = "annotations",
# Used as a tool in our build, so just target one framework
target_frameworks = ["net7.0"],
target_frameworks = ["net8.0"],
visibility = [
"//dotnet:__subpackages__",
],
Expand All @@ -14,6 +15,5 @@ csharp_binary(
framework("nuget", "Humanizer.Core"),
framework("nuget", "Microsoft.Extensions.DependencyInjection"),
framework("nuget", "Microsoft.Extensions.DependencyInjection.Abstractions"),
framework("nuget", "Newtonsoft.Json"),
],
)
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace OpenQA.Selenium.DevToolsGenerator.CodeGen
{
using Newtonsoft.Json;
using System.Text.Json.Serialization;

/// <summary>
/// Represents settings around Definition templates.
Expand Down Expand Up @@ -47,22 +47,22 @@ public CodeGenerationDefinitionTemplateSettings()
};
}

[JsonProperty("domainTemplate")]
[JsonPropertyName("domainTemplate")]
public CodeGenerationTemplateSettings DomainTemplate { get; set; }

[JsonProperty("commandTemplate")]
[JsonPropertyName("commandTemplate")]
public CodeGenerationTemplateSettings CommandTemplate { get; set; }

[JsonProperty("eventTemplate")]
[JsonPropertyName("eventTemplate")]
public CodeGenerationTemplateSettings EventTemplate { get; set; }

[JsonProperty("typeObjectTemplate")]
[JsonPropertyName("typeObjectTemplate")]
public CodeGenerationTemplateSettings TypeObjectTemplate { get; set; }

[JsonProperty("typeHashTemplate")]
[JsonPropertyName("typeHashTemplate")]
public CodeGenerationTemplateSettings TypeHashTemplate { get; set; }

[JsonProperty("typeEnumTemplate")]
[JsonPropertyName("typeEnumTemplate")]
public CodeGenerationTemplateSettings TypeEnumTemplate { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace OpenQA.Selenium.DevToolsGenerator.CodeGen
{
using Newtonsoft.Json;
using System.Text.Json.Serialization;
using System.Collections.Generic;

/// <summary>
Expand All @@ -26,43 +26,43 @@ public CodeGenerationSettings()
/// <summary>
/// Collection of templates that will be parsed and output in the target folder.
/// </summary>
[JsonProperty("include")]
[JsonPropertyName("include")]
public ICollection<CodeGenerationTemplateSettings> Include { get; set; }

/// <summary>
/// Indicates whether or not domains marked as depreciated will be generated. (Default: true)
/// </summary>
[JsonProperty("includeDeprecatedDomains")]
[JsonPropertyName("includeDeprecatedDomains")]
public bool IncludeDeprecatedDomains { get; set; }

/// <summary>
/// Indicates whether or not domains marked as depreciated will be generated. (Default: true)
/// </summary>
[JsonProperty("includeExperimentalDomains")]
[JsonPropertyName("includeExperimentalDomains")]
public bool IncludeExperimentalDomains { get; set; }

/// <summary>
/// Gets or sets the root namespace of generated classes.
/// </summary>
[JsonProperty("rootNamespace")]
[JsonPropertyName("rootNamespace")]
public string RootNamespace { get; set; }

/// <summary>
/// Gets the version number of the runtime.
/// </summary>
[JsonProperty("runtimeVersion")]
[JsonPropertyName("runtimeVersion")]
public string RuntimeVersion { get; set; }

[JsonProperty("definitionTemplates")]
[JsonPropertyName("definitionTemplates")]
public CodeGenerationDefinitionTemplateSettings DefinitionTemplates { get; set; }

[JsonProperty("templatesPath")]
[JsonPropertyName("templatesPath")]
public string TemplatesPath { get; set; }

/// <summary>
/// The using statements that will be included on each generated file.
/// </summary>
[JsonProperty("usingStatements")]
[JsonPropertyName("usingStatements")]
public ICollection<string> UsingStatements { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
namespace OpenQA.Selenium.DevToolsGenerator.CodeGen
{
using Newtonsoft.Json;
using System.Text.Json.Serialization;

/// <summary>
/// Defines settings around templates
/// </summary>
public class CodeGenerationTemplateSettings
{
[JsonProperty("templatePath")]
[JsonPropertyName("templatePath")]
public string TemplatePath { get; set; }

[JsonProperty("outputPath")]
[JsonPropertyName("outputPath")]
public string OutputPath { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,68 +1,59 @@
namespace OpenQA.Selenium.DevToolsGenerator.Converters
{
using Newtonsoft.Json;
using System;
using System.Text.Json;
using System.Text.Json.Serialization;

/// <summary>
/// Handles converting JSON string values into a C# boolean data type.
/// </summary>
public class BooleanJsonConverter : JsonConverter
public class BooleanJsonConverter : JsonConverter<bool>
{
/// <summary>
/// Determines whether this instance can convert the specified object type.
/// </summary>
/// <param name="objectType">Type of the object.</param>
/// <returns>
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
/// </returns>
public override bool CanConvert(Type objectType)
{
// Handle only boolean types.
return objectType == typeof(bool);
}
public override bool HandleNull => false;

/// <summary>
/// Reads the JSON representation of the object.
/// </summary>
/// <param name="reader">The <see cref="T:Newtonsoft.Json.JsonReader"/> to read from.</param>
/// <param name="objectType">Type of the object.</param>
/// <param name="existingValue">The existing value of object being read.</param>
/// <param name="serializer">The calling serializer.</param>
/// <returns>
/// The object value.
/// </returns>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
switch (reader.Value.ToString().ToLower().Trim())
switch (reader.TokenType)
{
case "true":
case "yes":
case "y":
case "1":
case JsonTokenType.True:
return true;
case "false":
case "no":
case "n":
case "0":

case JsonTokenType.False:
return false;
}

// If we reach here, we're pretty much going to throw an error so let's let Json.NET throw it's pretty-fied error message.
return new JsonSerializer().Deserialize(reader, objectType);
}
case JsonTokenType.String:
string boolString = reader.GetString()!;
if (bool.TryParse(boolString, out bool b))
{
return b;
}

boolString = boolString.ToLowerInvariant();

/// <summary>
/// Specifies that this converter will not participate in writing results.
/// </summary>
public override bool CanWrite => false;
if (boolString.AsSpan().Trim().SequenceEqual("yes".AsSpan()) ||
boolString.AsSpan().Trim().SequenceEqual("y".AsSpan()) ||
boolString.AsSpan().Trim().SequenceEqual("1".AsSpan()))
{
return true;
}

if (boolString.AsSpan().Trim().SequenceEqual("no".AsSpan()) ||
boolString.AsSpan().Trim().SequenceEqual("n".AsSpan()) ||
boolString.AsSpan().Trim().SequenceEqual("0".AsSpan()))
{
return false;
}

throw new JsonException();

default:
throw new JsonException();
}
}

/// <summary>
/// Writes the JSON representation of the object.
/// </summary>
/// <param name="writer">The <see cref="T:Newtonsoft.Json.JsonWriter"/> to write to.</param><param name="value">The value.</param><param name="serializer">The calling serializer.</param>
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
public override void Write(Utf8JsonWriter writer, bool value, JsonSerializerOptions options)
{
throw new NotSupportedException();
writer.WriteBooleanValue(value);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net60</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>OpenQA.Selenium.DevToolsGenerator</RootNamespace>
<Nullable>annotations</Nullable>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
Expand All @@ -19,7 +20,6 @@
<PackageReference Include="Handlebars.Net" Version="1.11.5" />
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.32" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>

</Project>
29 changes: 15 additions & 14 deletions third_party/dotnet/devtools/src/generator/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
using System.Text;
using CommandLine;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Text.Json.Serialization;
using OpenQA.Selenium.DevToolsGenerator.CodeGen;
using OpenQA.Selenium.DevToolsGenerator.ProtocolDefinition;
using System.Text.Json;
using System.Text.Json.Nodes;

namespace OpenQA.Selenium.DevToolsGenerator
{
Expand All @@ -24,7 +25,7 @@ static int Main(string[] args)
}

var settingsJson = File.ReadAllText(cliArguments.Settings);
var settings = JsonConvert.DeserializeObject<CodeGenerationSettings>(settingsJson);
var settings = JsonSerializer.Deserialize<CodeGenerationSettings>(settingsJson);
if (!string.IsNullOrEmpty(cliArguments.TemplatesPath))
{
settings.TemplatesPath = cliArguments.TemplatesPath;
Expand All @@ -48,7 +49,7 @@ static int Main(string[] args)

var protocolDefinitionData = GetProtocolDefinitionData(cliArguments);

var protocolDefinition = protocolDefinitionData.ToObject<ProtocolDefinition.ProtocolDefinition>(new JsonSerializer() { MetadataPropertyHandling = MetadataPropertyHandling.Ignore });
var protocolDefinition = protocolDefinitionData.Deserialize<ProtocolDefinition.ProtocolDefinition>(new JsonSerializerOptions() { ReferenceHandler = ReferenceHandler.IgnoreCycles });

//Begin the code generation process.
if (!cliArguments.Quiet)
Expand Down Expand Up @@ -113,9 +114,9 @@ static int Main(string[] args)
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
public static JObject GetProtocolDefinitionData(CommandLineOptions args)
public static JsonObject GetProtocolDefinitionData(CommandLineOptions args)
{
JObject protocolData;
JsonObject protocolData;
string browserProtocolPath = args.BrowserProtocolPath;
if (!File.Exists(browserProtocolPath))
{
Expand All @@ -134,15 +135,15 @@ public static JObject GetProtocolDefinitionData(CommandLineOptions args)
}
}

JObject browserProtocol = JObject.Parse(File.ReadAllText(browserProtocolPath));
JObject jsProtocol = JObject.Parse(File.ReadAllText(jsProtocolPath));
JsonObject browserProtocol = JsonNode.Parse(File.ReadAllText(browserProtocolPath)).AsObject();
JsonObject jsProtocol = JsonNode.Parse(File.ReadAllText(jsProtocolPath)).AsObject();

ProtocolVersionDefinition currentVersion = new ProtocolVersionDefinition();
currentVersion.ProtocolVersion = "1.3";
currentVersion.Browser = "Chrome/86.0";

protocolData = MergeJavaScriptProtocolDefinitions(browserProtocol, jsProtocol);
protocolData["browserVersion"] = JToken.FromObject(currentVersion);
protocolData["browserVersion"] = JsonSerializer.SerializeToNode(currentVersion);

return protocolData;
}
Expand All @@ -153,7 +154,7 @@ public static JObject GetProtocolDefinitionData(CommandLineOptions args)
/// <param name="browserProtocol"></param>
/// <param name="jsProtocol"></param>
/// <returns></returns>
public static JObject MergeJavaScriptProtocolDefinitions(JObject browserProtocol, JObject jsProtocol)
public static JsonObject MergeJavaScriptProtocolDefinitions(JsonObject? browserProtocol, JsonObject? jsProtocol)
{
//Merge the 2 protocols together.
if (jsProtocol["version"]["majorVersion"] != browserProtocol["version"]["majorVersion"] ||
Expand All @@ -162,11 +163,11 @@ public static JObject MergeJavaScriptProtocolDefinitions(JObject browserProtocol
throw new InvalidOperationException("Protocol mismatch -- The WebKit and V8 protocol versions should match.");
}

var result = browserProtocol.DeepClone() as JObject;
foreach (var domain in jsProtocol["domains"])
var result = browserProtocol.DeepClone().AsObject();
foreach (var domain in jsProtocol["domains"].AsArray())
{
JArray jDomains = (JArray)result["domains"];
jDomains.Add(domain);
JsonArray jDomains = result["domains"].AsArray();
jDomains.Add(domain.DeepClone());
}

return result;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace OpenQA.Selenium.DevToolsGenerator.ProtocolDefinition
{
using Newtonsoft.Json;
using System.Text.Json.Serialization;
using System.Collections.Generic;
using System.Collections.ObjectModel;

Expand All @@ -14,16 +14,16 @@ public CommandDefinition()
Returns = new Collection<TypeDefinition>();
}

[JsonProperty(PropertyName = "handlers")]
[JsonPropertyName("handlers")]
public ICollection<string> Handlers { get; set; }

[JsonProperty(PropertyName = "parameters")]
[JsonPropertyName("parameters")]
public ICollection<TypeDefinition> Parameters { get; set; }

[JsonProperty(PropertyName = "returns")]
[JsonPropertyName("returns")]
public ICollection<TypeDefinition> Returns { get; set; }

[JsonProperty(PropertyName = "redirect")]
[JsonPropertyName("redirect")]
public string Redirect { get; set; }

[JsonIgnore]
Expand Down
Loading

0 comments on commit 6da3095

Please sign in to comment.