summary refs log tree commit diff
path: root/ReferenceClientProxyImplementation/Patches/Implementations/JSPatches/JsonParseMultilinePatch.cs
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceClientProxyImplementation/Patches/Implementations/JSPatches/JsonParseMultilinePatch.cs')
-rw-r--r--ReferenceClientProxyImplementation/Patches/Implementations/JSPatches/JsonParseMultilinePatch.cs79
1 files changed, 79 insertions, 0 deletions
diff --git a/ReferenceClientProxyImplementation/Patches/Implementations/JSPatches/JsonParseMultilinePatch.cs b/ReferenceClientProxyImplementation/Patches/Implementations/JSPatches/JsonParseMultilinePatch.cs
new file mode 100644

index 0000000..b5e7d77 --- /dev/null +++ b/ReferenceClientProxyImplementation/Patches/Implementations/JSPatches/JsonParseMultilinePatch.cs
@@ -0,0 +1,79 @@ +using System.Diagnostics; +using System.Text; +using System.Text.Json; +using System.Text.RegularExpressions; +using ReferenceClientProxyImplementation.Configuration; + +namespace ReferenceClientProxyImplementation.Patches.Implementations.JSPatches; + +public partial class JsonParseMultilinePatch(ProxyConfiguration config) : IPatch { + public int GetOrder() => 1; + + public string GetName() => "Patch null-coalescing expressions in JS"; + public bool Applies(string relativeName, byte[] content) => relativeName.EndsWith(".js"); + + public async Task<byte[]> Execute(string relativePath, byte[] content) { + var stringContent = Encoding.UTF8.GetString(content); + + var matches = JsonParseRegex().Matches(stringContent); + Console.WriteLine($"Found {matches.Count} JSON.parse calls in {relativePath}"); + + + + await Parallel.ForEachAsync(matches, async (match, ct) => { + string formattedJson = match.Groups[1].Value; + try { + var jsonElement = JsonSerializer.Deserialize<JsonElement>(formattedJson.Replace("\\", "\\\\") + "waef"); + formattedJson = JsonSerializer.Serialize(jsonElement, new JsonSerializerOptions { WriteIndented = true }); + } catch (JsonException je) { + // Console.WriteLine($"STJ: Failed to parse JSON in {relativePath} at index {match.Index}: {je.Message}"); // intentinally broken + try { + formattedJson = await formatJsonWithNodejs(relativePath, match, ct); + } catch (Exception e) { + Console.WriteLine($"Node.js: Failed to parse JSON in {relativePath} at index {match.Index}: {e.Message}"); + return; + } + } + + lock (matches) stringContent = stringContent.Replace(match.Value, $"JSON.parse(`{formattedJson.Replace("\\", "\\\\")}`);"); + }); + + return Encoding.UTF8.GetBytes(stringContent); + } + + private async Task<string> formatJsonWithNodejs(string relativePath, Match match, CancellationToken ct) { + // Extract the JSON string from the match + var id = "dcp_" + Path.GetFileName(relativePath).Replace('.', '_') + "_" + match.Index; + await File.WriteAllTextAsync($"{Environment.GetEnvironmentVariable("TMPDIR") ?? "/tmp"}/{id}.js", $"console.log(JSON.stringify(JSON.parse(`{match.Groups[1].Value.Replace("`", "\\\\\\`")}`), null, 2))"); + var sw = Stopwatch.StartNew(); + + var psi = new ProcessStartInfo(config.AssetCache.NodePath, $"{Environment.GetEnvironmentVariable("TMPDIR") ?? "/tmp"}/{id}.js") { RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; + + using var process = Process.Start(psi); + if (process == null) { + throw new InvalidOperationException("Failed to start the formatting process."); + } + + var stdout = await process.StandardOutput.ReadToEndAsync(); + var stderr = await process.StandardError.ReadToEndAsync(); + + await process.WaitForExitAsync(); + // Console.WriteLine($"Formatted {relativeName} in {sw.ElapsedMilliseconds}ms: {process.ExitCode}"); + + if (process.ExitCode != 0) { + Console.WriteLine($"Failed to run {Environment.GetEnvironmentVariable("TMPDIR") ?? "/tmp"}/{id}.js in {sw.ElapsedMilliseconds}ms: {process.ExitCode}"); + Console.WriteLine("Standard Output: " + stdout); + Console.WriteLine("Standard Error: " + stderr); + throw new Exception($"Failed to execute {Environment.GetEnvironmentVariable("TMPDIR") ?? "/tmp"}/{id}.js: {stderr}"); + } + + var formattedJson = stdout.Trim(); + Console.WriteLine($"Parsed JSON({id}) in {sw.ElapsedMilliseconds}ms: {formattedJson.Length} bytes"); + // stringContent = stringContent.Replace(match.Value, $"JSON.parse(`{formattedJson.Replace("\\n", "\\\\n")}`);"); + await File.WriteAllTextAsync($"{config.TestClient.RevisionPath}/patched/assets/{Path.GetFileName(relativePath)}-{match.Index}.json", formattedJson); + return formattedJson; + } + + [GeneratedRegex(@"JSON\.parse\(\n\s*'(.*?)',?\s*\);", RegexOptions.Compiled | RegexOptions.Multiline)] + private static partial Regex JsonParseRegex(); +} \ No newline at end of file