@@ -25,6 +25,7 @@ public class LicenseAnalyzer : DiagnosticAnalyzer
2525
2626 public const string AllowedLicensesFileName = @"Allowed.Licenses.txt" ;
2727 public const string LicensesCacheFileName = @"licenses.json" ;
28+ private const string ProjectAssetsFileName = @"project.assets.json" ;
2829
2930 // Default acceptable licenses (permissive licenses that are generally safe to use)
3031 private static readonly HashSet < string > DefaultAcceptableLicenses = new ( StringComparer . OrdinalIgnoreCase )
@@ -185,17 +186,15 @@ private static string TryFindAssetsFileFromSourcePaths()
185186 // Look for project.assets.json in common locations
186187 var possiblePaths = new [ ]
187188 {
188- Path . Combine ( currentDir , "obj" , "project.assets.json" ) ,
189- Path . Combine ( currentDir , ".." , "obj" , "project.assets.json" ) ,
190- Path . Combine ( currentDir , ".." , ".." , "obj" , "project.assets.json" )
189+ Path . Combine ( currentDir , "obj" , ProjectAssetsFileName ) ,
190+ Path . Combine ( currentDir , ".." , "obj" , ProjectAssetsFileName ) ,
191+ Path . Combine ( currentDir , ".." , ".." , "obj" , ProjectAssetsFileName )
191192 } ;
192193
193- foreach ( var path in possiblePaths )
194+ var foundPath = possiblePaths . Where ( File . Exists ) . FirstOrDefault ( ) ;
195+ if ( foundPath != null )
194196 {
195- if ( File . Exists ( path ) )
196- {
197- return path ;
198- }
197+ return foundPath ;
199198 }
200199
201200 // If not found in common locations, search in current directory tree
@@ -204,7 +203,7 @@ private static string TryFindAssetsFileFromSourcePaths()
204203 var searchDir = currentDir ;
205204 for ( var i = 0 ; i < 5 ; i ++ ) // Limit search depth
206205 {
207- var assetsPath = Path . Combine ( searchDir , "obj" , "project.assets.json" ) ;
206+ var assetsPath = Path . Combine ( searchDir , "obj" , ProjectAssetsFileName ) ;
208207 if ( File . Exists ( assetsPath ) )
209208 {
210209 return assetsPath ;
@@ -269,6 +268,7 @@ private static void SaveLicenseCache(Dictionary<string, PackageLicenseInfo> cach
269268 catch ( Exception )
270269 {
271270 // If we can't write cache, just continue without caching
271+ return ;
272272 }
273273 }
274274
@@ -348,54 +348,79 @@ private static string ExtractLicenseFromNuspec(string nuspecPath)
348348 {
349349 var content = File . ReadAllText ( nuspecPath ) ;
350350
351- // Simple XML parsing to extract license information
352- // Look for <license> or <licenseUrl> elements
353- var licenseStart = content . IndexOf ( "<license" , StringComparison . OrdinalIgnoreCase ) ;
354- if ( licenseStart >= 0 )
351+ // Try to extract license from <license> element first
352+ var licenseFromElement = ExtractLicenseElement ( content ) ;
353+ if ( ! string . IsNullOrEmpty ( licenseFromElement ) )
355354 {
356- var typeStart = content . IndexOf ( "type=\" " , licenseStart , StringComparison . OrdinalIgnoreCase ) ;
357- if ( typeStart >= 0 )
358- {
359- typeStart += 6 ; // Skip 'type="'
360- var typeEnd = content . IndexOf ( "\" " , typeStart , StringComparison . OrdinalIgnoreCase ) ;
361- if ( typeEnd > typeStart )
362- {
363- var licenseType = content . Substring ( typeStart , typeEnd - typeStart ) ;
364- if ( licenseType . Equals ( "expression" , StringComparison . OrdinalIgnoreCase ) )
365- {
366- // Extract SPDX expression
367- var contentStart = content . IndexOf ( ">" , licenseStart ) + 1 ;
368- var contentEnd = content . IndexOf ( "</license>" , contentStart , StringComparison . OrdinalIgnoreCase ) ;
369- if ( contentEnd > contentStart )
370- {
371- return content . Substring ( contentStart , contentEnd - contentStart ) . Trim ( ) ;
372- }
373- }
374- }
375- }
355+ return licenseFromElement ;
376356 }
377357
378- // Fall back to looking for licenseUrl
379- var licenseUrlStart = content . IndexOf ( "<licenseUrl>" , StringComparison . OrdinalIgnoreCase ) ;
380- if ( licenseUrlStart >= 0 )
381- {
382- licenseUrlStart += 12 ; // Skip '<licenseUrl>'
383- var licenseUrlEnd = content . IndexOf ( "</licenseUrl>" , licenseUrlStart , StringComparison . OrdinalIgnoreCase ) ;
384- if ( licenseUrlEnd > licenseUrlStart )
385- {
386- var licenseUrl = content . Substring ( licenseUrlStart , licenseUrlEnd - licenseUrlStart ) . Trim ( ) ;
387- // Extract license name from common URLs
388- return ExtractLicenseFromUrl ( licenseUrl ) ;
389- }
390- }
358+ // Fall back to extracting from <licenseUrl> element
359+ return ExtractLicenseUrl ( content ) ;
391360 }
392361 catch ( Exception )
393362 {
394363 // If we can't parse the nuspec, return null
395364 return null ;
396365 }
366+ }
397367
398- return null ;
368+ private static string ExtractLicenseElement ( string content )
369+ {
370+ var licenseStart = content . IndexOf ( "<license" , StringComparison . OrdinalIgnoreCase ) ;
371+ if ( licenseStart < 0 )
372+ {
373+ return null ;
374+ }
375+
376+ var typeStart = content . IndexOf ( "type=\" " , licenseStart , StringComparison . OrdinalIgnoreCase ) ;
377+ if ( typeStart < 0 )
378+ {
379+ return null ;
380+ }
381+
382+ typeStart += 6 ; // Skip 'type="'
383+ var typeEnd = content . IndexOf ( "\" " , typeStart , StringComparison . OrdinalIgnoreCase ) ;
384+ if ( typeEnd <= typeStart )
385+ {
386+ return null ;
387+ }
388+
389+ var licenseType = content . Substring ( typeStart , typeEnd - typeStart ) ;
390+ if ( ! licenseType . Equals ( "expression" , StringComparison . OrdinalIgnoreCase ) )
391+ {
392+ return null ;
393+ }
394+
395+ // Extract SPDX expression
396+ var contentStart = content . IndexOf ( ">" , licenseStart ) + 1 ;
397+ var contentEnd = content . IndexOf ( "</license>" , contentStart , StringComparison . OrdinalIgnoreCase ) ;
398+ if ( contentEnd <= contentStart )
399+ {
400+ return null ;
401+ }
402+
403+ return content . Substring ( contentStart , contentEnd - contentStart ) . Trim ( ) ;
404+ }
405+
406+ private static string ExtractLicenseUrl ( string content )
407+ {
408+ var licenseUrlStart = content . IndexOf ( "<licenseUrl>" , StringComparison . OrdinalIgnoreCase ) ;
409+ if ( licenseUrlStart < 0 )
410+ {
411+ return null ;
412+ }
413+
414+ licenseUrlStart += 12 ; // Skip '<licenseUrl>'
415+ var licenseUrlEnd = content . IndexOf ( "</licenseUrl>" , licenseUrlStart , StringComparison . OrdinalIgnoreCase ) ;
416+ if ( licenseUrlEnd <= licenseUrlStart )
417+ {
418+ return null ;
419+ }
420+
421+ var licenseUrl = content . Substring ( licenseUrlStart , licenseUrlEnd - licenseUrlStart ) . Trim ( ) ;
422+ // Extract license name from common URLs
423+ return ExtractLicenseFromUrl ( licenseUrl ) ;
399424 }
400425
401426 private static string ExtractLicenseFromUrl ( string licenseUrl )
0 commit comments