using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using XFESystem.Documents;
if (args.Length is < 1 or > 2 || args.Length == 2 && args[1] != "--code-reference") throw new ArgumentException("Specify a fresh reference fixture directory and optional --code-reference.");
var output = Path.GetFullPath(args[0]);
if (Directory.Exists(output)) throw new IOException("The reference directory must be new.");
Directory.CreateDirectory(output);
var markdown = WebsiteAssets.ReadText("Fixtures/WebsiteParity.md");
var builder = new DocumentPreviewBuilder(new());
await File.WriteAllTextAsync(Path.Combine(output, "Fixture.md"), markdown);
await File.WriteAllTextAsync(Path.Combine(output, "Dark.html"), builder.MarkdownWeb(markdown, "Website parity", dark: true).Html);
await File.WriteAllTextAsync(Path.Combine(output, "Light.html"), builder.MarkdownWeb(markdown, "Website parity", dark: false).Html);
await File.WriteAllTextAsync(Path.Combine(output, "SourceManifest.json"), WebsiteAssets.ReadText("Exact/SourceManifest.json"));
if (args.Length == 2)
{
string? root = AppContext.BaseDirectory;
while (root is not null && !File.Exists(Path.Combine(root, "XFESystem.slnx"))) root = Path.GetDirectoryName(root);
if (root is null) throw new InvalidOperationException("Cannot identify the production sample source.");
var sourcePath = Path.Combine(root, "Source", "XFESystem.Browser", "BrowserResourceSource.cs");
var sourceBytes = await File.ReadAllBytesAsync(sourcePath);
var sourceText = Encoding.UTF8.GetString(sourceBytes);
var literal = Regex.Match(sourceText, @"else if\(!globalThis\.xfeMonacoFileMode\)xfeMonacoEditor\.setValue\(language==='csharp'\?'((?:\\.|[^'\\])*)':");
if (!literal.Success) throw new InvalidOperationException("The production C# sample shape changed; update the explicit reference extractor.");
// This is a string decoder, not evaluation of either JavaScript or C#.
var code = DecodeJavaScriptString(literal.Groups[1].Value);
var codeSha = Convert.ToHexStringLower(SHA256.HashData(Encoding.UTF8.GetBytes(code)));
await File.WriteAllTextAsync(Path.Combine(output, "CSharpSample.cs"), code);
await File.WriteAllTextAsync(Path.Combine(output, "CodeDark.html"), builder.CodeWeb(code, "MonacoSample.cs", dark: true).Html);
await File.WriteAllTextAsync(Path.Combine(output, "CodeLight.html"), builder.CodeWeb(code, "MonacoSample.cs", dark: false).Html);
await File.WriteAllTextAsync(Path.Combine(output, "CSharpSample.json"), JsonSerializer.Serialize(new
{
Kind = "ProductionMonacoDefaultCSharpSample", Component = "WebsiteStaticCSharpCodeBlock",
SourcePath = sourcePath, SourceSha256 = Convert.ToHexStringLower(SHA256.HashData(sourceBytes)),
CodeSha256 = codeSha, LineCount = code.Split('\n').Length,
ExtractedFrom = "xfeMonacoSetLanguage('csharp') default string; source code is not executed"
}, new JsonSerializerOptions { WriteIndented = true }));
}
var resources = new List<object>();
foreach (var entry in WebsiteAssets.WebResources)
{
var path = Path.Combine(output, "Assets", entry.AssetName.Replace('/', Path.DirectorySeparatorChar));
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
using var stream = WebsiteAssets.Open(entry.AssetName);
await using var file = File.Create(path);
await stream.CopyToAsync(file);
resources.Add(new { entry.UrlPath, entry.AssetName, entry.ContentType });
}
await File.WriteAllTextAsync(Path.Combine(output, "Resources.json"), JsonSerializer.Serialize(resources, new JsonSerializerOptions { WriteIndented = true }));
Console.WriteLine(output);
static string DecodeJavaScriptString(string literal)
{
var decoded = new StringBuilder();
for (int index = 0; index < literal.Length; index++)
{
char current = literal[index];
if (current != '\\') { decoded.Append(current); continue; }
if (++index == literal.Length) throw new FormatException("Incomplete sample string escape.");
decoded.Append(literal[index] switch
{
'n' => '\n', 'r' => '\r', 't' => '\t', 'b' => '\b', 'f' => '\f', 'v' => '\v',
'\\' => '\\', '\'' => '\'', '"' => '"',
_ => throw new FormatException("Unsupported sample escape; do not guess or execute it.")
});
}
return decoded.ToString();
}
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using XFESystem.Documents;
if (args.Length is < 1 or > 2 || args.Length == 2 && args[1] != "--code-reference") throw new ArgumentException("Specify a fresh reference fixture directory and optional --code-reference.");
var output = Path.GetFullPath(args[0]);
if (Directory.Exists(output)) throw new IOException("The reference directory must be new.");
Directory.CreateDirectory(output);
var markdown = WebsiteAssets.ReadText("Fixtures/WebsiteParity.md");
var builder = new DocumentPreviewBuilder(new());
await File.WriteAllTextAsync(Path.Combine(output, "Fixture.md"), markdown);
await File.WriteAllTextAsync(Path.Combine(output, "Dark.html"), builder.MarkdownWeb(markdown, "Website parity", dark: true).Html);
await File.WriteAllTextAsync(Path.Combine(output, "Light.html"), builder.MarkdownWeb(markdown, "Website parity", dark: false).Html);
await File.WriteAllTextAsync(Path.Combine(output, "SourceManifest.json"), WebsiteAssets.ReadText("Exact/SourceManifest.json"));
if (args.Length == 2)
{
string? root = AppContext.BaseDirectory;
while (root is not null && !File.Exists(Path.Combine(root, "XFESystem.slnx"))) root = Path.GetDirectoryName(root);
if (root is null) throw new InvalidOperationException("Cannot identify the production sample source.");
var sourcePath = Path.Combine(root, "Source", "XFESystem.Browser", "BrowserResourceSource.cs");
var sourceBytes = await File.ReadAllBytesAsync(sourcePath);
var sourceText = Encoding.UTF8.GetString(sourceBytes);
var literal = Regex.Match(sourceText, @"else if\(!globalThis\.xfeMonacoFileMode\)xfeMonacoEditor\.setValue\(language==='csharp'\?'((?:\\.|[^'\\])*)':");
if (!literal.Success) throw new InvalidOperationException("The production C# sample shape changed; update the explicit reference extractor.");
// This is a string decoder, not evaluation of either JavaScript or C#.
var code = DecodeJavaScriptString(literal.Groups[1].Value);
var codeSha = Convert.ToHexStringLower(SHA256.HashData(Encoding.UTF8.GetBytes(code)));
await File.WriteAllTextAsync(Path.Combine(output, "CSharpSample.cs"), code);
await File.WriteAllTextAsync(Path.Combine(output, "CodeDark.html"), builder.CodeWeb(code, "MonacoSample.cs", dark: true).Html);
await File.WriteAllTextAsync(Path.Combine(output, "CodeLight.html"), builder.CodeWeb(code, "MonacoSample.cs", dark: false).Html);
await File.WriteAllTextAsync(Path.Combine(output, "CSharpSample.json"), JsonSerializer.Serialize(new
{
Kind = "ProductionMonacoDefaultCSharpSample", Component = "WebsiteStaticCSharpCodeBlock",
SourcePath = sourcePath, SourceSha256 = Convert.ToHexStringLower(SHA256.HashData(sourceBytes)),
CodeSha256 = codeSha, LineCount = code.Split('\n').Length,
ExtractedFrom = "xfeMonacoSetLanguage('csharp') default string; source code is not executed"
}, new JsonSerializerOptions { WriteIndented = true }));
}
var resources = new List<object>();
foreach (var entry in WebsiteAssets.WebResources)
{
var path = Path.Combine(output, "Assets", entry.AssetName.Replace('/', Path.DirectorySeparatorChar));
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
using var stream = WebsiteAssets.Open(entry.AssetName);
await using var file = File.Create(path);
await stream.CopyToAsync(file);
resources.Add(new { entry.UrlPath, entry.AssetName, entry.ContentType });
}
await File.WriteAllTextAsync(Path.Combine(output, "Resources.json"), JsonSerializer.Serialize(resources, new JsonSerializerOptions { WriteIndented = true }));
Console.WriteLine(output);
static string DecodeJavaScriptString(string literal)
{
var decoded = new StringBuilder();
for (int index = 0; index < literal.Length; index++)
{
char current = literal[index];
if (current != '\\') { decoded.Append(current); continue; }
if (++index == literal.Length) throw new FormatException("Incomplete sample string escape.");
decoded.Append(literal[index] switch
{
'n' => '\n', 'r' => '\r', 't' => '\t', 'b' => '\b', 'f' => '\f', 'v' => '\v',
'\\' => '\\', '\'' => '\'', '"' => '"',
_ => throw new FormatException("Unsupported sample escape; do not guess or execute it.")
});
}
return decoded.ToString();
}