Skip to content

Commit e3b3803

Browse files
authored
JSON escape (#155)
* feat: escape strings in C# Automatically infer correct C# escaping for strings * feat: ignore local CI output
1 parent 1a98e2f commit e3b3803

10 files changed

Lines changed: 43 additions & 20 deletions

File tree

.github/workflows/sync.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ jobs:
4343
with:
4444
name: sync-artifacts
4545
path: |
46-
v1/*.json
47-
v2/*.json
46+
ci/v1/*.json
47+
ci/v2/*.json
4848
sync.log
4949
5050
- name: Capture error log

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,3 +370,6 @@ docs/README.md
370370

371371
# Ignore OpenAPI documents
372372
docs/openapi/*.json
373+
374+
# Ignore CI files
375+
/ci/

src/Helldivers-2-CI/Program.cs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,17 @@ await Task.WhenAll([
6666
var dispatchesv2 = await app.Services.GetRequiredService<IStore<Helldivers.Models.V2.Dispatch, int>>().AllAsync(maxRuntime.Token);
6767
var store = await app.Services.GetRequiredService<IStore<SpaceStation, long>>().AllAsync(maxRuntime.Token);
6868

69-
Directory.CreateDirectory("v1");
70-
Directory.CreateDirectory("v2");
69+
Directory.CreateDirectory("ci");
70+
Directory.CreateDirectory("ci/v1");
71+
Directory.CreateDirectory("ci/v2");
7172

7273
var options = new JsonSerializerOptions { WriteIndented = true };
73-
await File.WriteAllBytesAsync("v1/assignments.json", JsonSerializer.SerializeToUtf8Bytes(assignments, options), maxRuntime.Token);
74-
await File.WriteAllBytesAsync("v1/campaigns.json", JsonSerializer.SerializeToUtf8Bytes(campaigns, options), maxRuntime.Token);
75-
await File.WriteAllBytesAsync("v1/dispatches.json", JsonSerializer.SerializeToUtf8Bytes(dispatchesv1, options), maxRuntime.Token);
76-
await File.WriteAllBytesAsync("v1/planets.json", JsonSerializer.SerializeToUtf8Bytes(planets, options), maxRuntime.Token);
77-
await File.WriteAllBytesAsync("v1/war.json", JsonSerializer.SerializeToUtf8Bytes(war, options), maxRuntime.Token);
78-
await File.WriteAllBytesAsync("v2/dispatches.json", JsonSerializer.SerializeToUtf8Bytes(dispatchesv2, options), maxRuntime.Token);
79-
await File.WriteAllBytesAsync("v2/space-stations.json", JsonSerializer.SerializeToUtf8Bytes(store, options), maxRuntime.Token);
74+
await File.WriteAllBytesAsync("ci/v1/assignments.json", JsonSerializer.SerializeToUtf8Bytes(assignments, options), maxRuntime.Token);
75+
await File.WriteAllBytesAsync("ci/v1/campaigns.json", JsonSerializer.SerializeToUtf8Bytes(campaigns, options), maxRuntime.Token);
76+
await File.WriteAllBytesAsync("ci/v1/dispatches.json", JsonSerializer.SerializeToUtf8Bytes(dispatchesv1, options), maxRuntime.Token);
77+
await File.WriteAllBytesAsync("ci/v1/planets.json", JsonSerializer.SerializeToUtf8Bytes(planets, options), maxRuntime.Token);
78+
await File.WriteAllBytesAsync("ci/v1/war.json", JsonSerializer.SerializeToUtf8Bytes(war, options), maxRuntime.Token);
79+
await File.WriteAllBytesAsync("ci/v2/dispatches.json", JsonSerializer.SerializeToUtf8Bytes(dispatchesv2, options), maxRuntime.Token);
80+
await File.WriteAllBytesAsync("ci/v2/space-stations.json", JsonSerializer.SerializeToUtf8Bytes(store, options), maxRuntime.Token);
8081

8182
return 0;

src/Helldivers-2-SourceGen/Parsers/BaseJsonParser.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@ public abstract class BaseJsonParser : IJsonParser
1515
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
1616
using global::System.Collections.Generic;
1717
using global::Helldivers.Models.Domain.Localization;
18+
using global::System.CodeDom.Compiler;
1819
1920
namespace Helldivers.Models;
2021
2122
public static partial class Static
2223
{{
2324
/// <summary>Public list of {0} entries from {1}</summary>
25+
[GeneratedCode(""Helldivers.SourceGen"", ""1.0.0"")]
2426
public static {2} {0} = {3};
2527
}}";
2628

@@ -48,4 +50,23 @@ public SourceText Parse(AdditionalText file, CancellationToken cancellationToken
4850
/// Convert the JSON string into C# code that can be injected.
4951
/// </summary>
5052
protected abstract (string Type, string Source) Parse(string json);
53+
54+
/// <summary>
55+
/// Escapes the given JSON value so it remains a valid C# string while attempting to preserve formatting.
56+
/// </summary>
57+
protected string EscapeString(string? value)
58+
{
59+
const string tripleQuote = @"""""""";
60+
if (string.IsNullOrWhiteSpace(value))
61+
return string.Empty;
62+
63+
if (value.Contains('\n') || value.Contains('"'))
64+
{
65+
value = value?.Replace("\n", "\n\t\t");
66+
67+
return $"{tripleQuote}\n\t\t{value}\n\t\t{tripleQuote}";
68+
}
69+
70+
return $@"""{value}""";
71+
}
5172
}

src/Helldivers-2-SourceGen/Parsers/BiomesParser.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ protected override (string Type, string Source) Parse(string json)
1414
var builder = new StringBuilder("new Dictionary<string, Helldivers.Models.V1.Planets.Biome>()\n\t{\n");
1515
var entries = JsonSerializer.Deserialize<Dictionary<string, Dictionary<string, string>>>(json)!;
1616
foreach (var pair in entries)
17-
builder.AppendLine($@"{'\t'}{'\t'}{{ ""{pair.Key}"", new Helldivers.Models.V1.Planets.Biome(""{pair.Value["name"]}"", ""{pair.Value["description"]}"") }},");
17+
builder.AppendLine($@"{'\t'}{'\t'}{{ {EscapeString(pair.Key)}, new Helldivers.Models.V1.Planets.Biome({EscapeString(pair.Value["name"])}, {EscapeString(pair.Value["description"])}) }},");
1818

1919
builder.Append("\t}");
2020
return ("IReadOnlyDictionary<string, Helldivers.Models.V1.Planets.Biome>", builder.ToString());

src/Helldivers-2-SourceGen/Parsers/EnvironmentalsParser.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ protected override (string Type, string Source) Parse(string json)
1515
var builder = new StringBuilder("new Dictionary<string, Helldivers.Models.V1.Planets.Hazard>()\n\t{\n");
1616
var entries = JsonSerializer.Deserialize<Dictionary<string, Dictionary<string, string>>>(json)!;
1717
foreach (var pair in entries)
18-
builder.AppendLine($@"{'\t'}{'\t'}{{ ""{pair.Key}"", new Helldivers.Models.V1.Planets.Hazard(""{pair.Value["name"]}"", ""{pair.Value["description"]}"") }},");
18+
builder.AppendLine($@"{'\t'}{'\t'}{{ {EscapeString(pair.Key)}, new Helldivers.Models.V1.Planets.Hazard({EscapeString(pair.Value["name"])}, {EscapeString(pair.Value["description"])}) }},");
1919

2020
builder.Append("\t}");
2121
return ("IReadOnlyDictionary<string, Helldivers.Models.V1.Planets.Hazard>", builder.ToString());

src/Helldivers-2-SourceGen/Parsers/FactionsParser.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ protected override (string Type, string Source) Parse(string json)
1414
var builder = new StringBuilder("new Dictionary<int, string>()\n\t{\n");
1515
var entries = JsonSerializer.Deserialize<Dictionary<string, string>>(json)!;
1616
foreach (var pair in entries)
17-
builder.AppendLine($@"{'\t'}{'\t'}{{ {pair.Key}, ""{pair.Value}"" }},");
17+
builder.AppendLine($@"{'\t'}{'\t'}{{ {pair.Key}, {EscapeString(pair.Value)} }},");
1818

1919
builder.Append("\t}");
2020
return ("IReadOnlyDictionary<int, string>", builder.ToString());

src/Helldivers-2-SourceGen/Parsers/PlanetRegionsParser.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,8 @@ protected override (string Type, string Source) Parse(string json)
2121
string? description = property.Value.GetProperty("description").GetString();
2222
if (string.IsNullOrWhiteSpace(description))
2323
description = "null";
24-
else
25-
description = $@"""{description}""";
2624

27-
builder.AppendLine($@"{'\t'}{'\t'}{{ {index}, (""{name}"", {description}) }},");
25+
builder.AppendLine($@"{'\t'}{'\t'}{{ {index}, ({EscapeString(name)}, {EscapeString(description)}) }},");
2826
}
2927

3028
builder.Append("\t}");

src/Helldivers-2-SourceGen/Parsers/PlanetsParser.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ protected override (string Type, string Source) Parse(string json)
2727
.Value
2828
.GetProperty("environmentals")
2929
.EnumerateArray()
30-
.Select(prop => $@"""{prop.GetString()!}""")
30+
.Select(prop => EscapeString(prop.GetString()))
3131
.ToList();
3232

33-
builder.AppendLine($@"{'\t'}{'\t'}{{ {index}, (LocalizedMessage.FromStrings([{string.Join(", ", names.Select(pair => $@"[""{pair.Key}"", ""{pair.Value}""]"))}]), ""{sector}"", ""{biome}"", [{string.Join(", ", environmentals)}]) }},");
33+
builder.AppendLine($@"{'\t'}{'\t'}{{ {index}, (LocalizedMessage.FromStrings([{string.Join(", ", names.Select(pair => $@"[{EscapeString(pair.Key)}, {EscapeString(pair.Value)}]"))}]), {EscapeString(sector)}, {EscapeString(biome)}, [{string.Join(", ", environmentals)}]) }},");
3434
}
3535

3636
builder.Append("\t}");

0 commit comments

Comments
 (0)