From 7ca8847a9d38d8b558afda4831fb010e93393c3d Mon Sep 17 00:00:00 2001 From: Andrii Rublov Date: Sun, 7 Jul 2024 12:50:51 +0200 Subject: [PATCH 1/5] [codegen]: Fix #7: Code generation problem with `object` and `array` type definitions without properties --- src/ChromeProtocol.Domains/Generated/DOM.cs | 2 +- .../Generated/DOMSnapshot.cs | 4 +- .../Generated/DOMStorage.cs | 2 +- .../Generated/LayerTree.cs | 2 +- .../Generated/Network.cs | 2 +- .../Generated/Target.cs | 2 +- .../Generated/Tracing.cs | 2 +- .../Pipeline/Steps/GenerateCsharpStep.cs | 45 ++++++++++++------- 8 files changed, 38 insertions(+), 23 deletions(-) diff --git a/src/ChromeProtocol.Domains/Generated/DOM.cs b/src/ChromeProtocol.Domains/Generated/DOM.cs index d61f115..cd69b9a 100644 --- a/src/ChromeProtocol.Domains/Generated/DOM.cs +++ b/src/ChromeProtocol.Domains/Generated/DOM.cs @@ -215,7 +215,7 @@ public record RGBAType( { } /// An array of quad vertices, x immediately followed by y for each point, points clock-wise. - public record QuadType() : ChromeProtocol.Core.IType + public class QuadType : Newtonsoft.Json.Linq.JArray, ChromeProtocol.Core.IType { } /// Box model. diff --git a/src/ChromeProtocol.Domains/Generated/DOMSnapshot.cs b/src/ChromeProtocol.Domains/Generated/DOMSnapshot.cs index 57f45a0..b4a9009 100644 --- a/src/ChromeProtocol.Domains/Generated/DOMSnapshot.cs +++ b/src/ChromeProtocol.Domains/Generated/DOMSnapshot.cs @@ -190,7 +190,7 @@ int Value { } /// Index of the string in the strings table. - public record ArrayOfStringsType() : ChromeProtocol.Core.IType + public class ArrayOfStringsType : Newtonsoft.Json.Linq.JArray, ChromeProtocol.Core.IType { } /// Data that is only present on rare nodes. @@ -216,7 +216,7 @@ System.Collections.Generic.IReadOnlyList Value ) : ChromeProtocol.Core.IType { } - public record RectangleType() : ChromeProtocol.Core.IType + public class RectangleType : Newtonsoft.Json.Linq.JArray, ChromeProtocol.Core.IType { } /// Document snapshot. diff --git a/src/ChromeProtocol.Domains/Generated/DOMStorage.cs b/src/ChromeProtocol.Domains/Generated/DOMStorage.cs index 07da9d3..44f7728 100644 --- a/src/ChromeProtocol.Domains/Generated/DOMStorage.cs +++ b/src/ChromeProtocol.Domains/Generated/DOMStorage.cs @@ -27,7 +27,7 @@ public record StorageIdType( { } /// DOM Storage item. - public record ItemType() : ChromeProtocol.Core.IType + public class ItemType : Newtonsoft.Json.Linq.JArray, ChromeProtocol.Core.IType { } [ChromeProtocol.Core.MethodName("DOMStorage.domStorageItemAdded")] diff --git a/src/ChromeProtocol.Domains/Generated/LayerTree.cs b/src/ChromeProtocol.Domains/Generated/LayerTree.cs index 9f6a49d..b040075 100644 --- a/src/ChromeProtocol.Domains/Generated/LayerTree.cs +++ b/src/ChromeProtocol.Domains/Generated/LayerTree.cs @@ -118,7 +118,7 @@ public record LayerType( { } /// Array of timings, one per paint step. - public record PaintProfileType() : ChromeProtocol.Core.IType + public class PaintProfileType : Newtonsoft.Json.Linq.JArray, ChromeProtocol.Core.IType { } /// The id of the painted layer. diff --git a/src/ChromeProtocol.Domains/Generated/Network.cs b/src/ChromeProtocol.Domains/Generated/Network.cs index 5deabd5..4ab1dfb 100644 --- a/src/ChromeProtocol.Domains/Generated/Network.cs +++ b/src/ChromeProtocol.Domains/Generated/Network.cs @@ -59,7 +59,7 @@ double Value { } /// Request / response headers as keys / values of JSON object. - public record HeadersType() : ChromeProtocol.Core.IType + public class HeadersType : Newtonsoft.Json.Linq.JObject, ChromeProtocol.Core.IType { } /// The underlying connection technology that the browser is supposedly using. diff --git a/src/ChromeProtocol.Domains/Generated/Target.cs b/src/ChromeProtocol.Domains/Generated/Target.cs index fff9c32..b47b877 100644 --- a/src/ChromeProtocol.Domains/Generated/Target.cs +++ b/src/ChromeProtocol.Domains/Generated/Target.cs @@ -71,7 +71,7 @@ public record FilterEntryType( /// [{type: "browser", exclude: true}, {type: "tab", exclude: true}, {}]
/// (i.e. include everything but `browser` and `tab`).
/// - public record TargetFilterType() : ChromeProtocol.Core.IType + public class TargetFilterType : Newtonsoft.Json.Linq.JArray, ChromeProtocol.Core.IType { } public record RemoteLocationType( diff --git a/src/ChromeProtocol.Domains/Generated/Tracing.cs b/src/ChromeProtocol.Domains/Generated/Tracing.cs index 9f4f87b..ce7a2c0 100644 --- a/src/ChromeProtocol.Domains/Generated/Tracing.cs +++ b/src/ChromeProtocol.Domains/Generated/Tracing.cs @@ -6,7 +6,7 @@ namespace ChromeProtocol.Domains public static partial class Tracing { /// Configuration for memory dump. Used only when "memory-infra" category is enabled. - public record MemoryDumpConfigType() : ChromeProtocol.Core.IType + public class MemoryDumpConfigType : Newtonsoft.Json.Linq.JObject, ChromeProtocol.Core.IType { } /// Controls how the trace buffer stores data. diff --git a/src/ChromeProtocol.Tools/CodeGeneration/Pipeline/Steps/GenerateCsharpStep.cs b/src/ChromeProtocol.Tools/CodeGeneration/Pipeline/Steps/GenerateCsharpStep.cs index 10c8b6b..6ea9acb 100644 --- a/src/ChromeProtocol.Tools/CodeGeneration/Pipeline/Steps/GenerateCsharpStep.cs +++ b/src/ChromeProtocol.Tools/CodeGeneration/Pipeline/Steps/GenerateCsharpStep.cs @@ -8,6 +8,7 @@ using ChromeProtocol.Tools.Extensions; using ChromeProtocol.Tools.Schema.Models; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace ChromeProtocol.Tools.CodeGeneration.Pipeline.Steps; @@ -57,7 +58,7 @@ private static CsharpNamespaceDeclBuilder GenerateDomain(ValidatedDomain domain, private static CsharpClassDeclBuilder GenerateType(ValidatedType type, ValidatedDomain domain, string @namespace, CsharpClassDeclBuilder classBuilder) { - return type switch + switch (type) { // { Kind: TypeKind.Object } => // classBuilder.Record(CsharpNameResolver.Resolve(type.Id, ItemKind.TypeName, classBuilder.Node.Name), @@ -71,8 +72,8 @@ private static CsharpClassDeclBuilder GenerateType(ValidatedType type, Validated // XmlDocumentationDecorator.AddXmlDocs(_, type, propName => // CsharpNameResolver.Resolve(propName, ItemKind.PropertyName, recordBuilder.Node.Name)))), // { Kind: TypeKind.String, Enum: not null } => throw new NotImplementedException(), - { Kind: not TypeKind.Object and not TypeKind.Array } => - classBuilder.Record(CsharpNameResolver.Resolve(type.Id, ItemKind.TypeName, classBuilder.Node.Name), + case { Kind: not TypeKind.Object and not TypeKind.Array }: + return classBuilder.Record(CsharpNameResolver.Resolve(type.Id, ItemKind.TypeName, classBuilder.Node.Name), recordBuilder => { var valueType = CsharpTypeResolver.Resolve(@namespace, domain.Name, null, type.Kind, null, false); @@ -82,22 +83,36 @@ private static CsharpClassDeclBuilder GenerateType(ValidatedType type, Validated .Modifiers("public") .ApplyIf(type.Deprecated, _ => MarkDeprecated(_, "type")) .Parameters(paramsBuilder => paramsBuilder.Parameter("Value", valueType)) - .Inherit(CsharpTypeInfo.FromGenericType("ChromeProtocol.Core", "PrimitiveType", valueType), p => p.Argument("Value")) - .Apply(_ => - XmlDocumentationDecorator.AddXmlDocs(_, type, _ => throw new UnreachableException())); - }), - _ => - classBuilder.Record(CsharpNameResolver.Resolve(type.Id, ItemKind.TypeName, classBuilder.Node.Name), - recordBuilder => recordBuilder - .Modifiers("public") + .Inherit(CsharpTypeInfo.FromGenericType("ChromeProtocol.Core", "PrimitiveType", valueType), + p => p.Argument("Value")) + .Apply(_ => XmlDocumentationDecorator.AddXmlDocs(_, type, _ => throw new UnreachableException())); + }); + case { Kind: TypeKind.Object, Properties.Length: 0 }: + return classBuilder.Class(CsharpNameResolver.Resolve(type.Id, ItemKind.TypeName, classBuilder.Node.Name), + recordBuilder => recordBuilder.Modifiers("public") + .ApplyIf(type.Deprecated, _ => MarkDeprecated(_, "type")) + .Inherit(CsharpTypeInfo.FromTypeName("Newtonsoft.Json.Linq", nameof(JObject))) + .Inherit(CsharpTypeInfo.FromTypeName("ChromeProtocol.Core", nameof(IType))) + .Apply(_ => XmlDocumentationDecorator.AddXmlDocs(_, type, + propName => CsharpNameResolver.Resolve(propName, ItemKind.PropertyName, recordBuilder.Node.Name)))); + case { Kind: TypeKind.Array }: + return classBuilder.Class(CsharpNameResolver.Resolve(type.Id, ItemKind.TypeName, classBuilder.Node.Name), + recordBuilder => recordBuilder.Modifiers("public") + .ApplyIf(type.Deprecated, _ => MarkDeprecated(_, "type")) + .Inherit(CsharpTypeInfo.FromTypeName("Newtonsoft.Json.Linq", nameof(JArray))) + .Inherit(CsharpTypeInfo.FromTypeName("ChromeProtocol.Core", nameof(IType))) + .Apply(_ => XmlDocumentationDecorator.AddXmlDocs(_, type, + propName => CsharpNameResolver.Resolve(propName, ItemKind.PropertyName, recordBuilder.Node.Name)))); + default: + return classBuilder.Record(CsharpNameResolver.Resolve(type.Id, ItemKind.TypeName, classBuilder.Node.Name), + recordBuilder => recordBuilder.Modifiers("public") .ApplyIf(type.Deprecated, _ => MarkDeprecated(_, "type")) .Parameters(paramsBuilder => GenerateParameters(paramsBuilder, type.Properties, domain, @namespace, recordBuilder.Node.Name)) .Inherit(CsharpTypeInfo.FromTypeName("ChromeProtocol.Core", nameof(IType))) - .Apply(_ => - XmlDocumentationDecorator.AddXmlDocs(_, type, propName => - CsharpNameResolver.Resolve(propName, ItemKind.PropertyName, recordBuilder.Node.Name)))), - }; + .Apply(_ => XmlDocumentationDecorator.AddXmlDocs(_, type, + propName => CsharpNameResolver.Resolve(propName, ItemKind.PropertyName, recordBuilder.Node.Name)))); + } } private static CsharpClassDeclBuilder GenerateEvent(ValidatedEvent @event, ValidatedDomain domain, string @namespace, CsharpClassDeclBuilder classBuilder) => From d8a32ff48750539ee128d7309e689c2844aebde0 Mon Sep 17 00:00:00 2001 From: Andrii Rublov Date: Sun, 7 Jul 2024 12:51:17 +0200 Subject: [PATCH 2/5] Prepare 1.3.0 release --- CHANGELOG.md | 9 ++++++++- src/Directory.Build.props | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9da40d0..d891455 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.3.0] + +### Fixed + +- Fix code generation problem with `object` and `array` type definitions without properties (#7) + ## [1.2.3] ### Fixed @@ -52,7 +58,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Initial release -[Unreleased]: https://github.com/seclerp/dotnet-chrome-protocol/compare/1.2.3...HEAD +[Unreleased]: https://github.com/seclerp/dotnet-chrome-protocol/compare/1.3.0...HEAD +[1.3.0]: https://github.com/seclerp/dotnet-chrome-protocol/compare/1.2.3...1.3.0 [1.2.3]: https://github.com/seclerp/dotnet-chrome-protocol/compare/1.2.2...1.2.3 [1.2.2]: https://github.com/seclerp/dotnet-chrome-protocol/compare/1.2.1...1.2.2 [1.2.1]: https://github.com/seclerp/dotnet-chrome-protocol/compare/1.2.0...1.2.1 diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 8e36339..7a6a001 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,7 +1,7 @@ - 1.2.3 + 1.3.0 seclerp https://github.com/seclerp/dotnet-chrome-protocol MIT From 38b51e60934b41d8fb4e11921551ee0cbc98b384 Mon Sep 17 00:00:00 2001 From: Andrii Rublov Date: Sun, 7 Jul 2024 16:31:43 +0200 Subject: [PATCH 3/5] [codegen]: Fix deserializing into JObject inheritor, introduce weakly-typed object and array abstractions --- CHANGELOG.md | 4 +++ src/ChromeProtocol.Core/ArrayTypeConverter.cs | 29 +++++++++++++++++++ src/ChromeProtocol.Core/IArrayType.cs | 8 +++++ src/ChromeProtocol.Core/IObjectType.cs | 8 +++++ src/ChromeProtocol.Core/IType.cs | 2 -- .../ObjectTypeConverter.cs | 29 +++++++++++++++++++ src/ChromeProtocol.Domains/Generated/DOM.cs | 5 +++- .../Generated/DOMSnapshot.cs | 10 +++++-- .../Generated/DOMStorage.cs | 5 +++- .../Generated/LayerTree.cs | 5 +++- .../Generated/Network.cs | 5 +++- .../Generated/Target.cs | 5 +++- .../Generated/Tracing.cs | 5 +++- .../Pipeline/Steps/GenerateCsharpStep.cs | 24 +++++++++++---- 14 files changed, 128 insertions(+), 16 deletions(-) create mode 100644 src/ChromeProtocol.Core/ArrayTypeConverter.cs create mode 100644 src/ChromeProtocol.Core/IArrayType.cs create mode 100644 src/ChromeProtocol.Core/IObjectType.cs create mode 100644 src/ChromeProtocol.Core/ObjectTypeConverter.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index d891455..b9e6c6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.3.0] +### Added + +- New interfaces to represent weakly-typed arrays and objects - `IObjectType` and `IArrayType` with corresponding JSON converters + ### Fixed - Fix code generation problem with `object` and `array` type definitions without properties (#7) diff --git a/src/ChromeProtocol.Core/ArrayTypeConverter.cs b/src/ChromeProtocol.Core/ArrayTypeConverter.cs new file mode 100644 index 0000000..68aee31 --- /dev/null +++ b/src/ChromeProtocol.Core/ArrayTypeConverter.cs @@ -0,0 +1,29 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace ChromeProtocol.Core; + +public class ArrayTypeConverter : JsonConverter +{ + public override bool CanConvert(Type objectType) + { + return typeof(IArrayType).IsAssignableFrom(objectType); + } + + public override void WriteJson(JsonWriter writer, object? instance, JsonSerializer serializer) + { + var type = instance?.GetType(); + var properties = type.GetProperty(nameof(IArrayType.Items)).GetValue(instance) as IList; + var jArray = new JArray(properties); + + jArray.WriteTo(writer); + } + + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) + { + var jArray = JArray.Load(reader); + var instance = existingValue ?? Activator.CreateInstance(objectType, jArray); + + return instance; + } +} diff --git a/src/ChromeProtocol.Core/IArrayType.cs b/src/ChromeProtocol.Core/IArrayType.cs new file mode 100644 index 0000000..e6ccb7f --- /dev/null +++ b/src/ChromeProtocol.Core/IArrayType.cs @@ -0,0 +1,8 @@ +using Newtonsoft.Json.Linq; + +namespace ChromeProtocol.Core; + +public interface IArrayType +{ + public IReadOnlyCollection Items { get; } +} diff --git a/src/ChromeProtocol.Core/IObjectType.cs b/src/ChromeProtocol.Core/IObjectType.cs new file mode 100644 index 0000000..f1cb017 --- /dev/null +++ b/src/ChromeProtocol.Core/IObjectType.cs @@ -0,0 +1,8 @@ +using Newtonsoft.Json.Linq; + +namespace ChromeProtocol.Core; + +public interface IObjectType +{ + public IReadOnlyDictionary Properties { get; } +} diff --git a/src/ChromeProtocol.Core/IType.cs b/src/ChromeProtocol.Core/IType.cs index 021b41d..fb0fc8c 100644 --- a/src/ChromeProtocol.Core/IType.cs +++ b/src/ChromeProtocol.Core/IType.cs @@ -3,5 +3,3 @@ public interface IType { } - -public record ExampleValue(string Value) : PrimitiveType(Value); diff --git a/src/ChromeProtocol.Core/ObjectTypeConverter.cs b/src/ChromeProtocol.Core/ObjectTypeConverter.cs new file mode 100644 index 0000000..30cafa7 --- /dev/null +++ b/src/ChromeProtocol.Core/ObjectTypeConverter.cs @@ -0,0 +1,29 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace ChromeProtocol.Core; + +public class ObjectTypeConverter : JsonConverter +{ + public override bool CanConvert(Type objectType) + { + return typeof(IObjectType).IsAssignableFrom(objectType); + } + + public override void WriteJson(JsonWriter writer, object? instance, JsonSerializer serializer) + { + var type = instance?.GetType(); + var properties = type.GetProperty(nameof(IObjectType.Properties)).GetValue(instance) as IDictionary; + var jObject = new JObject(properties); + + jObject.WriteTo(writer); + } + + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) + { + var jObject = JObject.Load(reader); + var instance = existingValue ?? Activator.CreateInstance(objectType, jObject); + + return instance; + } +} diff --git a/src/ChromeProtocol.Domains/Generated/DOM.cs b/src/ChromeProtocol.Domains/Generated/DOM.cs index cd69b9a..a73759f 100644 --- a/src/ChromeProtocol.Domains/Generated/DOM.cs +++ b/src/ChromeProtocol.Domains/Generated/DOM.cs @@ -215,7 +215,10 @@ public record RGBAType( { } /// An array of quad vertices, x immediately followed by y for each point, points clock-wise. - public class QuadType : Newtonsoft.Json.Linq.JArray, ChromeProtocol.Core.IType + [Newtonsoft.Json.JsonConverter(typeof(ChromeProtocol.Core.ArrayTypeConverter))] + public record QuadType( + System.Collections.Generic.IReadOnlyCollection Items + ) : ChromeProtocol.Core.IArrayType { } /// Box model. diff --git a/src/ChromeProtocol.Domains/Generated/DOMSnapshot.cs b/src/ChromeProtocol.Domains/Generated/DOMSnapshot.cs index b4a9009..885c2bd 100644 --- a/src/ChromeProtocol.Domains/Generated/DOMSnapshot.cs +++ b/src/ChromeProtocol.Domains/Generated/DOMSnapshot.cs @@ -190,7 +190,10 @@ int Value { } /// Index of the string in the strings table. - public class ArrayOfStringsType : Newtonsoft.Json.Linq.JArray, ChromeProtocol.Core.IType + [Newtonsoft.Json.JsonConverter(typeof(ChromeProtocol.Core.ArrayTypeConverter))] + public record ArrayOfStringsType( + System.Collections.Generic.IReadOnlyCollection Items + ) : ChromeProtocol.Core.IArrayType { } /// Data that is only present on rare nodes. @@ -216,7 +219,10 @@ System.Collections.Generic.IReadOnlyList Value ) : ChromeProtocol.Core.IType { } - public class RectangleType : Newtonsoft.Json.Linq.JArray, ChromeProtocol.Core.IType + [Newtonsoft.Json.JsonConverter(typeof(ChromeProtocol.Core.ArrayTypeConverter))] + public record RectangleType( + System.Collections.Generic.IReadOnlyCollection Items + ) : ChromeProtocol.Core.IArrayType { } /// Document snapshot. diff --git a/src/ChromeProtocol.Domains/Generated/DOMStorage.cs b/src/ChromeProtocol.Domains/Generated/DOMStorage.cs index 44f7728..ecfecf3 100644 --- a/src/ChromeProtocol.Domains/Generated/DOMStorage.cs +++ b/src/ChromeProtocol.Domains/Generated/DOMStorage.cs @@ -27,7 +27,10 @@ public record StorageIdType( { } /// DOM Storage item. - public class ItemType : Newtonsoft.Json.Linq.JArray, ChromeProtocol.Core.IType + [Newtonsoft.Json.JsonConverter(typeof(ChromeProtocol.Core.ArrayTypeConverter))] + public record ItemType( + System.Collections.Generic.IReadOnlyCollection Items + ) : ChromeProtocol.Core.IArrayType { } [ChromeProtocol.Core.MethodName("DOMStorage.domStorageItemAdded")] diff --git a/src/ChromeProtocol.Domains/Generated/LayerTree.cs b/src/ChromeProtocol.Domains/Generated/LayerTree.cs index b040075..0b91db8 100644 --- a/src/ChromeProtocol.Domains/Generated/LayerTree.cs +++ b/src/ChromeProtocol.Domains/Generated/LayerTree.cs @@ -118,7 +118,10 @@ public record LayerType( { } /// Array of timings, one per paint step. - public class PaintProfileType : Newtonsoft.Json.Linq.JArray, ChromeProtocol.Core.IType + [Newtonsoft.Json.JsonConverter(typeof(ChromeProtocol.Core.ArrayTypeConverter))] + public record PaintProfileType( + System.Collections.Generic.IReadOnlyCollection Items + ) : ChromeProtocol.Core.IArrayType { } /// The id of the painted layer. diff --git a/src/ChromeProtocol.Domains/Generated/Network.cs b/src/ChromeProtocol.Domains/Generated/Network.cs index 4ab1dfb..9bcaecc 100644 --- a/src/ChromeProtocol.Domains/Generated/Network.cs +++ b/src/ChromeProtocol.Domains/Generated/Network.cs @@ -59,7 +59,10 @@ double Value { } /// Request / response headers as keys / values of JSON object. - public class HeadersType : Newtonsoft.Json.Linq.JObject, ChromeProtocol.Core.IType + [Newtonsoft.Json.JsonConverter(typeof(ChromeProtocol.Core.ObjectTypeConverter))] + public record HeadersType( + System.Collections.Generic.IReadOnlyDictionary Properties + ) : ChromeProtocol.Core.IObjectType { } /// The underlying connection technology that the browser is supposedly using. diff --git a/src/ChromeProtocol.Domains/Generated/Target.cs b/src/ChromeProtocol.Domains/Generated/Target.cs index b47b877..596f6f8 100644 --- a/src/ChromeProtocol.Domains/Generated/Target.cs +++ b/src/ChromeProtocol.Domains/Generated/Target.cs @@ -71,7 +71,10 @@ public record FilterEntryType( /// [{type: "browser", exclude: true}, {type: "tab", exclude: true}, {}]
/// (i.e. include everything but `browser` and `tab`).
/// - public class TargetFilterType : Newtonsoft.Json.Linq.JArray, ChromeProtocol.Core.IType + [Newtonsoft.Json.JsonConverter(typeof(ChromeProtocol.Core.ArrayTypeConverter))] + public record TargetFilterType( + System.Collections.Generic.IReadOnlyCollection Items + ) : ChromeProtocol.Core.IArrayType { } public record RemoteLocationType( diff --git a/src/ChromeProtocol.Domains/Generated/Tracing.cs b/src/ChromeProtocol.Domains/Generated/Tracing.cs index ce7a2c0..bd4990d 100644 --- a/src/ChromeProtocol.Domains/Generated/Tracing.cs +++ b/src/ChromeProtocol.Domains/Generated/Tracing.cs @@ -6,7 +6,10 @@ namespace ChromeProtocol.Domains public static partial class Tracing { /// Configuration for memory dump. Used only when "memory-infra" category is enabled. - public class MemoryDumpConfigType : Newtonsoft.Json.Linq.JObject, ChromeProtocol.Core.IType + [Newtonsoft.Json.JsonConverter(typeof(ChromeProtocol.Core.ObjectTypeConverter))] + public record MemoryDumpConfigType( + System.Collections.Generic.IReadOnlyDictionary Properties + ) : ChromeProtocol.Core.IObjectType { } /// Controls how the trace buffer stores data. diff --git a/src/ChromeProtocol.Tools/CodeGeneration/Pipeline/Steps/GenerateCsharpStep.cs b/src/ChromeProtocol.Tools/CodeGeneration/Pipeline/Steps/GenerateCsharpStep.cs index 6ea9acb..9db0b74 100644 --- a/src/ChromeProtocol.Tools/CodeGeneration/Pipeline/Steps/GenerateCsharpStep.cs +++ b/src/ChromeProtocol.Tools/CodeGeneration/Pipeline/Steps/GenerateCsharpStep.cs @@ -87,22 +87,34 @@ private static CsharpClassDeclBuilder GenerateType(ValidatedType type, Validated p => p.Argument("Value")) .Apply(_ => XmlDocumentationDecorator.AddXmlDocs(_, type, _ => throw new UnreachableException())); }); + case { Kind: TypeKind.Object, Properties.Length: 0 }: - return classBuilder.Class(CsharpNameResolver.Resolve(type.Id, ItemKind.TypeName, classBuilder.Node.Name), + var propertiesType = CsharpTypeInfo.FromGenericType("System.Collections.Generic", "IReadOnlyDictionary", + CsharpTypeInfo.FromTypeName("System", nameof(String)), + CsharpTypeInfo.MakeNullable(CsharpTypeInfo.FromTypeName("Newtonsoft.Json.Linq", "JToken"))); + return classBuilder.Record(CsharpNameResolver.Resolve(type.Id, ItemKind.TypeName, classBuilder.Node.Name), recordBuilder => recordBuilder.Modifiers("public") + .Attribute(CsharpTypeInfo.FromTypeName("Newtonsoft.Json", nameof(JsonConverter)), + attr => attr.Arguments("typeof(ChromeProtocol.Core.ObjectTypeConverter)")) .ApplyIf(type.Deprecated, _ => MarkDeprecated(_, "type")) - .Inherit(CsharpTypeInfo.FromTypeName("Newtonsoft.Json.Linq", nameof(JObject))) - .Inherit(CsharpTypeInfo.FromTypeName("ChromeProtocol.Core", nameof(IType))) + .Inherit(CsharpTypeInfo.FromTypeName("ChromeProtocol.Core", nameof(IObjectType))) + .Parameters(paramsBuilder => paramsBuilder.Parameter("Properties", propertiesType)) .Apply(_ => XmlDocumentationDecorator.AddXmlDocs(_, type, propName => CsharpNameResolver.Resolve(propName, ItemKind.PropertyName, recordBuilder.Node.Name)))); + case { Kind: TypeKind.Array }: - return classBuilder.Class(CsharpNameResolver.Resolve(type.Id, ItemKind.TypeName, classBuilder.Node.Name), + var itemsType = CsharpTypeInfo.FromGenericType("System.Collections.Generic", "IReadOnlyCollection", + CsharpTypeInfo.MakeNullable(CsharpTypeInfo.FromTypeName("Newtonsoft.Json.Linq", "JToken"))); + return classBuilder.Record(CsharpNameResolver.Resolve(type.Id, ItemKind.TypeName, classBuilder.Node.Name), recordBuilder => recordBuilder.Modifiers("public") + .Attribute(CsharpTypeInfo.FromTypeName("Newtonsoft.Json", nameof(JsonConverter)), + attr => attr.Arguments("typeof(ChromeProtocol.Core.ArrayTypeConverter)")) .ApplyIf(type.Deprecated, _ => MarkDeprecated(_, "type")) - .Inherit(CsharpTypeInfo.FromTypeName("Newtonsoft.Json.Linq", nameof(JArray))) - .Inherit(CsharpTypeInfo.FromTypeName("ChromeProtocol.Core", nameof(IType))) + .Inherit(CsharpTypeInfo.FromTypeName("ChromeProtocol.Core", nameof(IArrayType))) + .Parameters(paramsBuilder => paramsBuilder.Parameter("Items", itemsType)) .Apply(_ => XmlDocumentationDecorator.AddXmlDocs(_, type, propName => CsharpNameResolver.Resolve(propName, ItemKind.PropertyName, recordBuilder.Node.Name)))); + default: return classBuilder.Record(CsharpNameResolver.Resolve(type.Id, ItemKind.TypeName, classBuilder.Node.Name), recordBuilder => recordBuilder.Modifiers("public") From e8aedda6e2c6477767c9f0469e6be8af2e823273 Mon Sep 17 00:00:00 2001 From: Andrii Rublov Date: Sun, 7 Jul 2024 23:26:25 +0200 Subject: [PATCH 4/5] [codegen]: Fix exceptions types incompatibility on older runtimes --- src/ChromeProtocol.Core/ArrayTypeConverter.cs | 4 ++-- src/ChromeProtocol.Core/ObjectTypeConverter.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ChromeProtocol.Core/ArrayTypeConverter.cs b/src/ChromeProtocol.Core/ArrayTypeConverter.cs index 68aee31..f27d508 100644 --- a/src/ChromeProtocol.Core/ArrayTypeConverter.cs +++ b/src/ChromeProtocol.Core/ArrayTypeConverter.cs @@ -13,7 +13,7 @@ public override bool CanConvert(Type objectType) public override void WriteJson(JsonWriter writer, object? instance, JsonSerializer serializer) { var type = instance?.GetType(); - var properties = type.GetProperty(nameof(IArrayType.Items)).GetValue(instance) as IList; + var properties = type.GetProperty(nameof(IArrayType.Items)).GetValue(instance) as IReadOnlyCollection; var jArray = new JArray(properties); jArray.WriteTo(writer); @@ -22,7 +22,7 @@ public override void WriteJson(JsonWriter writer, object? instance, JsonSerializ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { var jArray = JArray.Load(reader); - var instance = existingValue ?? Activator.CreateInstance(objectType, jArray); + var instance = existingValue ?? Activator.CreateInstance(objectType, jArray.ToObject>()); return instance; } diff --git a/src/ChromeProtocol.Core/ObjectTypeConverter.cs b/src/ChromeProtocol.Core/ObjectTypeConverter.cs index 30cafa7..49e3eae 100644 --- a/src/ChromeProtocol.Core/ObjectTypeConverter.cs +++ b/src/ChromeProtocol.Core/ObjectTypeConverter.cs @@ -13,7 +13,7 @@ public override bool CanConvert(Type objectType) public override void WriteJson(JsonWriter writer, object? instance, JsonSerializer serializer) { var type = instance?.GetType(); - var properties = type.GetProperty(nameof(IObjectType.Properties)).GetValue(instance) as IDictionary; + var properties = type.GetProperty(nameof(IObjectType.Properties)).GetValue(instance) as IReadOnlyDictionary; var jObject = new JObject(properties); jObject.WriteTo(writer); @@ -22,7 +22,7 @@ public override void WriteJson(JsonWriter writer, object? instance, JsonSerializ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { var jObject = JObject.Load(reader); - var instance = existingValue ?? Activator.CreateInstance(objectType, jObject); + var instance = existingValue ?? Activator.CreateInstance(objectType, jObject.ToObject>()); return instance; } From 88624ff6e9f6af2ecc81042fb003e50d2282229f Mon Sep 17 00:00:00 2001 From: Andrii Rublov Date: Sun, 7 Jul 2024 23:36:26 +0200 Subject: [PATCH 5/5] [codegen]: Remove nullable types from weakly typed arrays --- src/ChromeProtocol.Domains/Generated/DOM.cs | 2 +- src/ChromeProtocol.Domains/Generated/DOMSnapshot.cs | 4 ++-- src/ChromeProtocol.Domains/Generated/DOMStorage.cs | 2 +- src/ChromeProtocol.Domains/Generated/LayerTree.cs | 2 +- src/ChromeProtocol.Domains/Generated/Target.cs | 2 +- .../CodeGeneration/Pipeline/Steps/GenerateCsharpStep.cs | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ChromeProtocol.Domains/Generated/DOM.cs b/src/ChromeProtocol.Domains/Generated/DOM.cs index a73759f..c108a7a 100644 --- a/src/ChromeProtocol.Domains/Generated/DOM.cs +++ b/src/ChromeProtocol.Domains/Generated/DOM.cs @@ -217,7 +217,7 @@ public record RGBAType( /// An array of quad vertices, x immediately followed by y for each point, points clock-wise. [Newtonsoft.Json.JsonConverter(typeof(ChromeProtocol.Core.ArrayTypeConverter))] public record QuadType( - System.Collections.Generic.IReadOnlyCollection Items + System.Collections.Generic.IReadOnlyCollection Items ) : ChromeProtocol.Core.IArrayType { } diff --git a/src/ChromeProtocol.Domains/Generated/DOMSnapshot.cs b/src/ChromeProtocol.Domains/Generated/DOMSnapshot.cs index 885c2bd..8f6574c 100644 --- a/src/ChromeProtocol.Domains/Generated/DOMSnapshot.cs +++ b/src/ChromeProtocol.Domains/Generated/DOMSnapshot.cs @@ -192,7 +192,7 @@ int Value /// Index of the string in the strings table. [Newtonsoft.Json.JsonConverter(typeof(ChromeProtocol.Core.ArrayTypeConverter))] public record ArrayOfStringsType( - System.Collections.Generic.IReadOnlyCollection Items + System.Collections.Generic.IReadOnlyCollection Items ) : ChromeProtocol.Core.IArrayType { } @@ -221,7 +221,7 @@ System.Collections.Generic.IReadOnlyList Value } [Newtonsoft.Json.JsonConverter(typeof(ChromeProtocol.Core.ArrayTypeConverter))] public record RectangleType( - System.Collections.Generic.IReadOnlyCollection Items + System.Collections.Generic.IReadOnlyCollection Items ) : ChromeProtocol.Core.IArrayType { } diff --git a/src/ChromeProtocol.Domains/Generated/DOMStorage.cs b/src/ChromeProtocol.Domains/Generated/DOMStorage.cs index ecfecf3..f36fc47 100644 --- a/src/ChromeProtocol.Domains/Generated/DOMStorage.cs +++ b/src/ChromeProtocol.Domains/Generated/DOMStorage.cs @@ -29,7 +29,7 @@ public record StorageIdType( /// DOM Storage item. [Newtonsoft.Json.JsonConverter(typeof(ChromeProtocol.Core.ArrayTypeConverter))] public record ItemType( - System.Collections.Generic.IReadOnlyCollection Items + System.Collections.Generic.IReadOnlyCollection Items ) : ChromeProtocol.Core.IArrayType { } diff --git a/src/ChromeProtocol.Domains/Generated/LayerTree.cs b/src/ChromeProtocol.Domains/Generated/LayerTree.cs index 0b91db8..d77f0a6 100644 --- a/src/ChromeProtocol.Domains/Generated/LayerTree.cs +++ b/src/ChromeProtocol.Domains/Generated/LayerTree.cs @@ -120,7 +120,7 @@ public record LayerType( /// Array of timings, one per paint step. [Newtonsoft.Json.JsonConverter(typeof(ChromeProtocol.Core.ArrayTypeConverter))] public record PaintProfileType( - System.Collections.Generic.IReadOnlyCollection Items + System.Collections.Generic.IReadOnlyCollection Items ) : ChromeProtocol.Core.IArrayType { } diff --git a/src/ChromeProtocol.Domains/Generated/Target.cs b/src/ChromeProtocol.Domains/Generated/Target.cs index 596f6f8..2e7db6b 100644 --- a/src/ChromeProtocol.Domains/Generated/Target.cs +++ b/src/ChromeProtocol.Domains/Generated/Target.cs @@ -73,7 +73,7 @@ public record FilterEntryType( /// [Newtonsoft.Json.JsonConverter(typeof(ChromeProtocol.Core.ArrayTypeConverter))] public record TargetFilterType( - System.Collections.Generic.IReadOnlyCollection Items + System.Collections.Generic.IReadOnlyCollection Items ) : ChromeProtocol.Core.IArrayType { } diff --git a/src/ChromeProtocol.Tools/CodeGeneration/Pipeline/Steps/GenerateCsharpStep.cs b/src/ChromeProtocol.Tools/CodeGeneration/Pipeline/Steps/GenerateCsharpStep.cs index 9db0b74..fa6dea9 100644 --- a/src/ChromeProtocol.Tools/CodeGeneration/Pipeline/Steps/GenerateCsharpStep.cs +++ b/src/ChromeProtocol.Tools/CodeGeneration/Pipeline/Steps/GenerateCsharpStep.cs @@ -104,7 +104,7 @@ private static CsharpClassDeclBuilder GenerateType(ValidatedType type, Validated case { Kind: TypeKind.Array }: var itemsType = CsharpTypeInfo.FromGenericType("System.Collections.Generic", "IReadOnlyCollection", - CsharpTypeInfo.MakeNullable(CsharpTypeInfo.FromTypeName("Newtonsoft.Json.Linq", "JToken"))); + CsharpTypeInfo.FromTypeName("Newtonsoft.Json.Linq", "JToken")); return classBuilder.Record(CsharpNameResolver.Resolve(type.Id, ItemKind.TypeName, classBuilder.Node.Name), recordBuilder => recordBuilder.Modifiers("public") .Attribute(CsharpTypeInfo.FromTypeName("Newtonsoft.Json", nameof(JsonConverter)),