Skip to content

Commit d4c0621

Browse files
committed
Add script key tests and simplify internal logic
1 parent f2eb3b7 commit d4c0621

7 files changed

+64
-72
lines changed

src/Program.cs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@
1111
Environment.SetEnvironmentVariable("INIT_CWD", workingDirectory);
1212

1313
Project? project;
14-
Dictionary<string, string?> scripts;
1514
try
1615
{
17-
(project, scripts, workingDirectory) = await new ProjectLoader().LoadAsync(workingDirectory);
16+
(project, workingDirectory) = await new ProjectLoader().LoadAsync(workingDirectory);
1817
}
1918
catch (Exception ex)
2019
{
@@ -29,19 +28,18 @@
2928
rootCommand.AddGlobalOption(GlobalOptions.ScriptShell);
3029
rootCommand.AddGlobalOption(GlobalOptions.Verbose);
3130

32-
foreach (var (name, script) in scripts.OrderBy(s => s.Key))
31+
foreach (var (name, script) in project.Scripts!.OrderBy(s => s.Key))
3332
{
3433
var runScript = new RunScriptCommand(
3534
name,
3635
script,
37-
project.ScriptShell,
38-
scripts,
36+
project,
3937
workingDirectory);
4038

4139
rootCommand.AddCommand(runScript);
4240
}
4341

44-
if (!scripts.ContainsKey("env"))
42+
if (!project.Scripts!.ContainsKey("env"))
4543
{
4644
rootCommand.AddCommand(new EnvironmentCommand());
4745
}

src/Project.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
namespace RunScript;
22

3+
using System.Text.Json.Serialization;
4+
5+
using RunScript.Serialization;
6+
37
public class Project
48
{
59
public string? ScriptShell { get; set; }
610

11+
[JsonConverter(typeof(CaseInsensitiveDictionaryConverter<string?>))]
712
public Dictionary<string, string?>? Scripts { get; set; }
813
}

src/ProjectLoader.cs

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ namespace RunScript;
44

55
public class ProjectLoader
66
{
7-
public async Task<(Project, Dictionary<string, string?>, string)> LoadAsync(string executingDirectory)
7+
public async Task<(Project, string)> LoadAsync(string executingDirectory)
88
{
99
var jsonPath = CheckFolderForFile(executingDirectory, "global.json");
1010
if (jsonPath is null)
@@ -23,13 +23,12 @@ public class ProjectLoader
2323
throw new RunScriptException("Error parsing global.json");
2424
}
2525

26-
var scripts = LoadScripts(project);
27-
if (scripts is null)
26+
if (project.Scripts is null || project.Scripts.Count == 0)
2827
{
29-
throw new RunScriptException("Error loading scripts");
28+
throw new RunScriptException("No scripts found in the global.json");
3029
}
3130

32-
return (project, scripts, workingDirectory);
31+
return (project, workingDirectory);
3332
}
3433

3534
private string? CheckFolderForFile(string path, string file)
@@ -55,29 +54,17 @@ public class ProjectLoader
5554

5655
try
5756
{
58-
var globalJson = JsonSerializer.Deserialize<Project>(json, new JsonSerializerOptions
59-
{
60-
PropertyNameCaseInsensitive = true,
61-
ReadCommentHandling = JsonCommentHandling.Skip,
62-
});
63-
64-
return globalJson;
57+
return JsonSerializer.Deserialize<Project>(
58+
json,
59+
new JsonSerializerOptions
60+
{
61+
PropertyNameCaseInsensitive = true,
62+
ReadCommentHandling = JsonCommentHandling.Skip,
63+
});
6564
}
6665
catch
6766
{
6867
return null;
6968
}
7069
}
71-
72-
private static Dictionary<string, string?> LoadScripts(Project project)
73-
{
74-
if (project is null) throw new ArgumentNullException(nameof(project));
75-
76-
if (project.Scripts is null || project.Scripts.Count == 0)
77-
{
78-
throw new RunScriptException("No scripts found in the global.json");
79-
}
80-
81-
return new Dictionary<string, string?>(project.Scripts, StringComparer.OrdinalIgnoreCase);
82-
}
8370
}

src/RunScriptCommand.cs

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,21 @@ public class RunScriptCommand : Command, ICommandHandler
1414
private readonly bool _isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
1515
private readonly string? _comspec = Environment.GetEnvironmentVariable("COMSPEC");
1616

17-
private string? _projectScriptshell;
18-
private readonly IDictionary<string, string?> _scripts;
17+
private readonly Project _project;
1918
private readonly string _workingDirectory;
2019

2120
private readonly ImmutableArray<string> _scriptNames;
2221

