@@ -61,6 +61,7 @@ export default class SchemaMerger {
6161
6262 // State tracking
6363 private readonly projects = { }
64+ private nugetRoot = ''
6465 private readonly validator = new Validator ( )
6566 private metaSchemaId = ''
6667 private metaSchema : any
@@ -295,7 +296,78 @@ export default class SchemaMerger {
295296 return ppath . normalize ( path )
296297 }
297298
298- // Expand .csproj packages and projects
299+ // Expand nuget package and all of its dependencies
300+ async expandNuget ( packageName : string , minVersion : string , root : boolean ) : Promise < string [ ] > {
301+ let packages : string [ ] = [ ]
302+ let pkgPath = ppath . join ( this . nugetRoot , packageName )
303+ if ( ! this . projects [ pkgPath ] && ! packageName . startsWith ( 'System' ) ) {
304+ let oldFile = this . currentFile
305+ try {
306+ this . currentFile = pkgPath
307+ this . projects [ pkgPath ] = true
308+ let versions : string [ ] = [ ]
309+ if ( await fs . pathExists ( pkgPath ) ) {
310+ for ( let pkgVersion of await fs . readdir ( pkgPath ) ) {
311+ versions . push ( pkgVersion . toLowerCase ( ) )
312+ }
313+ minVersion = minVersion || '0.0.0'
314+ // NOTE: The semver package does not handle more complex nuget range revisions
315+ // We get an exception and will ignore those dependencies.
316+ let version = semver . minSatisfying ( versions , minVersion )
317+ pkgPath = this . normalize ( ppath . join ( pkgPath , version || '' ) )
318+ this . currentFile = pkgPath
319+ packages . push ( pkgPath )
320+ if ( this . verbose ) {
321+ this . log ( ` Following nuget ${ this . prettyPath ( pkgPath ) } ` )
322+ }
323+ let nuspecPath = ppath . join ( pkgPath , `${ packageName } .nuspec` )
324+ if ( await fs . pathExists ( nuspecPath ) ) {
325+ let nuspec = await this . xmlToJSON ( nuspecPath )
326+ let dependencies : any [ ] = [ ]
327+ walkJSON ( nuspec , val => {
328+ if ( val . dependencies ) {
329+ // NOTE: We assume first framework with dependencies has schema files.
330+ for ( let groups of val . dependencies ) {
331+ if ( groups . dependency ) {
332+ // Direct dependencies
333+ for ( let dependency of groups . dependency ) {
334+ dependencies . push ( dependency . $ )
335+ }
336+ break
337+ } else {
338+ // Grouped dependencies
339+ for ( let group of groups . group ) {
340+ if ( group . dependency ) {
341+ for ( let dependency of group . dependency ) {
342+ dependencies . push ( dependency . $ )
343+ }
344+ break
345+ }
346+ }
347+ }
348+ }
349+ return true
350+ }
351+ return false
352+ } )
353+ for ( let dependent of dependencies ) {
354+ let dependentPackages = await this . expandNuget ( dependent . id , dependent . version , false )
355+ packages = [ ...packages , ...dependentPackages ]
356+ }
357+ }
358+ } else if ( root ) {
359+ this . parsingError ( ' Nuget package does not exist' )
360+ }
361+ } catch ( e ) {
362+ this . parsingWarning ( e . message )
363+ } finally {
364+ this . currentFile = oldFile
365+ }
366+ }
367+ return packages
368+ }
369+
370+ // Expand .csproj packages, nugets and projects
299371 async expandCSProj ( path : string ) : Promise < string [ ] > {
300372 let references : string [ ] = [ ]
301373 if ( ! this . projects [ path ] ) {
@@ -306,41 +378,30 @@ export default class SchemaMerger {
306378 }
307379 references . push ( this . normalize ( ppath . join ( ppath . dirname ( path ) , '/**/*.schema' ) ) )
308380 let json = await this . xmlToJSON ( path )
309- let packages = await this . findGlobalNuget ( )
310- if ( packages ) {
381+ await this . findGlobalNuget ( )
382+ if ( this . nugetRoot !== '' ) {
383+ let nugetPackages : any [ ] = [ ]
311384 walkJSON ( json , elt => {
312385 if ( elt . PackageReference ) {
313386 for ( let pkgRef of elt . PackageReference ) {
314- let pkg = pkgRef . $
315- let pkgName = pkg . Include
316- let pkgPath = ppath . join ( packages , pkgName )
317- let versions : string [ ] = [ ]
318- if ( fs . pathExistsSync ( pkgPath ) ) {
319- for ( let version of fs . readdirSync ( pkgPath ) ) {
320- versions . push ( version . toLowerCase ( ) )
321- }
322- let baseVersion = pkg . Version || '0.0.0'
323- let version = semver . minSatisfying ( versions , `>=${ baseVersion . toLowerCase ( ) } ` )
324- pkgPath = this . normalize ( ppath . join ( pkgPath , version || '' , '**/*.schema' ) )
325- references . push ( pkgPath )
326- if ( this . verbose ) {
327- this . log ( ` Following nuget ${ this . prettyPath ( pkgPath ) } ` )
328- }
329- } else {
330- this . parsingError ( `Nuget package does not exist ${ pkgPath } ` )
331- }
387+ nugetPackages . push ( pkgRef . $ )
332388 }
333389 return true
334390 }
335391 return false
336392 } )
393+ for ( let pkg of nugetPackages ) {
394+ let nugetReferences = await this . expandNuget ( pkg . Include , pkg . Version , true )
395+ for ( let nuget of nugetReferences ) {
396+ references . push ( this . normalize ( ppath . join ( nuget , '**/*.schema' ) ) )
397+ }
398+ }
337399 }
338400 let projects : string [ ] = [ ]
339401 walkJSON ( json , elt => {
340402 if ( elt . ProjectReference ) {
341403 for ( let ref of elt . ProjectReference ) {
342- let project = ref . $
343- let projectPath = this . normalize ( ppath . join ( ppath . dirname ( path ) , project . Include ) )
404+ let projectPath = this . normalize ( ppath . join ( ppath . dirname ( path ) , ref . $ . Include ) )
344405 projects . push ( projectPath )
345406 }
346407 return true
@@ -419,19 +480,20 @@ export default class SchemaMerger {
419480 }
420481
421482 // Find the global nuget repository
422- async findGlobalNuget ( ) : Promise < string > {
423- let result = ''
424- try {
425- const { stdout} = await exec ( 'dotnet nuget locals global-packages --list' )
426- const name = 'global-packages:'
427- let start = stdout . indexOf ( name )
428- if ( start > - 1 ) {
429- result = stdout . substring ( start + name . length ) . trim ( )
430- }
431- } catch {
432- this . parsingError ( 'Cannot find global nuget packages' )
483+ async findGlobalNuget ( ) : Promise < void > {
484+ if ( ! this . nugetRoot ) {
485+ this . nugetRoot = ''
486+ try {
487+ const { stdout} = await exec ( 'dotnet nuget locals global-packages --list' )
488+ const name = 'global-packages:'
489+ let start = stdout . indexOf ( name )
490+ if ( start > - 1 ) {
491+ this . nugetRoot = stdout . substring ( start + name . length ) . trim ( )
492+ }
493+ } catch {
494+ this . parsingError ( 'Cannot find global nuget packages' )
495+ }
433496 }
434- return result
435497 }
436498
437499 // Convert XML to JSON
0 commit comments