1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
using System.Diagnostics;
using ArcaneLibs;
using ReferenceClientProxyImplementation.Configuration;
namespace ReferenceClientProxyImplementation.Patches.Implementations;
public partial class FormatJsFilePatch(ProxyConfiguration config) : IPatch {
public int GetOrder() => -100;
public string GetName() => "Format JS file";
public bool Applies(string relativeName, byte[] content) => relativeName.EndsWith(".js") || relativeName.EndsWith(".css") || relativeName.EndsWith(".html");
public async Task<byte[]> Execute(string relativeName, byte[] content) {
var cachePath = Path.Combine(config.TestClient.RevisionPath, "formatted", relativeName);
if (File.Exists(cachePath)) {
Console.WriteLine($"Using cached formatted file for {relativeName}");
return await File.ReadAllBytesAsync(cachePath);
}
// temporary: add some newlines
var stringContent = System.Text.Encoding.UTF8.GetString(content);
// stringContent = stringContent.Replace("function(){", "function() {\n");
content = System.Text.Encoding.UTF8.GetBytes(stringContent);
Directory.CreateDirectory(Path.GetDirectoryName(cachePath)!);
var tmpPath = $"{Environment.GetEnvironmentVariable("TMPDIR") ?? "/tmp"}/{Random.Shared.NextInt64()}_{Path.GetFileName(relativeName)}";
await File.WriteAllBytesAsync(tmpPath, content);
var sw = Stopwatch.StartNew();
ProcessStartInfo psi;
// Biome doesn't support HTML and struggles with upstream emitting Sass directives
if (relativeName.EndsWith(".html") || relativeName.EndsWith(".css"))
psi = new ProcessStartInfo(config.AssetCache.PrettierPath, $"-w --print-width 240 {tmpPath}") {
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
else
psi = new ProcessStartInfo(config.AssetCache.PrettierPath, $"-w --print-width 240 {tmpPath}") {
// psi = new ProcessStartInfo(config.AssetCache.BiomePath, $"format --write --line-width 240 --files-max-size=100000000 {tmpPath}") {
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();
Dictionary<ulong, string> stdoutLines = new();
Dictionary<ulong, string> stderrLines = new();
process.OutputDataReceived += (sender, args) => {
if (args.Data != null) {
stdoutLines[(ulong)sw.ElapsedMilliseconds] = args.Data;
Console.Write("O");
}
};
process.ErrorDataReceived += (sender, args) => {
if (args.Data != null) {
stderrLines[(ulong)sw.ElapsedMilliseconds] = args.Data;
Console.Write("E");
}
};
process.BeginOutputReadLine();
process.BeginErrorReadLine();
await process.WaitForExitAsync();
Console.WriteLine($"Formatted {relativeName} in {sw.ElapsedMilliseconds}ms: {process.ExitCode}");
if (process.ExitCode != 0) {
Console.WriteLine($"Failed to format {relativeName} in {sw.ElapsedMilliseconds}ms: {process.ExitCode}");
Console.WriteLine("Standard Output:\n" + string.Join("\n", stdoutLines.OrderBy(kv => kv.Key).Select(kv => $"[{kv.Key}ms] {kv.Value}")));
Console.WriteLine("Standard Error:\n" + string.Join("\n", stderrLines.OrderBy(kv => kv.Key).Select(kv => $"[{kv.Key}ms] {kv.Value}")));
throw new Exception($"Failed to exec({psi.FileName} {psi.Arguments}): {string.Join("\n", stderrLines.OrderBy(kv => kv.Key).Select(kv => kv.Value))}");
}
var result = await File.ReadAllBytesAsync(tmpPath);
File.Move(tmpPath, cachePath);
return result;
}
}
|