@@ -25,8 +25,7 @@ public class AssemblyGenerator
25
25
readonly string _outputRoot ;
26
26
readonly IFileSystem _fileSystem ;
27
27
28
- public AssemblyGenerator
29
- (
28
+ public AssemblyGenerator (
30
29
string outputRoot ,
31
30
IFileSystem fileSystem = null
32
31
)
@@ -102,6 +101,7 @@ void Save(string packageOutputRoot, ISymbolMap symbols, Assembly assembly, strin
102
101
103
102
SaveProjectFile ( ) ;
104
103
SaveAssemblyInfo ( assembly . Name , assembly . Version , tarballFileName ) ;
104
+ SaveDependencyAnchorFile ( ) ;
105
105
106
106
foreach ( Type type in assembly . Types ? . Values ?? Enumerable . Empty < Type > ( ) )
107
107
{
@@ -185,6 +185,64 @@ IEnumerable<KeyValuePair<string, PackageVersion>> GetDependenciesCore(Dependency
185
185
}
186
186
}
187
187
188
+ void SaveDependencyAnchorFile ( )
189
+ {
190
+ string anchorNamespace = $ "{ assembly . GetNativeNamespace ( ) } .Internal.DependencyResolution";
191
+ var syntaxTree = SF . SyntaxTree (
192
+ SF . CompilationUnit (
193
+ SF . List < ExternAliasDirectiveSyntax > ( ) ,
194
+ SF . List < UsingDirectiveSyntax > ( ) ,
195
+ SF . List < AttributeListSyntax > ( ) ,
196
+ SF . List < MemberDeclarationSyntax > ( new [ ] {
197
+ SF . NamespaceDeclaration (
198
+ SF . IdentifierName ( anchorNamespace ) ,
199
+ SF . List < ExternAliasDirectiveSyntax > ( ) ,
200
+ SF . List < UsingDirectiveSyntax > ( ) ,
201
+ SF . List ( new MemberDeclarationSyntax [ ] { GenerateDependencyAnchor ( ) } )
202
+ )
203
+ } )
204
+ ) . NormalizeWhitespace ( elasticTrivia : true )
205
+ ) ;
206
+
207
+ string directory = GetNamespaceDirectory ( packageOutputRoot , @anchorNamespace ) ;
208
+ SaveSyntaxTree ( directory , "Anchor.cs" , syntaxTree ) ;
209
+
210
+ ClassDeclarationSyntax GenerateDependencyAnchor ( ) {
211
+ return SF . ClassDeclaration (
212
+ SF . List < AttributeListSyntax > ( ) ,
213
+ SF . TokenList ( SF . Token ( SyntaxKind . PublicKeyword ) ) ,
214
+ SF . Identifier ( "Anchor" ) ,
215
+ null ,
216
+ null ,
217
+ SF . List < TypeParameterConstraintClauseSyntax > ( ) ,
218
+ SF . List ( new MemberDeclarationSyntax [ ] {
219
+ SF . ConstructorDeclaration (
220
+ SF . List < AttributeListSyntax > ( ) ,
221
+ SF . TokenList ( SF . Token ( SyntaxKind . PublicKeyword ) ) ,
222
+ SF . Identifier ( "Anchor" ) ,
223
+ SF . ParameterList ( SF . SeparatedList < ParameterSyntax > ( ) ) ,
224
+ null ,
225
+ SF . Block ( SF . List ( GenerateAnchorReferences ( ) ) ) ,
226
+ null
227
+ )
228
+ } )
229
+ ) ;
230
+
231
+ IEnumerable < StatementSyntax > GenerateAnchorReferences ( )
232
+ {
233
+ return assembly . Dependencies ? . Keys
234
+ . Select ( k => assembly . GetNativeNamespace ( k ) )
235
+ . Select ( n => $ "{ n } .Internal.DependencyResolution.Anchor")
236
+ . Select ( t => SF . ExpressionStatement ( SF . ObjectCreationExpression (
237
+ SF . Token ( SyntaxKind . NewKeyword ) ,
238
+ SF . ParseTypeName ( t ) ,
239
+ SF . ArgumentList ( SF . SeparatedList < ArgumentSyntax > ( ) ) ,
240
+ null
241
+ ) ) ) ?? Enumerable . Empty < StatementSyntax > ( ) ;
242
+ }
243
+ }
244
+ }
245
+
188
246
void SaveAssemblyInfo ( string name , string version , string tarball )
189
247
{
190
248
SyntaxTree assemblyInfo = SF . SyntaxTree (
@@ -217,14 +275,8 @@ void SaveAssemblyInfo(string name, string version, string tarball)
217
275
218
276
void SaveType ( Type type )
219
277
{
220
- string packageName = Path . GetFileName ( packageOutputRoot ) ;
221
278
string @namespace = symbols . GetNamespace ( type ) ;
222
- if ( @namespace . StartsWith ( packageName ) )
223
- {
224
- @namespace = @namespace . Substring ( packageName . Length ) . TrimStart ( '.' ) ;
225
- }
226
-
227
- string directory = Path . Combine ( packageOutputRoot , Path . Combine ( @namespace . Split ( '.' ) ) ) ;
279
+ string directory = GetNamespaceDirectory ( packageOutputRoot , @namespace ) ;
228
280
229
281
switch ( type . Kind )
230
282
{
@@ -252,17 +304,37 @@ void SaveType(Type type)
252
304
253
305
void SaveTypeFile ( string filename , SyntaxTree syntaxTree )
254
306
{
255
- if ( ! _fileSystem . Directory . Exists ( directory ) )
256
- {
257
- _fileSystem . Directory . CreateDirectory ( directory ) ;
258
- }
307
+ SaveSyntaxTree ( directory , filename , syntaxTree ) ;
308
+ }
309
+ }
259
310
260
- _fileSystem . File . WriteAllText (
261
- Path . Combine ( directory , filename ) ,
262
- syntaxTree . ToString ( )
263
- ) ;
311
+ void SaveSyntaxTree ( string directory , string filename , SyntaxTree syntaxTree )
312
+ {
313
+ if ( ! _fileSystem . Directory . Exists ( directory ) )
314
+ {
315
+ _fileSystem . Directory . CreateDirectory ( directory ) ;
264
316
}
317
+
318
+ _fileSystem . File . WriteAllText (
319
+ Path . Combine ( directory , filename ) ,
320
+ syntaxTree . ToString ( )
321
+ ) ;
322
+ }
323
+ }
324
+
325
+ string GetNamespaceDirectory ( string packageOutputRoot , string @namespace )
326
+ {
327
+ string packageName = Path . GetFileName ( packageOutputRoot ) ;
328
+
329
+ // packageOutputRoot is typically a directory like My.Root.Namespace/
330
+ // We don't want to create redundant directories, i.e.
331
+ // My.Root.Namespace/My/Root/Namespace/Sub/Namespace. We just
332
+ // want My.Root.Namespace/Sub/Namespace.
333
+ if ( @namespace . StartsWith ( packageName ) ) {
334
+ @namespace = @namespace . Substring ( packageName . Length ) . TrimStart ( '.' ) ;
265
335
}
336
+
337
+ return Path . Combine ( packageOutputRoot , Path . Combine ( @namespace . Split ( '.' ) ) ) ;
266
338
}
267
339
}
268
340
}
0 commit comments