33
44using System ;
55using System . Collections ;
6+ using System . Collections . Generic ;
67using System . IO ;
78using System . Linq ;
89using System . Management . Automation . Language ;
@@ -78,6 +79,92 @@ public SettingsData Parse(Stream content, string sourcePath)
7879
7980 return HashtableSettingsConverter . Convert ( raw ) ;
8081 }
81- }
8282
83+ /// <summary>
84+ /// Serializes a <see cref="SettingsData"/> instance into a formatted .psd1 settings file
85+ /// (PowerShell hashtable) similar to shipped presets.
86+ /// Omits empty collections and flags (if false) to keep output concise.
87+ /// </summary>
88+ /// <param name="settingsData">Settings to serialize.</param>
89+ /// <returns>Formatted .psd1 content as a string.</returns>
90+ public string Serialise ( SettingsData settingsData )
91+ {
92+ if ( settingsData == null ) throw new ArgumentNullException ( nameof ( settingsData ) ) ;
93+
94+ var sb = new System . Text . StringBuilder ( ) ;
95+ var indent = " " ;
96+
97+ string Quote ( string s ) => "'" + s . Replace ( "'" , "''" ) + "'" ;
98+
99+ void AppendStringList ( string key , List < string > list )
100+ {
101+ if ( list == null || list . Count == 0 ) return ;
102+ sb . Append ( indent ) . Append ( key ) . Append ( " = @(" ) . AppendLine ( ) ;
103+ for ( int i = 0 ; i < list . Count ; i ++ )
104+ {
105+ sb . Append ( indent ) . Append ( indent ) . Append ( Quote ( list [ i ] ) ) ;
106+ sb . AppendLine ( i == list . Count - 1 ? string . Empty : "," ) ;
107+ }
108+ sb . AppendLine ( indent + ")" ) . AppendLine ( ) ;
109+ }
110+
111+ string FormatScalar ( object value )
112+ {
113+ if ( value == null ) return "$null" ;
114+ return value switch
115+ {
116+ string s => Quote ( s ) ,
117+ bool b => b ? "$true" : "$false" ,
118+ Enum e => Quote ( e . ToString ( ) ) ,
119+ int or long or short or byte or sbyte or uint or ulong or ushort => Convert . ToString ( value , System . Globalization . CultureInfo . InvariantCulture ) ,
120+ float f => f . ToString ( System . Globalization . CultureInfo . InvariantCulture ) ,
121+ double d => d . ToString ( System . Globalization . CultureInfo . InvariantCulture ) ,
122+ decimal m => m . ToString ( System . Globalization . CultureInfo . InvariantCulture ) ,
123+ _ => Quote ( value . ToString ( ) )
124+ } ;
125+ }
126+
127+ sb . AppendLine ( "@{" ) ;
128+
129+ // Ordered sections
130+ AppendStringList ( "IncludeRules" , settingsData . IncludeRules ) ;
131+ AppendStringList ( "ExcludeRules" , settingsData . ExcludeRules ) ;
132+ AppendStringList ( "Severity" , settingsData . Severities ) ;
133+ AppendStringList ( "CustomRulePath" , settingsData . CustomRulePath ) ;
134+
135+ if ( settingsData . IncludeDefaultRules )
136+ {
137+ sb . Append ( indent ) . Append ( "IncludeDefaultRules = " ) . AppendLine ( "$true" ) . AppendLine ( ) ;
138+ }
139+ if ( settingsData . RecurseCustomRulePath )
140+ {
141+ sb . Append ( indent ) . Append ( "RecurseCustomRulePath = " ) . AppendLine ( "$true" ) . AppendLine ( ) ;
142+ }
143+
144+ // Rules block
145+ if ( settingsData . RuleArguments != null && settingsData . RuleArguments . Count > 0 )
146+ {
147+ sb . Append ( indent ) . AppendLine ( "Rules = @{" ) ;
148+ foreach ( var ruleKvp in settingsData . RuleArguments )
149+ {
150+ sb . Append ( indent ) . Append ( indent ) . Append ( ruleKvp . Key ) . Append ( " = @{" ) . AppendLine ( ) ;
151+ if ( ruleKvp . Value != null && ruleKvp . Value . Count > 0 )
152+ {
153+ foreach ( var argKvp in ruleKvp . Value )
154+ {
155+ sb . Append ( indent ) . Append ( indent ) . Append ( indent )
156+ . Append ( argKvp . Key ) . Append ( " = " )
157+ . AppendLine ( FormatScalar ( argKvp . Value ) ) ;
158+ }
159+ }
160+ sb . Append ( indent ) . Append ( indent ) . AppendLine ( "}" ) . AppendLine ( ) ;
161+ }
162+ sb . Append ( indent ) . AppendLine ( "}" ) ;
163+ }
164+
165+ sb . AppendLine ( "}" ) ;
166+
167+ return sb . ToString ( ) ;
168+ }
169+ }
83170}
0 commit comments