-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathClassGeneration.cs
123 lines (111 loc) · 5.8 KB
/
ClassGeneration.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using SF = Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
namespace NetJsonAOT.Generators;
internal static class ClassGeneration
{
public static SyntaxTree GenerateJsonSerializable(string fullNamespace, string className, SyntaxKind accessModifier)
{
// todo - runtime types and using statements
// function to be called "CreateClassWithAttributes or something like that
var usingDirectives = new[]
{
SF.UsingDirective(SF.ParseName("System")), SF.UsingDirective(SF.ParseName("System.Text.Json")),
SF.UsingDirective(SF.ParseName("System.Text.Json.Serialization"))
};
var namespaceLastPart = $"{className}.JsonGen";
var generatedNamespace = string.IsNullOrWhiteSpace(fullNamespace)
? namespaceLastPart
: $"{fullNamespace}.{namespaceLastPart}";
var tree = SF.SyntaxTree(
root: SF.CompilationUnit()
.WithUsings(SF.List(usingDirectives))
// add namespace of original type
.WithMembers(SF.SingletonList<MemberDeclarationSyntax>(
SF.NamespaceDeclaration(SF.ParseName(generatedNamespace)))
)
.WithMembers(SF.SingletonList<MemberDeclarationSyntax>(
CreateClassDeclaration(fullNamespace, className, accessModifier)
)
)
.NormalizeWhitespace(),
encoding: Encoding.UTF8
);
return tree;
static ClassDeclarationSyntax CreateClassDeclaration(string fullNamespace, string className, SyntaxKind scope)
{
switch (scope)
{
case SyntaxKind.InternalKeyword:
break;
case SyntaxKind.PublicKeyword:
break;
case SyntaxKind.ProtectedKeyword:
break;
default:
throw new ArgumentOutOfRangeException(nameof(scope), scope, null);
}
/*
[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)]
[JsonSerializable(typeof(Person))]
internal partial class PersonJsonContext : JsonSerializerContext
{
}
*/
var jsonContextClassName = className + "JsonContext";
var fullyQualifiedClassName = fullNamespace + "." + className;
GeneratedTypes.AddType(fullyQualifiedClassName, jsonContextClassName);
const string jsonContextName = "System.Text.Json.Serialization.JsonSerializerContext";
//todo - add serialization attribute for field types
return SF.ClassDeclaration(jsonContextClassName)
.WithAttributeLists(SF.List(
[
SF.AttributeList(SF.SingletonSeparatedList(SF
.Attribute(SF.IdentifierName("JsonSourceGenerationOptions"))
.WithArgumentList(SF.AttributeArgumentList(SF.SeparatedList<AttributeArgumentSyntax>(
new SyntaxNodeOrToken[]
{
SF.AttributeArgument(SF.LiteralExpression(SyntaxKind.TrueLiteralExpression))
.WithNameEquals(SF.NameEquals(SF.IdentifierName("WriteIndented"))),
SF.Token(SyntaxKind.CommaToken), SF.AttributeArgument(SF.MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
SF.IdentifierName("JsonSourceGenerationMode"),
SF.IdentifierName("Default")))
.WithNameEquals(SF.NameEquals(SF.IdentifierName("GenerationMode"))),
SF.Token(SyntaxKind.CommaToken), SF.AttributeArgument(SF.MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
SF.IdentifierName("JsonCommentHandling"), SF.IdentifierName("Skip")))
.WithNameEquals(SF.NameEquals("ReadCommentHandling")),
SF.Token(SyntaxKind.CommaToken), SF
.AttributeArgument(SF.LiteralExpression(SyntaxKind.TrueLiteralExpression))
.WithNameEquals(SF.NameEquals("IgnoreReadOnlyFields"))
}))))),
SF.AttributeList(SF.SingletonSeparatedList(
GenerateAttributeWithTypeArgument(fullyQualifiedClassName)))
]
)
)
.WithModifiers(
SF.TokenList([SF.Token(scope), SF.Token(SyntaxKind.PartialKeyword)])
)
.WithBaseList(
SF.BaseList(
SF.SingletonSeparatedList<BaseTypeSyntax>(
SF.SimpleBaseType(
SF.IdentifierName(jsonContextName)
)
)
)
);
}
}
private static AttributeSyntax GenerateAttributeWithTypeArgument(string fullyQualifiedTypeName)
{
return SF.Attribute(SF.IdentifierName("JsonSerializable"))
.WithArgumentList(SF.AttributeArgumentList(
SF.SingletonSeparatedList(
SF.AttributeArgument(SF.TypeOfExpression(SF.IdentifierName(fullyQualifiedTypeName))))));
}
}