diff --git a/src/Dapper.Json.Core/Dapper.Json.Core.csproj b/src/Dapper.Json.Core/Dapper.Json.Core.csproj index 5031665..0aaa636 100644 --- a/src/Dapper.Json.Core/Dapper.Json.Core.csproj +++ b/src/Dapper.Json.Core/Dapper.Json.Core.csproj @@ -5,6 +5,7 @@ enable enable latest + Dapper.Json diff --git a/src/Dapper.Json.Core/Json.cs b/src/Dapper.Json.Core/Json.cs index fea271f..d5b1619 100644 --- a/src/Dapper.Json.Core/Json.cs +++ b/src/Dapper.Json.Core/Json.cs @@ -1,13 +1,8 @@ namespace Dapper.Json; -public class Json +public class Json(T? value) { - public Json(T? value) - { - Value = value; - } + public T? Value { get; } = value; - public T? Value { get; } - public static implicit operator Json(T? value) => new(value); } \ No newline at end of file diff --git a/src/Dapper.Json.Newtonsoft/Dapper.Json.Newtonsoft.csproj b/src/Dapper.Json.Newtonsoft/Dapper.Json.Newtonsoft.csproj index 5c515a8..e91050e 100644 --- a/src/Dapper.Json.Newtonsoft/Dapper.Json.Newtonsoft.csproj +++ b/src/Dapper.Json.Newtonsoft/Dapper.Json.Newtonsoft.csproj @@ -4,11 +4,12 @@ netstandard2.0 Apparatus.Dapper.Json.Newtonsoft Enables the Newtonsoft.Json deserialization for Apparatus.Dapper.Json. + Dapper.Json - + diff --git a/src/Dapper.Json.SourceGenerator/Dapper.Json.SourceGenerator.csproj b/src/Dapper.Json.SourceGenerator/Dapper.Json.SourceGenerator.csproj index 8fb7432..975ebb7 100644 --- a/src/Dapper.Json.SourceGenerator/Dapper.Json.SourceGenerator.csproj +++ b/src/Dapper.Json.SourceGenerator/Dapper.Json.SourceGenerator.csproj @@ -2,11 +2,12 @@ netstandard2.0 + true 10 - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Dapper.Json.SourceGenerator/DapperJsonSourceGenerator.cs b/src/Dapper.Json.SourceGenerator/DapperJsonSourceGenerator.cs index bda4ff5..c8dcab7 100644 --- a/src/Dapper.Json.SourceGenerator/DapperJsonSourceGenerator.cs +++ b/src/Dapper.Json.SourceGenerator/DapperJsonSourceGenerator.cs @@ -1,7 +1,6 @@ using System.Collections.Immutable; using System.Linq; using System.Threading; -using DuckInterface; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -13,7 +12,7 @@ public class DapperJsonSourceGenerator : IIncrementalGenerator public void Initialize(IncrementalGeneratorInitializationContext context) { var jsonType = context.CompilationProvider - .Select((o, t) => o.GetTypeByMetadataName("Dapper.Json.Json`1")); + .Select((o, _) => o.GetTypeByMetadataName("Dapper.Json.Json`1")); var jsons = context.SyntaxProvider .CreateSyntaxProvider(SelectJsonT, Transform); @@ -83,7 +82,7 @@ private ITypeSymbol Transform(GeneratorSyntaxContext context, CancellationToken private bool SelectJsonT(SyntaxNode syntaxNode, CancellationToken token) { - if (syntaxNode is GenericNameSyntax { Identifier.ValueText: "Json", } type) + if (syntaxNode is GenericNameSyntax { Identifier.ValueText: "Json", } _) { return true; } diff --git a/src/Dapper.Json.SourceGenerator/DapperSourceGeneratorSyntaxReceiver.cs b/src/Dapper.Json.SourceGenerator/DapperSourceGeneratorSyntaxReceiver.cs deleted file mode 100644 index 65ca9ea..0000000 --- a/src/Dapper.Json.SourceGenerator/DapperSourceGeneratorSyntaxReceiver.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Collections.Generic; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; - -namespace Dapper.Json.SourceGenerator; - -public class DapperSourceGeneratorSyntaxReceiver : ISyntaxReceiver -{ - public List Types { get; } = new(); - - public void OnVisitSyntaxNode(SyntaxNode syntaxNode) - { - if (syntaxNode is GenericNameSyntax { Identifier.ValueText: "Json", } type) - { - Types.Add(type); - } - } -} \ No newline at end of file diff --git a/src/Dapper.Json.SourceGenerator/Utils.cs b/src/Dapper.Json.SourceGenerator/Utils.cs index a594a39..ea7df9c 100644 --- a/src/Dapper.Json.SourceGenerator/Utils.cs +++ b/src/Dapper.Json.SourceGenerator/Utils.cs @@ -5,174 +5,168 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Text; -namespace DuckInterface +namespace Dapper.Json.SourceGenerator; + +public static class Utils { - public static class Utils + public const string EditorBrowsable = "[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]"; + + public static string GetDuckImplementationClassName(ITypeSymbol duckInterface) { - public const string EditorBrowsable = "[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]"; + return $"Duck_{duckInterface.ToSafeGlobalName()}"; + } - public static string GetDuckImplementationClassName(ITypeSymbol duckInterface) + public static string LowerFirstChar(this string value) + { + var stringBuilder = new StringBuilder(); + stringBuilder.Append(char.ToLower(value.First())); + var span = value.AsSpan(1); + for (int i = 0; i < span.Length; i++) { - return $"Duck_{duckInterface.ToSafeGlobalName()}"; + stringBuilder.Append(span[i]); } - public static string LowerFirstChar(this string value) - { - var stringBuilder = new StringBuilder(); - stringBuilder.Append(char.ToLower(value.First())); - var span = value.AsSpan(1); - for (int i = 0; i < span.Length; i++) - { - stringBuilder.Append(span[i]); - } - - return stringBuilder.ToString(); - } + return stringBuilder.ToString(); + } - public static IEnumerable GetAllMembers(this ITypeSymbol symbol, HashSet processedInterfaces = null) + public static IEnumerable GetAllMembers(this ITypeSymbol symbol, HashSet processedInterfaces = null) + { + processedInterfaces ??= new HashSet(SymbolEqualityComparer.Default); + if (symbol.BaseType != null) { - processedInterfaces ??= new HashSet(SymbolEqualityComparer.Default); - if (symbol.BaseType != null) - { - foreach (var member in symbol.BaseType.GetAllMembers(processedInterfaces)) - { - yield return member; - } - } - - foreach (var member in symbol.GetMembers()) + foreach (var member in symbol.BaseType.GetAllMembers(processedInterfaces)) { yield return member; } + } - var typeSymbols = symbol.Interfaces - .Where(o => !processedInterfaces.Contains(o)) - .OfType() - .ToArray(); - - foreach (var type in typeSymbols) - { - processedInterfaces.Add(type); - } + foreach (var member in symbol.GetMembers()) + { + yield return member; + } - var members = typeSymbols - .SelectMany(o => o.GetAllMembers(processedInterfaces)) - .Distinct(SymbolEqualityComparer.Default); + var typeSymbols = symbol.Interfaces + .Where(o => !processedInterfaces.Contains(o)) + .OfType() + .ToArray(); - foreach (var member in members) - { - yield return member; - } + foreach (var type in typeSymbols) + { + processedInterfaces.Add(type); } - public static ITypeSymbol GetTypeSymbol(this SymbolInfo info) + var members = typeSymbols + .SelectMany(o => o.GetAllMembers(processedInterfaces)) + .Distinct(SymbolEqualityComparer.Default); + + foreach (var member in members) { - switch (info.Symbol) - { - case ITypeSymbol type: - return type; - case ILocalSymbol local: - return local.Type; - case IParameterSymbol parameterSymbol: - return parameterSymbol.Type; - default: - return null; - } + yield return member; } + } - public static IEnumerable GetPublicMethods(this IEnumerable members) + public static ITypeSymbol GetTypeSymbol(this SymbolInfo info) + { + switch (info.Symbol) { - return members - .OfType() - .Where(o => o.DeclaredAccessibility == Accessibility.Public) - .Where(o => o.MethodKind == MethodKind.Ordinary); + case ITypeSymbol type: + return type; + case ILocalSymbol local: + return local.Type; + case IParameterSymbol parameterSymbol: + return parameterSymbol.Type; + default: + return null; } + } - public static (bool IsDuckable, IEnumerable MissingSymbols) IsDuckableTo( - this ITypeSymbol @interface, ITypeSymbol implementation) - { - var methodsToDuck = MemberThatCanBeDucked(@interface); - var memberThatCanBeDucked = MemberThatCanBeDucked(implementation); + public static IEnumerable GetPublicMethods(this IEnumerable members) + { + return members + .OfType() + .Where(o => o.DeclaredAccessibility == Accessibility.Public) + .Where(o => o.MethodKind == MethodKind.Ordinary); + } - var missingSymbols = methodsToDuck - .Where(o => !memberThatCanBeDucked.ContainsKey(o.Key)) - .Select(o => o.Value) - .ToArray(); + public static (bool IsDuckable, IEnumerable MissingSymbols) IsDuckableTo( + this ITypeSymbol @interface, ITypeSymbol implementation) + { + var methodsToDuck = MemberThatCanBeDucked(@interface); + var memberThatCanBeDucked = MemberThatCanBeDucked(implementation); - return (!missingSymbols.Any(), missingSymbols); - } + var missingSymbols = methodsToDuck + .Where(o => !memberThatCanBeDucked.ContainsKey(o.Key)) + .Select(o => o.Value) + .ToArray(); - private static Dictionary MemberThatCanBeDucked(ITypeSymbol type) - { - var properties = type - .GetAllMembers() - .OfType() - .Where(o => o.DeclaredAccessibility.HasFlag(Accessibility.Public)) - .Select(o => - ( - Key: - $"{o.Type.ToGlobalName()}_{o.Name}{(o.GetMethod != null ? "_getter" : string.Empty)}{(o.SetMethod != null ? "_setter" : string.Empty)}", - Value: (ISymbol)o - )) - .ToArray(); - - var methods = type - .GetAllMembers() - .GetPublicMethods() - .Select(o => - ( - Key: - $"{o.ReturnType.ToGlobalName()}_${o.Name}_{o.Parameters.Select(oo => oo.Type.ToGlobalName() + oo.Name).Join("_")}", - Value: (ISymbol)o - )) - .ToArray(); - - return methods - .Concat(properties) - .GroupBy(o => o.Key) - .ToDictionary(o => o.Key, o => o.First().Value); - } + return (!missingSymbols.Any(), missingSymbols); + } - public static string GetUniqueName(this ITypeSymbol type) - { - return $"{type.Name}_{Guid.NewGuid().ToString().Replace("-", "")}"; - } + private static Dictionary MemberThatCanBeDucked(ITypeSymbol type) + { + var properties = type + .GetAllMembers() + .OfType() + .Where(o => o.DeclaredAccessibility.HasFlag(Accessibility.Public)) + .Select(o => + ( + Key: + $"{o.Type.ToGlobalName()}_{o.Name}{(o.GetMethod != null ? "_getter" : string.Empty)}{(o.SetMethod != null ? "_setter" : string.Empty)}", + Value: (ISymbol)o + )) + .ToArray(); + + var methods = type + .GetAllMembers() + .GetPublicMethods() + .Select(o => + ( + Key: + $"{o.ReturnType.ToGlobalName()}_${o.Name}_{o.Parameters.Select(oo => oo.Type.ToGlobalName() + oo.Name).Join("_")}", + Value: (ISymbol)o + )) + .ToArray(); + + return methods + .Concat(properties) + .GroupBy(o => o.Key) + .ToDictionary(o => o.Key, o => o.First().Value); + } - public static SourceText ToSourceText(this string source) - { - return SourceText.From(source, Encoding.UTF8); - } + public static string GetUniqueName(this ITypeSymbol type) + { + return $"{type.Name}_{Guid.NewGuid().ToString().Replace("-", "")}"; + } - public static string ToGlobalName(this ISymbol symbol) - { - return symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); - } + public static SourceText ToSourceText(this string source) + { + return SourceText.From(source, Encoding.UTF8); + } - public static string ToSafeGlobalName(this ISymbol symbol) - { - return symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) - .Replace("global::", "") - .Replace("[]", "Array") - .Replace("<", "Of") - .Replace(">", "") - .Replace(",", "And") - .Replace(" ", "") - .Replace(".", ""); - } + public static string ToGlobalName(this ISymbol symbol) + { + return symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + } - public static string Join(this IEnumerable values, string separator = ", ") - { - return string.Join(separator, values); - } + public static string ToSafeGlobalName(this ISymbol symbol) + { + return symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + .Replace("global::", "") + .Replace("[]", "Array") + .Replace("<", "Of") + .Replace(">", "") + .Replace(",", "And") + .Replace(" ", "") + .Replace(".", ""); + } - public static string Wrap(this string text, string left = "", string right = "") - { - return $"{left}{text}{right}"; - } + public static string Join(this IEnumerable values, string separator = ", ") + { + return string.Join(separator, values); + } - public static string JoinWithNewLine(this IEnumerable values, string separator = "") - { - return string.Join($"{separator}{Environment.NewLine}", values); - } + public static string Wrap(this string text, string left = "", string right = "") + { + return $"{left}{text}{right}"; } } \ No newline at end of file diff --git a/src/Dapper.Json.System/Dapper.Json.System.csproj b/src/Dapper.Json.System/Dapper.Json.System.csproj index 6f71de1..749e880 100644 --- a/src/Dapper.Json.System/Dapper.Json.System.csproj +++ b/src/Dapper.Json.System/Dapper.Json.System.csproj @@ -4,11 +4,12 @@ netstandard2.0 Apparatus.Dapper.Json.System Enables the System.Json deserialization for Apparatus.Dapper.Json. + Dapper.Json - + diff --git a/src/Dapper.Json.TestProject/Dapper.Json.TestProject.csproj b/src/Dapper.Json.TestProject/Dapper.Json.TestProject.csproj index 526699c..5d4caec 100644 --- a/src/Dapper.Json.TestProject/Dapper.Json.TestProject.csproj +++ b/src/Dapper.Json.TestProject/Dapper.Json.TestProject.csproj @@ -2,12 +2,12 @@ Exe - net6.0 + net8.0 enable - + diff --git a/src/Dapper.Json.Tests/Dapper.Json.Tests.csproj b/src/Dapper.Json.Tests/Dapper.Json.Tests.csproj index f28cf6e..aa78ac6 100644 --- a/src/Dapper.Json.Tests/Dapper.Json.Tests.csproj +++ b/src/Dapper.Json.Tests/Dapper.Json.Tests.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 enable enable false @@ -11,13 +11,13 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/src/Dapper.Json.Tests/Data/TestProject.cs b/src/Dapper.Json.Tests/Data/TestProject.cs index 578adf9..5722533 100644 --- a/src/Dapper.Json.Tests/Data/TestProject.cs +++ b/src/Dapper.Json.Tests/Data/TestProject.cs @@ -1,23 +1,21 @@ -using System.Linq; -using Buildalyzer; +using Buildalyzer; using Buildalyzer.Workspaces; using Microsoft.CodeAnalysis; -namespace Dapper.Json.Tests.Data +namespace Dapper.Json.Tests.Data; + +public static class TestProject { - public static class TestProject - { - public static Project Project { get; } + public static Project Project { get; } - public static AdhocWorkspace Workspace { get; } + public static AdhocWorkspace Workspace { get; } - static TestProject() - { - var manager = new AnalyzerManager(); - manager.GetProject(@"../../../../Dapper.Json.TestProject/Dapper.Json.TestProject.csproj"); - Workspace = manager.GetWorkspace(); + static TestProject() + { + var manager = new AnalyzerManager(); + manager.GetProject(@"../../../../Dapper.Json.TestProject/Dapper.Json.TestProject.csproj"); + Workspace = manager.GetWorkspace(); - Project = Workspace.CurrentSolution.Projects.First(o => o.Name == "Dapper.Json.TestProject"); - } + Project = Workspace.CurrentSolution.Projects.First(o => o.Name == "Dapper.Json.TestProject"); } } \ No newline at end of file diff --git a/src/Dapper.Json.Tests/MainTest.cs b/src/Dapper.Json.Tests/MainTest.cs index 51087c1..2568bb7 100644 --- a/src/Dapper.Json.Tests/MainTest.cs +++ b/src/Dapper.Json.Tests/MainTest.cs @@ -1,9 +1,9 @@ using Dapper.Json.Tests.Data; +using Dapper.Json.Tests.Utils; using Microsoft.CodeAnalysis; namespace Dapper.Json.Tests; -[UsesVerify] public class MainTest : IAsyncLifetime { [Fact] @@ -115,7 +115,7 @@ private static async Task Execute(Project project) method.Invoke(null, null); - var handlers = Utils.GetRegisteredJsonTypeHandlers(); + var handlers = Utils.Utils.GetRegisteredJsonTypeHandlers(); return handlers; } diff --git a/src/Dapper.Json.Tests/Utils/Utils.cs b/src/Dapper.Json.Tests/Utils/Utils.cs index 75f5869..950f822 100644 --- a/src/Dapper.Json.Tests/Utils/Utils.cs +++ b/src/Dapper.Json.Tests/Utils/Utils.cs @@ -1,69 +1,63 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; +using System.Reflection; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Text; -namespace Dapper.Json.Tests +namespace Dapper.Json.Tests.Utils; + +public static class Utils { - public static class Utils + public static string[] GetRegisteredJsonTypeHandlers() { - public static string[] GetRegisteredJsonTypeHandlers() - { - var field = typeof(SqlMapper) - .GetField("typeHandlers", BindingFlags.Static | BindingFlags.NonPublic)!; + var field = typeof(SqlMapper) + .GetField("typeHandlers", BindingFlags.Static | BindingFlags.NonPublic)!; - var handlers = field.GetValue(null) as Dictionary; + var handlers = field.GetValue(null) as Dictionary; - return handlers! - .Where(o => o.Key.FullName!.StartsWith("Dapper.Json.Json")) - .Select(o => o.Key.GenericTypeArguments.First().Name) - .ToArray(); - } + return handlers! + .Where(o => o.Key.FullName!.StartsWith("Dapper.Json.Json")) + .Select(o => o.Key.GenericTypeArguments.First().Name) + .ToArray(); + } - public static async Task ReplacePartOfDocumentAsync(this Project project, string documentName, string textToReplace, string newText) - { - return await project.ReplacePartsOfDocumentAsync(documentName, (textToReplace, newText)); - } + public static async Task ReplacePartOfDocumentAsync(this Project project, string documentName, string textToReplace, string newText) + { + return await project.ReplacePartsOfDocumentAsync(documentName, (textToReplace, newText)); + } - public static async Task ReplacePartsOfDocumentAsync(this Project project, string documentName, params (string TextToReplace, string NewText)[] placesToReplace) + public static async Task ReplacePartsOfDocumentAsync(this Project project, string documentName, params (string TextToReplace, string NewText)[] placesToReplace) + { + var document = project.Documents.First(o => o.Name == documentName); + foreach (var place in placesToReplace) { - var document = project.Documents.First(o => o.Name == documentName); - foreach (var place in placesToReplace) - { - var text = await document.GetTextAsync(); - var sourceText = SourceText.From(text.ToString().Replace(place.TextToReplace, place.NewText)); - document = document - .WithText(sourceText); - } - - return document.Project; + var text = await document.GetTextAsync(); + var sourceText = SourceText.From(text.ToString().Replace(place.TextToReplace, place.NewText)); + document = document + .WithText(sourceText); } - public static async Task CompileToRealAssembly(this Project project) - { - var compilation = await project.GetCompilationAsync(); - var analyzerResults = compilation.GetDiagnostics(); + return document.Project; + } + + public static async Task CompileToRealAssembly(this Project project) + { + var compilation = await project.GetCompilationAsync(); + var analyzerResults = compilation.GetDiagnostics(); - var error = compilation.GetDiagnostics().Concat(analyzerResults) - .FirstOrDefault(o => o.Severity == DiagnosticSeverity.Error); + var error = compilation.GetDiagnostics().Concat(analyzerResults) + .FirstOrDefault(o => o.Severity == DiagnosticSeverity.Error); - if (error != null) - { - throw new Exception(error.GetMessage()); - } + if (error != null) + { + throw new Exception(error.GetMessage()); + } - using (var memoryStream = new MemoryStream()) - { - compilation.Emit(memoryStream); - var bytes = memoryStream.ToArray(); - var assembly = Assembly.Load(bytes); + using (var memoryStream = new MemoryStream()) + { + compilation.Emit(memoryStream); + var bytes = memoryStream.ToArray(); + var assembly = Assembly.Load(bytes); - return assembly; - } + return assembly; } } } \ No newline at end of file