@@ -10,10 +10,10 @@ namespace StructId;
1010
1111public static class CodeTemplate
1212{
13- public static SyntaxNode Parse ( string template )
13+ public static SyntaxNode Parse ( string template , CSharpParseOptions ? parseOptions = default )
1414 {
1515 var tree = CSharpSyntaxTree . ParseText ( template ,
16- CSharpParseOptions . Default . WithLanguageVersion ( LanguageVersion . Latest ) ) ;
16+ parseOptions ?? CSharpParseOptions . Default . WithLanguageVersion ( LanguageVersion . Latest ) ) ;
1717
1818 return tree . GetRoot ( ) ;
1919 }
@@ -30,6 +30,17 @@ public static string Apply(string template, string structIdType, string valueTyp
3030 applied . ToFullString ( ) ;
3131 }
3232
33+ public static string Apply ( string template , string valueType , bool normalizeWhitespace = false )
34+ {
35+ var applied = ApplyImpl ( Parse ( template ) , valueType ) ;
36+
37+ return normalizeWhitespace ?
38+ applied . NormalizeWhitespace ( ) . ToFullString ( ) . Trim ( ) :
39+ applied . ToFullString ( ) . Trim ( ) ;
40+ }
41+
42+ public static SyntaxNode ApplyValue ( this SyntaxNode node , INamedTypeSymbol valueType ) => ApplyImpl ( node , valueType . ToFullName ( ) ) ;
43+
3344 public static SyntaxNode Apply ( this SyntaxNode node , INamedTypeSymbol structId )
3445 {
3546 var root = node . SyntaxTree . GetCompilationUnitRoot ( ) ;
@@ -49,6 +60,17 @@ public static SyntaxNode Apply(this SyntaxNode node, INamedTypeSymbol structId)
4960 return ApplyImpl ( root , structId . Name , tid , targetNamespace , corens ) ;
5061 }
5162
63+ static SyntaxNode ApplyImpl ( this SyntaxNode node , string valueType )
64+ {
65+ var root = node . SyntaxTree . GetCompilationUnitRoot ( ) ;
66+ if ( root == null )
67+ return node ;
68+
69+ node = new ValueRewriter ( valueType ) . Visit ( root ) ! ;
70+
71+ return node ;
72+ }
73+
5274 static SyntaxNode ApplyImpl ( this SyntaxNode node , string structIdType , string valueType , string ? targetNamespace = default , string coreNamespace = "StructId" )
5375 {
5476 var root = node . SyntaxTree . GetCompilationUnitRoot ( ) ;
@@ -95,6 +117,84 @@ static SyntaxNode ApplyImpl(this SyntaxNode node, string structIdType, string va
95117 return node ;
96118 }
97119
120+ class ValueRewriter ( string tvalue ) : CSharpSyntaxRewriter
121+ {
122+ public override SyntaxNode ? VisitRecordDeclaration ( RecordDeclarationSyntax node )
123+ {
124+ if ( IsFileLocal ( node ) )
125+ return null ;
126+
127+ return node ;
128+ }
129+
130+ public override SyntaxNode ? VisitStructDeclaration ( StructDeclarationSyntax node )
131+ {
132+ if ( IsFileLocal ( node ) )
133+ return null ;
134+
135+ return base . VisitStructDeclaration ( node ) ;
136+ }
137+
138+ public override SyntaxNode ? VisitClassDeclaration ( ClassDeclarationSyntax node )
139+ {
140+ if ( IsFileLocal ( node ) )
141+ return null ;
142+
143+ return base . VisitClassDeclaration ( node ) ;
144+ }
145+
146+ public override SyntaxNode ? VisitAttribute ( AttributeSyntax node )
147+ {
148+ if ( node . IsValueTemplate ( ) )
149+ return null ;
150+
151+ return base . VisitAttribute ( node ) ;
152+ }
153+
154+ public override SyntaxNode ? VisitAttributeList ( AttributeListSyntax node )
155+ {
156+ node = ( AttributeListSyntax ) base . VisitAttributeList ( node ) ! ;
157+ if ( node . Attributes . Count == 0 )
158+ return null ;
159+
160+ return base . VisitAttributeList ( node ) ;
161+ }
162+
163+ public override SyntaxNode ? VisitIdentifierName ( IdentifierNameSyntax node )
164+ {
165+ if ( node . Identifier . Text == "TValue" )
166+ return IdentifierName ( tvalue )
167+ . WithLeadingTrivia ( node . Identifier . LeadingTrivia )
168+ . WithTrailingTrivia ( node . Identifier . TrailingTrivia ) ;
169+
170+ if ( node . Identifier . Text . StartsWith ( "TValue_" ) )
171+ return IdentifierName ( node . Identifier . Text . Replace ( "TValue_" , tvalue . Replace ( '.' , '_' ) + "_" ) )
172+ . WithLeadingTrivia ( node . Identifier . LeadingTrivia )
173+ . WithTrailingTrivia ( node . Identifier . TrailingTrivia ) ;
174+
175+ return base . VisitIdentifierName ( node ) ;
176+ }
177+
178+ public override SyntaxToken VisitToken ( SyntaxToken token )
179+ {
180+ if ( token . IsKind ( SyntaxKind . IdentifierToken ) && token . Text == "TValue" )
181+ return Identifier ( tvalue )
182+ . WithLeadingTrivia ( token . LeadingTrivia )
183+ . WithTrailingTrivia ( token . TrailingTrivia ) ;
184+
185+ if ( token . IsKind ( SyntaxKind . IdentifierToken ) && token . Text . StartsWith ( "TValue_" ) )
186+ return Identifier ( token . Text . Replace ( "TValue_" , tvalue . Replace ( '.' , '_' ) + "_" ) )
187+ . WithLeadingTrivia ( token . LeadingTrivia )
188+ . WithTrailingTrivia ( token . TrailingTrivia ) ;
189+
190+ return base . VisitToken ( token ) ;
191+ }
192+
193+ bool IsFileLocal ( TypeDeclarationSyntax node ) =>
194+ node . Modifiers . Any ( x => x . IsKind ( SyntaxKind . FileKeyword ) ) &&
195+ ! node . AttributeLists . Any ( list => list . Attributes . Any ( a => a . IsValueTemplate ( ) ) ) ;
196+ }
197+
98198 class TemplateRewriter ( string tself , string tid ) : CSharpSyntaxRewriter
99199 {
100200 public override SyntaxNode ? VisitRecordDeclaration ( RecordDeclarationSyntax node )
@@ -183,7 +283,7 @@ class TemplateRewriter(string tself, string tid) : CSharpSyntaxRewriter
183283 return IdentifierName ( tself )
184284 . WithLeadingTrivia ( node . Identifier . LeadingTrivia )
185285 . WithTrailingTrivia ( node . Identifier . TrailingTrivia ) ;
186- else if ( node . Identifier . Text == "TId" )
286+ else if ( node . Identifier . Text == "TId" || node . Identifier . Text == "TValue" )
187287 return IdentifierName ( tid )
188288 . WithLeadingTrivia ( node . Identifier . LeadingTrivia )
189289 . WithTrailingTrivia ( node . Identifier . TrailingTrivia ) ;
@@ -198,7 +298,7 @@ public override SyntaxToken VisitToken(SyntaxToken token)
198298 return Identifier ( tself )
199299 . WithLeadingTrivia ( token . LeadingTrivia )
200300 . WithTrailingTrivia ( token . TrailingTrivia ) ;
201- else if ( token . IsKind ( SyntaxKind . IdentifierToken ) && token . Text == "TId" )
301+ else if ( token . IsKind ( SyntaxKind . IdentifierToken ) && ( token . Text == "TId" || token . Text == "TValue" ) )
202302 return Identifier ( tid )
203303 . WithLeadingTrivia ( token . LeadingTrivia )
204304 . WithTrailingTrivia ( token . TrailingTrivia ) ;
0 commit comments