From 6c15a111fc8e3cf19d8cbbb65ef724c28f10a0d5 Mon Sep 17 00:00:00 2001 From: David Pine Date: Wed, 13 Oct 2021 11:24:10 -0500 Subject: [PATCH] More updates and additional functionality added --- src/TypeScript.TypeConverter/CSharpMember.cs | 5 ++- src/TypeScript.TypeConverter/CSharpObject.cs | 5 ++- src/TypeScript.TypeConverter/LibDomParser.cs | 23 +++++++--- src/TypeScript.TypeConverter/TypeMap.cs | 27 +++++++++++ .../LibDomParserTests.cs | 45 +++++++++++++++++++ 5 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 src/TypeScript.TypeConverter/TypeMap.cs create mode 100644 tests/TypeScript.TypeConverter.Tests/LibDomParserTests.cs diff --git a/src/TypeScript.TypeConverter/CSharpMember.cs b/src/TypeScript.TypeConverter/CSharpMember.cs index 5605be4..d3c94c6 100644 --- a/src/TypeScript.TypeConverter/CSharpMember.cs +++ b/src/TypeScript.TypeConverter/CSharpMember.cs @@ -10,4 +10,7 @@ internal record CSharpMember( string Name, string TypeName, bool IsNullable = false, - bool IsReadonly = false); \ No newline at end of file + bool IsReadonly = false) +{ + public string MappedTypeName => TypeMap.PrimitiveTypes[TypeName]; +} \ No newline at end of file diff --git a/src/TypeScript.TypeConverter/CSharpObject.cs b/src/TypeScript.TypeConverter/CSharpObject.cs index b3e69ea..cb7d264 100644 --- a/src/TypeScript.TypeConverter/CSharpObject.cs +++ b/src/TypeScript.TypeConverter/CSharpObject.cs @@ -29,6 +29,7 @@ public sealed override string ToString() { if (IsParameter && Members is { Count: 1 }) { + // TODO: Return simplified parameter declaration text. return $""; } @@ -46,7 +47,7 @@ public sealed override string ToString() var statementTerminator = index + 1 < memberCount ? "," : ""; var nullableExpression = member.IsNullable ? "?" : ""; builder.Append( - $" {member.TypeName}{nullableExpression} {memberName.CapitalizeFirstLetter()}{statementTerminator}\r\n"); + $" {member.MappedTypeName}{nullableExpression} {memberName.CapitalizeFirstLetter()}{statementTerminator}\r\n"); } builder.Append(");\r\n"); @@ -61,7 +62,7 @@ public sealed override string ToString() var nullableExpression = member.IsNullable ? "?" : ""; builder.Append( - $" public {member.TypeName}{nullableExpression} {memberName.CapitalizeFirstLetter()} {{ get; set; }}\r\n"); + $" public {member.MappedTypeName}{nullableExpression} {memberName.CapitalizeFirstLetter()} {{ get; set; }}\r\n"); } builder.Append("}\r\n"); diff --git a/src/TypeScript.TypeConverter/LibDomParser.cs b/src/TypeScript.TypeConverter/LibDomParser.cs index 6ed1353..3e5b574 100644 --- a/src/TypeScript.TypeConverter/LibDomParser.cs +++ b/src/TypeScript.TypeConverter/LibDomParser.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System.Collections.Concurrent; +using System.Text.RegularExpressions; namespace TypeScript.TypeConverter; @@ -11,6 +12,15 @@ public class LibDomParser private readonly HttpClient _httpClient = new(); private readonly ConcurrentDictionary _typeNameToTypeDefinitionMap = new(); + // See: https://regex101.com/r/GV3DiG/1 + private readonly Regex _interfacesRegex = new("(?'declaration'interface.*?{.*?})", RegexOptions.Singleline); + private readonly Regex _interfaceTypeName = new("(?:interface )(?'TypeName'\\S+)"); + + /// + /// For testing purposes. + /// + internal bool IsInitialized => _typeNameToTypeDefinitionMap is { Count: > 100 }; + public async Task InitializeAsync() { try @@ -18,11 +28,14 @@ public async Task InitializeAsync() var libDomDefinitionTypeScript = await _httpClient.GetStringAsync(_rawUrl); if (libDomDefinitionTypeScript is { Length: > 0 }) { - // TODO: parse entire file into - // _typeNameToTypeDefinitionMap - - // key: type name - // value: type definition + foreach (Match match in _interfacesRegex.Matches(libDomDefinitionTypeScript)) + { + var typeName = _interfaceTypeName.GetMatchGroupValue(match.Value, "TypeName"); + if (typeName is not null) + { + _typeNameToTypeDefinitionMap[typeName] = match.Value; + } + } } } catch (Exception ex) diff --git a/src/TypeScript.TypeConverter/TypeMap.cs b/src/TypeScript.TypeConverter/TypeMap.cs new file mode 100644 index 0000000..c5af6bf --- /dev/null +++ b/src/TypeScript.TypeConverter/TypeMap.cs @@ -0,0 +1,27 @@ +// Copyright (c) David Pine. All rights reserved. +// Licensed under the MIT License. + +namespace TypeScript.TypeConverter; + +static class TypeMap +{ + internal static readonly Primitives PrimitiveTypes = new(); + + internal class Primitives + { + internal static readonly Dictionary _primitiveTypeMap = + new(StringComparer.OrdinalIgnoreCase) + { + // The JavaScript Number type is a double-precision 64-bit binary format IEEE 754 value + ["number"] = "double", + ["string"] = "string", + ["boolean"] = "bool", + ["enum"] = "enum", + ["Date"] = "DateTime", + //["Array"] = "[]" + }; + + internal string this[string typeScriptType] => + _primitiveTypeMap.TryGetValue(typeScriptType, out var csharpType) ? csharpType : typeScriptType; + } +} diff --git a/tests/TypeScript.TypeConverter.Tests/LibDomParserTests.cs b/tests/TypeScript.TypeConverter.Tests/LibDomParserTests.cs new file mode 100644 index 0000000..94ccf79 --- /dev/null +++ b/tests/TypeScript.TypeConverter.Tests/LibDomParserTests.cs @@ -0,0 +1,45 @@ +// Copyright (c) David Pine. All rights reserved. +// Licensed under the MIT License. + +using System.Diagnostics; +using Xunit; + +namespace TypeScript.TypeConverter.Tests; + +public class LibDomParserTests +{ + [Fact] + public async Task InitializesTypeDefinitionsCorrectly() + { + var stopwatch = Stopwatch.StartNew(); + var sut = new LibDomParser(); + + await sut.InitializeAsync(); + stopwatch.Stop(); + + Assert.True(sut.IsInitialized); + Assert.True(stopwatch.Elapsed < TimeSpan.FromSeconds(1.5)); + } + + [Fact] + public async Task TryParseDefinitionCorrectly() + { + var sut = new LibDomParser(); + + await sut.InitializeAsync(); + + var expected = @"namespace Microsoft.JSInterop; + +public record PositionOptions( + bool? EnableHighAccuracy, + double? MaximumAge, + double? Timeout +); +"; + + var result = sut.TryParseType("PositionOptions", false, out var actual); + + Assert.True(result); + Assert.Equal(expected, actual); + } +}