mirror of
https://github.com/AssetRipper/AssetRipper.GUI.Web.Dependencies.git
synced 2026-11-13 04:26:27 -10:00
Updated Bootstrap CDN links and integrity hashes to version 5.3.8. Also updated Vue.js CDN links to version 3.5.27 for both production and development builds.
188 lines
6.3 KiB
C#
188 lines
6.3 KiB
C#
using AssetRipper.Text.SourceGeneration;
|
|
using Microsoft.CodeAnalysis.CSharp;
|
|
using System.CodeDom.Compiler;
|
|
using System.Net.Http.Headers;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
|
|
namespace AssetRipper.GUI.Web.Dependencies.SourceGenerator;
|
|
|
|
public static class Program
|
|
{
|
|
private readonly record struct Dependency(string Name, string Website, string ProductionDownloadUrl, string? ProductionIntegrity, string? DevelopmentDownloadUrl, string? DevelopmentIntegrity, string Path, string MimeType);
|
|
private static readonly Dependency[] dependencies =
|
|
[
|
|
new(
|
|
"BabylonMain",
|
|
"https://www.babylonjs.com/",
|
|
"https://cdn.babylonjs.com/babylon.js",
|
|
null,
|
|
null,
|
|
null,
|
|
"/js/babylon.js",
|
|
"application/javascript"),
|
|
new(
|
|
"BabylonLoader",
|
|
"https://www.babylonjs.com/",
|
|
"https://cdn.babylonjs.com/loaders/babylonjs.loaders.min.js",
|
|
null,
|
|
null,
|
|
null,
|
|
"/js/babylonjs.loaders.min.js",
|
|
"application/javascript"),
|
|
new(
|
|
"BootstrapStyleSheet",
|
|
"https://getbootstrap.com/",
|
|
"https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css",
|
|
"sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB",
|
|
null,
|
|
null,
|
|
"/css/bootstrap.min.css",
|
|
"text/css"),
|
|
new(
|
|
"BootstrapScript",
|
|
"https://getbootstrap.com/",
|
|
"https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js",
|
|
"sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI",
|
|
null,
|
|
null,
|
|
"/js/bootstrap.bundle.min.js",
|
|
"application/javascript"),
|
|
new(
|
|
"Popper",
|
|
"https://jquery.com/",
|
|
"https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js",
|
|
"sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r",
|
|
null,
|
|
null,
|
|
"/js/popper.min.js",
|
|
"application/javascript"),
|
|
new(
|
|
"Vue",
|
|
"https://vuejs.org/",
|
|
"https://unpkg.com/[email protected]/dist/vue.global.prod.js",
|
|
null,
|
|
"https://unpkg.com/[email protected]/dist/vue.global.js",
|
|
null,
|
|
"/js/vue.js",
|
|
"application/javascript"),
|
|
];
|
|
public static void Main(string[] args)
|
|
{
|
|
string outputDirectory = args[0];
|
|
using HttpClient client = CreateClient();
|
|
|
|
string outputPath = Path.Combine(outputDirectory, "Dependencies");
|
|
IndentedTextWriter writer = IndentedTextWriterFactory.Create(outputDirectory, "EmbeddedDependency");
|
|
writer.WriteGeneratedCodeWarning();
|
|
writer.WriteLineNoTabs();
|
|
writer.WriteUsing("System.Text");
|
|
writer.WriteLineNoTabs();
|
|
writer.WriteFileScopedNamespace("AssetRipper.GUI.Web.Dependencies");
|
|
writer.WriteLineNoTabs();
|
|
writer.WriteLine("public readonly record struct EmbeddedDependency(string Content, string Path, string MimeType, bool IsDevelopment)");
|
|
using (new CurlyBrackets(writer))
|
|
{
|
|
writer.WriteLine("public bool IsScript => MimeType == \"application/javascript\";");
|
|
writer.WriteLine("public bool IsStyleSheet => MimeType == \"text/css\";");
|
|
writer.WriteLine("public bool IsProduction => !IsDevelopment;");
|
|
foreach (Dependency dependency in dependencies)
|
|
{
|
|
writer.WriteSummaryDocumentation($"<see href={GetLiteral(dependency.Website)} />");
|
|
WriteProperty(client, writer, dependency.Name, dependency.ProductionDownloadUrl, dependency.ProductionIntegrity, dependency.Path, dependency.MimeType, false);
|
|
if (dependency.DevelopmentDownloadUrl is null)
|
|
{
|
|
writer.WriteLine($"internal static EmbeddedDependency {dependency.Name}Development => {dependency.Name};");
|
|
}
|
|
else
|
|
{
|
|
writer.WriteSummaryDocumentation($"<see href={GetLiteral(dependency.Website)} />");
|
|
WriteProperty(client, writer, dependency.Name + "Development", dependency.DevelopmentDownloadUrl, dependency.DevelopmentIntegrity, dependency.Path, dependency.MimeType, true);
|
|
}
|
|
}
|
|
writer.WriteLine("public static IReadOnlyList<EmbeddedDependency> GetAllProduction() =>");
|
|
writer.WriteLine('[');
|
|
using (new Indented(writer))
|
|
{
|
|
foreach (Dependency dependency in dependencies)
|
|
{
|
|
writer.WriteLine($"{dependency.Name},");
|
|
}
|
|
}
|
|
writer.WriteLine("];");
|
|
writer.WriteLine("public static IReadOnlyList<EmbeddedDependency> GetAllDevelopment() =>");
|
|
writer.WriteLine('[');
|
|
using (new Indented(writer))
|
|
{
|
|
foreach (Dependency dependency in dependencies)
|
|
{
|
|
writer.WriteLine($"{dependency.Name}Development,");
|
|
}
|
|
}
|
|
writer.WriteLine("];");
|
|
}
|
|
}
|
|
|
|
private static void WriteProperty(HttpClient client, IndentedTextWriter writer, string name, string url, string? integrity, string path, string mimeType, bool isDevelopment)
|
|
{
|
|
writer.WriteLine($"public static EmbeddedDependency {name}");
|
|
using (new CurlyBrackets(writer))
|
|
{
|
|
writer.WriteLine("get");
|
|
using (new CurlyBrackets(writer))
|
|
{
|
|
using (new If(writer, "field == default"))
|
|
{
|
|
byte[] data = DownloadAsync(client, url, integrity).GetAwaiter().GetResult();
|
|
string content = GetLiteral(Encoding.UTF8.GetString(data));
|
|
string isDevelopmentString = isDevelopment ? "true" : "false";
|
|
writer.WriteLine($"ReadOnlySpan<byte> data = {content}u8;");
|
|
writer.WriteLine($"field = new(Encoding.UTF8.GetString(data), {GetLiteral(path)}, {GetLiteral(mimeType)}, {isDevelopmentString});");
|
|
}
|
|
writer.WriteLine("return field;");
|
|
}
|
|
}
|
|
}
|
|
|
|
private static HttpClient CreateClient()
|
|
{
|
|
HttpClient client = new();
|
|
client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("AssetRipper.GUI.Web.Dependencies.SourceGenerator", "1.0"));
|
|
return client;
|
|
}
|
|
|
|
private static async Task<byte[]> DownloadAsync(HttpClient client, string url, string? integrity)
|
|
{
|
|
using HttpResponseMessage response = await client.GetAsync(url);
|
|
response.EnsureSuccessStatusCode();
|
|
byte[] result = await response.Content.ReadAsByteArrayAsync();
|
|
if (!ValidateIntegrity(result, integrity))
|
|
{
|
|
throw new InvalidOperationException($"Integrity check failed for {url}");
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static bool ValidateIntegrity(byte[] data, string? integrity)
|
|
{
|
|
if (string.IsNullOrEmpty(integrity))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
const string Sha384Prefix = "sha384-";
|
|
if (integrity.StartsWith(Sha384Prefix, StringComparison.Ordinal))
|
|
{
|
|
byte[] hash = SHA384.HashData(data);
|
|
byte[] integrityHash = Convert.FromBase64String(integrity[Sha384Prefix.Length..]);
|
|
return hash.SequenceEqual(integrityHash);
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static string GetLiteral(string content) => SymbolDisplay.FormatLiteral(content, true);
|
|
}
|