2322
public RunScriptCommand(
2423
string name,
2524
string? description,
26-
string? projectScriptShell,
27-
IDictionary<string, string?> scripts,
25+
Project project,
2826
string workingDirectory)
2927
: base(name, description)
3028
{
3129
if (string.IsNullOrEmpty(workingDirectory)) throw new ArgumentException($"'{nameof(workingDirectory)}' cannot be null or empty.", nameof(workingDirectory));
3230

33-
_projectScriptshell = projectScriptShell;
34-
_scripts = scripts ?? throw new ArgumentNullException(nameof(scripts));
31+
_project = project ?? throw new ArgumentNullException(nameof(project));
3532
_workingDirectory = workingDirectory;
3633

3734
_scriptNames = ImmutableArray.Create(new[] { "pre" + Name, Name, "post" + Name });
@@ -47,16 +44,11 @@ public async Task<int> InvokeAsync(InvocationContext context)
4744
console.AlertAboutVerbose();
4845

4946
var scriptShell = context.ParseResult.GetValueForOption(GlobalOptions.ScriptShell);
50-
if (scriptShell is not null)
51-
{
52-
_projectScriptshell = scriptShell;
53-
}
54-
55-
var (shell, isCmd) = GetScriptShell();
47+
var (shell, isCmd) = GetScriptShell(scriptShell ?? _project.ScriptShell);
5648

5749
var ct = context.GetCancellationToken();
5850

59-
foreach (var script in _scriptNames.Where(scriptName => _scripts.ContainsKey(scriptName)).ToImmutableArray())
51+
foreach (var script in _scriptNames.Where(scriptName => _project.Scripts!.ContainsKey(scriptName)).ToImmutableArray())
6052
{
6153
var args = script == Name
6254
? context.ParseResult.UnparsedTokens
@@ -65,7 +57,7 @@ public async Task<int> InvokeAsync(InvocationContext context)
6557
var result = await RunScriptAsync(
6658
console,
6759
script,
68-
_scripts[script],
60+
_project.Scripts![script],
6961
shell,
7062
isCmd,
7163
args,
@@ -80,10 +72,8 @@ public async Task<int> InvokeAsync(InvocationContext context)
8072
return 0;
8173
}
8274

83-
private (string shell, bool isCmd) GetScriptShell()
75+
private (string shell, bool isCmd) GetScriptShell(string? shell)
8476
{
85-
var shell = _projectScriptshell;
86-
8777
shell ??= _isWindows
8878
? _comspec ?? "cmd"
8979
: "sh";
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
namespace RunScript.Serialization;
2+
3+
using System.Text.Json;
4+
using System.Text.Json.Serialization;
5+
6+
internal class CaseInsensitiveDictionaryConverter<TValue> : JsonConverter<Dictionary<string, TValue>>
7+
{
8+
public override Dictionary<string, TValue> Read(
9+
ref Utf8JsonReader reader,
10+
Type typeToConvert,
11+
JsonSerializerOptions options)
12+
{
13+
var dict = (Dictionary<string, TValue>)JsonSerializer
14+
.Deserialize(ref reader, typeToConvert, options)!;
15+
16+
return dict.ToDictionary(
17+
i => i.Key.ToLowerInvariant(),
18+
i => i.Value,
19+
StringComparer.OrdinalIgnoreCase);
20+
}
21+
22+
public override void Write(
23+
Utf8JsonWriter writer,
24+
Dictionary<string, TValue> value,
25+
JsonSerializerOptions options)
26+
=> JsonSerializer.Serialize(
27+
writer,
28+
value,
29+
value.GetType(),
30+
options);
31+
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
Scripts: {
3-
bUiLD: build,
3+
build: build,
44
pack: pack,
5-
TEST: test
5+
test: test
66
}
77
}

test/ProjectLoaderTests.cs

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -55,19 +55,13 @@ public async Task Should_find_in_root()
5555
var projectLoader = new ProjectLoader();
5656

5757
// When
58-
var (project, scripts, workingDirectory) = await projectLoader.LoadAsync(testPath);
58+
var (project, workingDirectory) = await projectLoader.LoadAsync(testPath);
5959

6060
// Then
6161
project.ShouldNotBeNull();
6262

6363
await Verify(project);
6464

65-
scripts.ShouldBeEquivalentTo(
66-
new Dictionary<string, string>
67-
{
68-
{ "test", "echo \"dir1\" && exit 1" },
69-
});
70-
7165
workingDirectory.ShouldBe(TestPath("dir1"));
7266
}
7367

@@ -79,18 +73,13 @@ public async Task Should_look_up_the_tree()
7973
var projectLoader = new ProjectLoader();
8074

8175
// When
82-
var (project, scripts, workingDirectory) = await projectLoader.LoadAsync(testPath);
76+
var (project, workingDirectory) = await projectLoader.LoadAsync(testPath);
8377

8478
// Then
8579
project.ShouldNotBeNull();
8680

8781
await Verify(project);
8882

89-
scripts.ShouldBeEquivalentTo(
90-
new Dictionary<string, string>
91-
{
92-
{ "test", "echo \"dir1\" && exit 1" },
93-
});
9483
workingDirectory.ShouldBe(TestPath("dir1"));
9584
}
9685

@@ -102,20 +91,12 @@ public async Task Should_treat_script_names_as_lowercase()
10291
var projectLoader = new ProjectLoader();
10392

10493
// When
105-
var (project, scripts, _) = await projectLoader.LoadAsync(testPath);
94+
var (project, _) = await projectLoader.LoadAsync(testPath);
10695

10796
// Then
108-
project.Scripts.ShouldNotBeNull();
109-
110-
project.Scripts["bUiLD"].ShouldBe("build");
111-
project.Scripts["TEST"].ShouldBe("test");
112-
project.Scripts["pack"].ShouldBe("pack");
97+
project.Scripts?.Comparer.ShouldBe(StringComparer.OrdinalIgnoreCase);
11398

11499
await Verify(project);
115-
116-
scripts["build"].ShouldBe("build");
117-
scripts["test"].ShouldBe("test");
118-
scripts["pack"].ShouldBe("pack");
119100
}
120101

121102
private string TestPath(params string[] folders)

0 commit comments

Comments
 (0)