11using System . Diagnostics . CodeAnalysis ;
22using System . Text . RegularExpressions ;
3+ using System . Threading . Channels ;
34namespace System . Management . Generator ;
45
5- internal partial class DefinitionLoader ( IEnumerable < string > classNames )
6+ internal partial class DefinitionLoader ( ChannelWriter < ClassDefinition > channel )
67{
78
89 [ GeneratedRegex ( @"<code class=""lang-syntax"">([^<]*)</code>" ) ]
@@ -33,68 +34,56 @@ internal partial class DefinitionLoader(IEnumerable<string> classNames)
3334 private static partial Regex GetLinkRegex ( ) ;
3435 private static readonly Regex LinkRegex = GetLinkRegex ( ) ;
3536
36- private readonly Dictionary < string , ClassDefinition > _classDefinitions = classNames . ToDictionary ( n => n , n => default ( ClassDefinition ) , StringComparer . OrdinalIgnoreCase ) ;
37- public IEnumerable < ClassDefinition > LoadedClassDefinitions => _classDefinitions . Values ;
37+ private readonly Dictionary < string , string > _typeMismatches = new ( ) { [ "Win32_LogicalElement" ] = "CIM_LogicalElement" } ;
38+ private readonly HashSet < string > _loadedClassDefinitions = new ( StringComparer . OrdinalIgnoreCase ) ;
3839
39- private string ? CheckClass ( string ? className )
40+ public async Task Load ( IEnumerable < string > classesToLoad )
4041 {
41- if ( className == null )
42+ foreach ( var className in classesToLoad )
4243 {
43- return null ;
44+ await TryLoadClass ( className ) ;
4445 }
4546
46- if ( "Win32_LogicalElement" . Equals ( className ) )
47+ channel . Complete ( ) ;
48+ }
49+
50+ private async Task < string ? > TryLoadClass ( string ? className )
51+ {
52+ if ( className == null )
4753 {
48- return CheckClass ( "CIM_LogicalElement" ) ;
54+ return null ;
4955 }
5056
51- if ( ! _classDefinitions . ContainsKey ( className ) )
57+ if ( _typeMismatches . TryGetValue ( className , out var correctClassName ) )
5258 {
53- if ( className . IndexOf ( '_' ) == - 1 )
54- {
55- return CheckClass ( $ "__{ className } ") ;
56- }
57-
58- _classDefinitions . Add ( className , default ) ;
59- Console . WriteLine ( $ "Met new class { className } .") ;
59+ return await TryLoadClass ( correctClassName ) ;
6060 }
61- return className ;
62- }
6361
64- public async Task Load ( )
65- {
66- foreach ( var className in GetUnloadedClassNames ( ) )
62+ if ( _loadedClassDefinitions . Add ( className ) )
6763 {
6864 if ( await LoadClassDefinition ( className ) is ClassDefinition classDefinition )
6965 {
70- _classDefinitions [ className ] = classDefinition ;
66+ Console . WriteLine ( $ "Loaded info for { className } :") ;
67+ await channel . WriteAsync ( classDefinition ) ;
68+ return className ;
7169 }
72- else
70+ else if ( className . IndexOf ( '_' ) == - 1 )
7371 {
74- _classDefinitions . Remove ( className ) ;
72+ var prefixedClassName = $ "__{ className } ";
73+ _typeMismatches [ className ] = prefixedClassName ;
74+ return await TryLoadClass ( prefixedClassName ) ;
7575 }
7676 }
77- }
7877
79- private IEnumerable < string > GetUnloadedClassNames ( )
80- {
81- var classNames = _classDefinitions . Where ( kvp => kvp . Value . ClassName == null ) . Select ( kvp => kvp . Key ) . ToArray ( ) ;
82- while ( classNames . Length > 0 )
83- {
84- foreach ( var className in classNames )
85- {
86- yield return className ;
87- }
88- classNames = _classDefinitions . Where ( kvp => kvp . Value . ClassName == null ) . Select ( kvp => kvp . Key ) . ToArray ( ) ;
89- }
78+ return null ;
9079 }
9180
9281 private async Task < ClassDefinition ? > LoadClassDefinition ( string className )
9382 {
94- Console . WriteLine ( $ "Getting info for { className } :") ;
83+ Console . WriteLine ( $ "Loading info for { className } :") ;
9584 Uri ? classUri = null ;
9685 Uri [ ] uris = className [ 0 ] == '_'
97- ? [ new Uri ( $ "https://learn.microsoft.com/en-gb /windows/win32/wmisdk/{ className . Replace ( '_' , '-' ) } ") ]
86+ ? [ new Uri ( $ "https://learn.microsoft.com/en-us /windows/win32/wmisdk/{ className . Replace ( '_' , '-' ) } ") ]
9887 : [ new Uri ( $ "https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/{ className . Replace ( '_' , '-' ) } ") ,
9988 new Uri ( $ "https://learn.microsoft.com/en-us/previous-versions/windows/desktop/secrcw32prov//{ className . Replace ( '_' , '-' ) } ") ] ;
10089
@@ -111,15 +100,14 @@ private IEnumerable<string> GetUnloadedClassNames()
111100 {
112101 if ( i + 1 == uris . Length )
113102 {
114- ErrorReporter . Report ( $ "Unable to find Microsoft Learn page to parse for { className } : { ex . Message } ", ex ) ;
103+ ErrorReporter . Report ( $ "Unable to find Microsoft Learn page to parse for { className } : { ex . Message } ", ex , throwOrBreak : false ) ;
115104 break ;
116105 }
117106 }
118107 }
119108
120109 if ( classUri == null || pageContents == null )
121110 {
122- ErrorReporter . Report ( $ "Failed to load { className } .") ;
123111 return null ;
124112 }
125113
@@ -151,14 +139,14 @@ private IEnumerable<string> GetUnloadedClassNames()
151139 ErrorReporter . Report ( $ "Encounterd different type { classDef [ 1 ] } when parsing data for { className } .") ;
152140 }
153141
154- superClass = CheckClass ( classDef . Length > 2 ? classDef [ ^ 1 ] : null ) ;
142+ superClass = await TryLoadClass ( classDef . Length > 2 ? classDef [ ^ 1 ] : null ) ;
155143
156144 break ;
157145 }
158146
159147 var propertyBlock = pageContents . IndexOf ( "<h3 id=\" properties\" " ) ;
160148 var endBlock = pageContents . IndexOf ( "<h3" , propertyBlock + 1 ) ;
161- var properties = propertyBlock == - 1 ? [ ] : ParseProperties ( codeLines [ ( lineIndex + 2 ) ..^ 1 ] , pageContents [ propertyBlock ..endBlock ] ) . ToList ( ) ;
149+ var properties = propertyBlock == - 1 ? [ ] : await ParseProperties ( codeLines [ ( lineIndex + 2 ) ..^ 1 ] , pageContents [ propertyBlock ..endBlock ] ) ;
162150
163151 var methodBlock = pageContents . IndexOf ( "<h3 id=\" methods\" " ) ;
164152 endBlock = pageContents . IndexOf ( "<h3" , methodBlock + 1 ) ;
@@ -177,31 +165,37 @@ private static async Task<string> GetPageContentsAsync(Uri url)
177165 return await response . Content . ReadAsStringAsync ( ) ;
178166 }
179167
180- private IEnumerable < PropertyDefinition > ParseProperties ( string [ ] propertyLines , string propertiesBlock )
168+ private async Task < List < PropertyDefinition > > ParseProperties ( string [ ] propertyLines , string propertiesBlock )
181169 {
182- foreach ( var property in propertyLines . Select ( ParsePropertyLine ) . OfType < PropertyDefinition > ( ) )
170+ var result = new List < PropertyDefinition > ( propertyLines . Length ) ;
171+ foreach ( var propertyLine in propertyLines )
183172 {
184- if ( TryGetPropertyV1 ( property . Name , propertiesBlock , out var propertyBlock ) )
173+ if ( await ParsePropertyLine ( propertyLine ) is PropertyDefinition property )
185174 {
186- if ( PropertyIsInherited ( propertyBlock ) )
175+ if ( TryGetPropertyV1 ( property . Name , propertiesBlock , out var propertyBlock ) )
187176 {
188- continue ;
177+ if ( PropertyIsInherited ( propertyBlock ) )
178+ {
179+ continue ;
180+ }
181+ result . Add ( await UpdatePropertyV1 ( property , propertyBlock ) ) ;
189182 }
190- yield return UpdatePropertyV1 ( property , propertyBlock ) ;
191- }
192- else if ( TryGetPropertyV2 ( property . Name , propertiesBlock , out propertyBlock ) )
193- {
194- if ( PropertyIsInherited ( propertyBlock ) )
183+ else if ( TryGetPropertyV2 ( property . Name , propertiesBlock , out propertyBlock ) )
195184 {
196- continue ;
185+ if ( PropertyIsInherited ( propertyBlock ) )
186+ {
187+ continue ;
188+ }
189+ result . Add ( await UpdatePropertyV2 ( property , propertyBlock ) ) ;
190+ }
191+ else
192+ {
193+ ErrorReporter . Report ( $ "No description found for property { property . Name } .", throwOrBreak : false ) ;
197194 }
198- yield return UpdatePropertyV2 ( property , propertyBlock ) ;
199- }
200- else
201- {
202- ErrorReporter . Report ( $ "No description found for property { property . Name } .", throwOrBreak : false ) ;
203195 }
204196 }
197+
198+ return result ;
205199 }
206200
207201 private static bool TryGetPropertyV1 ( string propertyName , string propertiesBlock , [ MaybeNullWhen ( false ) ] out string propertyBlock )
@@ -235,11 +229,12 @@ private static bool TryGetPropertyV2(string propertyName, string propertiesBlock
235229 private static bool PropertyIsInherited ( string propertyBlock )
236230 => propertyBlock . Contains ( "This property is inherited from" ) ;
237231
238- private PropertyDefinition UpdatePropertyV1 ( PropertyDefinition property , string propertyBlock )
232+ private async Task < PropertyDefinition > UpdatePropertyV1 ( PropertyDefinition property , string propertyBlock )
239233 {
240234 foreach ( var paragraph in ParagraphRegex . Matches ( propertyBlock ) . Select ( TrimHTML ) )
241235 {
242- if ( ! ParseSubProperty ( ref property , paragraph ) )
236+ ( var parsed , property ) = await ParseSubProperty ( property , paragraph ) ;
237+ if ( ! parsed )
243238 {
244239 property = property with { Description = paragraph } ;
245240 break ;
@@ -249,11 +244,11 @@ private PropertyDefinition UpdatePropertyV1(PropertyDefinition property, string
249244 return property ;
250245 }
251246
252- private PropertyDefinition UpdatePropertyV2 ( PropertyDefinition property , string propertyBlock )
247+ private async Task < PropertyDefinition > UpdatePropertyV2 ( PropertyDefinition property , string propertyBlock )
253248 {
254249 foreach ( var propertyDescription in PropertyRegex . Matches ( propertyBlock ) . Select ( TrimHTML ) )
255250 {
256- ParseSubProperty ( ref property , propertyDescription ) ;
251+ ( _ , property ) = await ParseSubProperty ( property , propertyDescription ) ;
257252 }
258253
259254 if ( TrimHTML ( DescriptionRegex . Match ( propertyBlock ) ) is string description && description . Length > 0 )
@@ -264,12 +259,12 @@ private PropertyDefinition UpdatePropertyV2(PropertyDefinition property, string
264259 return property ;
265260 }
266261
267- private bool ParseSubProperty ( ref PropertyDefinition property , string paragraph )
262+ private async Task < ( bool , PropertyDefinition ) > ParseSubProperty ( PropertyDefinition property , string paragraph )
268263 {
269264 var colonIndex = paragraph . IndexOf ( ':' ) ;
270265 if ( colonIndex == - 1 )
271266 {
272- return false ;
267+ return ( false , property ) ;
273268 }
274269
275270 switch ( paragraph [ ..colonIndex ] )
@@ -289,7 +284,7 @@ private bool ParseSubProperty(ref PropertyDefinition property, string paragraph)
289284 }
290285 else if ( typeName . Contains ( '_' ) )
291286 {
292- property = property with { Type = CimType . Reference , ReferencedClass = CheckClass ( typeName ) } ;
287+ property = property with { Type = CimType . Reference , ReferencedClass = await TryLoadClass ( typeName ) } ;
293288 }
294289 else
295290 {
@@ -314,7 +309,7 @@ private bool ParseSubProperty(ref PropertyDefinition property, string paragraph)
314309 property = property with { Qualifiers = ParseQualifiers ( paragraph [ ( colonIndex + 2 ) ..] ) } ;
315310 break ;
316311 }
317- return true ;
312+ return ( true , property ) ;
318313 }
319314
320315 private static List < QualifierDefinition > ParseQualifiers ( string qualifiers )
@@ -334,7 +329,7 @@ private static string TrimHTML(string source)
334329 . Replace ( " " , " " )
335330 . Trim ( ) ;
336331
337- private PropertyDefinition ? ParsePropertyLine ( string propertyLine )
332+ private async Task < PropertyDefinition ? > ParsePropertyLine ( string propertyLine )
338333 {
339334 var parts = TrimHTML ( propertyLine ) . Split ( ' ' , options : StringSplitOptions . RemoveEmptyEntries ) ;
340335
@@ -347,7 +342,7 @@ private static string TrimHTML(string source)
347342 if ( ! Enum . TryParse ( parts [ 0 ] , ignoreCase : true , out CimType type ) && parts [ 0 ] . Contains ( '_' ) )
348343 {
349344 type = CimType . Reference ;
350- referenceType = CheckClass ( parts [ 0 ] ) ;
345+ referenceType = await TryLoadClass ( parts [ 0 ] ) ;
351346 }
352347
353348 var name = parts [ ^ 2 ] [ 0 ] == '=' ? parts [ ^ 3 ] : parts [ ^ 1 ] ;
0 commit comments