Skip to content

Commit c92738a

Browse files
committed
Change from 'Parser' to 'Format'
'Parser' has one-way connotations. Settle on 'Serialize' over 'Serialise' (as the rest of the project is in American English and mine and copilots mixed usage was getting confusing). Stream -> string in the Deserialize interface method as it wasn't helpful like I thought it might be
1 parent 03acbd6 commit c92738a

File tree

4 files changed

+75
-80
lines changed

4 files changed

+75
-80
lines changed

Engine/Settings/ISettingsFormat.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
namespace Microsoft.Windows.PowerShell.ScriptAnalyzer
5+
{
6+
/// <summary>
7+
/// Interface for settings file formats
8+
/// </summary>
9+
public interface ISettingsFormat
10+
{
11+
/// <summary>
12+
/// Format identifier (extension without dot, e.g. 'json', 'psd1').
13+
/// </summary>
14+
string FormatName { get; }
15+
16+
/// <summary>
17+
/// Whether this format can handle the specified path
18+
/// </summary>
19+
/// <param name="path">Full path or filename.</param>
20+
/// <returns>True if this format can handle the path.</returns>
21+
bool Supports(string path);
22+
23+
/// <summary>
24+
/// Deserialises the content stream into <see cref="SettingsData"/>.
25+
/// </summary>
26+
/// <param name="content">The content to parse.</param>
27+
/// <returns>The parsed SettingsData.</returns>
28+
SettingsData Deserialize(string content, string sourcePath);
29+
30+
/// <summary>
31+
/// Serializes the <see cref="SettingsData"/> into a string representation.
32+
/// </summary>
33+
/// <param name="settingsData"></param>
34+
/// <returns></returns>
35+
string Serialize(SettingsData settingsData);
36+
37+
}
38+
}

Engine/Settings/ISettingsParser.cs

Lines changed: 0 additions & 43 deletions
This file was deleted.

Engine/Settings/JsonSettingsParser.cs renamed to Engine/Settings/JsonSettingsFormat.cs

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer
1111
{
1212

1313
/// <summary>
14-
/// Parses JSON settings files (extension .json) into <see cref="SettingsData"/>.
14+
/// Handles JSON settings files (extension .json).
1515
/// Expected top-level properties:
1616
/// Severity : string or string array
1717
/// IncludeRules : string or string array
@@ -20,15 +20,8 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer
2020
/// IncludeDefaultRules : bool
2121
/// RecurseCustomRulePath : bool
2222
/// Rules : object with ruleName -> { argumentName : value } mapping
23-
/// Parsing logic:
24-
/// 1. Read entire stream into a string.
25-
/// 2. Deserialize to DTO with Newtonsoft.Json (case-insensitive by default).
26-
/// 3. Validate null result -> invalid data.
27-
/// 4. Normalize each collection to empty lists when absent.
28-
/// 5. Rebuild rule arguments as case-insensitive dictionaries.
29-
/// Throws <see cref="InvalidDataException"/> on malformed JSON or missing structure.
3023
/// </summary>
31-
internal sealed class JsonSettingsParser : ISettingsParser
24+
internal sealed class JsonSettingsFormat : ISettingsFormat
3225
{
3326

3427
/// <summary>
@@ -48,12 +41,12 @@ private sealed class JsonSettingsDto
4841
public string FormatName => "json";
4942

5043
/// <summary>
51-
/// Determines if this parser can handle the supplied path by checking for .json extension.
44+
/// Determines if this format can handle the supplied path by checking for .json extension.
5245
/// </summary>
53-
/// <param name="pathOrExtension">File path or extension string.</param>
46+
/// <param name="path">File path</param>
5447
/// <returns>True if extension is .json.</returns>
55-
public bool CanParse(string pathOrExtension) =>
56-
string.Equals(Path.GetExtension(pathOrExtension), ".json", StringComparison.OrdinalIgnoreCase);
48+
public bool Supports(string path) =>
49+
string.Equals(Path.GetExtension(path), ".json", StringComparison.OrdinalIgnoreCase);
5750

5851
/// <summary>
5952
/// Parses a JSON settings file stream into <see cref="SettingsData"/>.
@@ -64,14 +57,12 @@ public bool CanParse(string pathOrExtension) =>
6457
/// <exception cref="InvalidDataException">
6558
/// Thrown on JSON deserialization error or invalid/empty root object.
6659
/// </exception>
67-
public SettingsData Parse(Stream content, string sourcePath)
60+
public SettingsData Deserialize(string content, string sourcePath)
6861
{
69-
using var reader = new StreamReader(content);
70-
string json = reader.ReadToEnd();
7162
JsonSettingsDto dto;
7263
try
7364
{
74-
dto = JsonConvert.DeserializeObject<JsonSettingsDto>(json);
65+
dto = JsonConvert.DeserializeObject<JsonSettingsDto>(content);
7566
}
7667
catch (JsonException je)
7768
{
@@ -112,7 +103,7 @@ public SettingsData Parse(Stream content, string sourcePath)
112103
/// <param name="pretty">True for indented JSON, false for minified.</param>
113104
/// <returns>JSON string suitable for saving as PSScriptAnalyzerSettings.json.</returns>
114105
/// <exception cref="ArgumentNullException">If <paramref name="data"/> is null.</exception>
115-
public string Serialise(SettingsData data)
106+
public string Serialize(SettingsData data)
116107
{
117108
if (data == null) throw new ArgumentNullException(nameof(data));
118109

Engine/Settings/Psd1SettingsParser.cs renamed to Engine/Settings/Psd1SettingsFormat.cs

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)