@@ -24,7 +24,7 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer
2424 /// Throws <see cref="InvalidDataException"/> for structural issues (missing hashtable, invalid
2525 /// values).
2626 /// </summary>
27- internal sealed class Psd1SettingsParser : ISettingsParser
27+ internal sealed class Psd1SettingsFormat : ISettingsFormat
2828 {
2929 public string FormatName => "psd1" ;
3030
@@ -33,30 +33,23 @@ internal sealed class Psd1SettingsParser : ISettingsParser
3333 /// </summary>
3434 /// <param name="pathOrExtension">Full path or just an extension string.</param>
3535 /// <returns>True if the extension is .psd1 (case-insensitive).</returns>
36- public bool CanParse ( string pathOrExtension ) =>
36+ public bool Supports ( string pathOrExtension ) =>
3737 string . Equals ( Path . GetExtension ( pathOrExtension ) , ".psd1" , StringComparison . OrdinalIgnoreCase ) ;
3838
3939 /// <summary>
40- /// Parses a .psd1 settings file into <see cref="SettingsData"/>.
40+ /// Deserializes a .psd1 settings file into <see cref="SettingsData"/>.
4141 /// </summary>
4242 /// <param name="content">
43- /// Stream for API symmetry; not directly consumed (PowerShell parser reads from file path) .
43+ /// The content of the .psd1 file as a string .
4444 /// </param>
4545 /// <param name="sourcePath">Absolute or relative path to the .psd1 file.</param>
4646 /// <returns>Normalized <see cref="SettingsData"/> instance.</returns>
47- /// <exception cref="FileNotFoundException">If the file does not exist.</exception>
4847 /// <exception cref="InvalidDataException">
4948 /// If no top-level hashtable is found or conversion yields invalid data.
5049 /// </exception>
51- public SettingsData Parse ( Stream content , string sourcePath )
50+ public SettingsData Deserialize ( string content , string sourcePath )
5251 {
53- // Need file path for PowerShell Parser.ParseFile
54- if ( ! File . Exists ( sourcePath ) )
55- {
56- throw new FileNotFoundException ( "Settings file not found." , sourcePath ) ;
57- }
58-
59- Ast ast = Parser . ParseFile ( sourcePath , out Token [ ] tokens , out ParseError [ ] errors ) ;
52+ Ast ast = Parser . ParseInput ( content , out Token [ ] tokens , out ParseError [ ] errors ) ;
6053
6154 if ( ast . FindAll ( a => a is HashtableAst , false ) . FirstOrDefault ( ) is not HashtableAst hashTableAst )
6255 {
@@ -87,7 +80,7 @@ public SettingsData Parse(Stream content, string sourcePath)
8780 /// </summary>
8881 /// <param name="settingsData">Settings to serialize.</param>
8982 /// <returns>Formatted .psd1 content as a string.</returns>
90- public string Serialise ( SettingsData settingsData )
83+ public string Serialize ( SettingsData settingsData )
9184 {
9285 if ( settingsData == null ) throw new ArgumentNullException ( nameof ( settingsData ) ) ;
9386
@@ -124,24 +117,40 @@ string FormatScalar(object value)
124117 } ;
125118 }
126119
120+ string FormatValue ( object value )
121+ {
122+ // Non-string enumerable -> PowerShell array literal
123+ if ( value is System . Collections . IEnumerable en && value is not string )
124+ {
125+ var items = new List < string > ( ) ;
126+ foreach ( var item in en )
127+ {
128+ // Treat nested enumerable of strings similarly; else fall back to scalar
129+ items . Add ( FormatScalar ( item ) ) ;
130+ }
131+ return items . Count == 0
132+ ? "@()"
133+ : "@(" + string . Join ( ", " , items ) + ")" ;
134+ }
135+ return FormatScalar ( value ) ;
136+ }
137+
127138 sb . AppendLine ( "@{" ) ;
128139
129- // Ordered sections
130140 AppendStringList ( "IncludeRules" , settingsData . IncludeRules ) ;
131141 AppendStringList ( "ExcludeRules" , settingsData . ExcludeRules ) ;
132142 AppendStringList ( "Severity" , settingsData . Severities ) ;
133143 AppendStringList ( "CustomRulePath" , settingsData . CustomRulePath ) ;
134144
135145 if ( settingsData . IncludeDefaultRules )
136146 {
137- sb . Append ( indent ) . Append ( "IncludeDefaultRules = " ) . AppendLine ( "$true" ) . AppendLine ( ) ;
147+ sb . Append ( indent ) . Append ( "IncludeDefaultRules = $true " ) . AppendLine ( ) . AppendLine ( ) ;
138148 }
139149 if ( settingsData . RecurseCustomRulePath )
140150 {
141- sb . Append ( indent ) . Append ( "RecurseCustomRulePath = " ) . AppendLine ( "$true" ) . AppendLine ( ) ;
151+ sb . Append ( indent ) . Append ( "RecurseCustomRulePath = $true " ) . AppendLine ( ) . AppendLine ( ) ;
142152 }
143153
144- // Rules block
145154 if ( settingsData . RuleArguments != null && settingsData . RuleArguments . Count > 0 )
146155 {
147156 sb . Append ( indent ) . AppendLine ( "Rules = @{" ) ;
@@ -154,7 +163,7 @@ string FormatScalar(object value)
154163 {
155164 sb . Append ( indent ) . Append ( indent ) . Append ( indent )
156165 . Append ( argKvp . Key ) . Append ( " = " )
157- . AppendLine ( FormatScalar ( argKvp . Value ) ) ;
166+ . AppendLine ( FormatValue ( argKvp . Value ) ) ;
158167 }
159168 }
160169 sb . Append ( indent ) . Append ( indent ) . AppendLine ( "}" ) . AppendLine ( ) ;
0 commit comments