mirror of https://github.com/Squidex/squidex.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
215 lines
7.4 KiB
215 lines
7.4 KiB
using NJsonSchema;
|
|
using NJsonSchema.CodeGeneration.TypeScript;
|
|
using NSwag;
|
|
using NSwag.CodeGeneration.TypeScript;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace Generator;
|
|
|
|
internal partial class Program
|
|
{
|
|
static async Task Main(string[] args)
|
|
{
|
|
var cacheFile = "cache.json";
|
|
|
|
if (!File.Exists(cacheFile) || !args.Contains("--cache"))
|
|
{
|
|
var httpClient = new HttpClient();
|
|
var schemaResponse = await httpClient.GetAsync("https://localhost:5001/api/swagger/v1/swagger.json");
|
|
var schemaText = await schemaResponse.Content.ReadAsStringAsync();
|
|
|
|
File.WriteAllText(cacheFile, schemaText);
|
|
}
|
|
|
|
var (rootPath, codePath) = GetCodePath();
|
|
Console.WriteLine($"Using root folder {rootPath}");
|
|
|
|
var document = await OpenApiDocument.FromJsonAsync(File.ReadAllText(cacheFile));
|
|
|
|
foreach (var (typeName, schema) in document.Components.Schemas.ToList())
|
|
{
|
|
if (typeName.Equals("AssetDto"))
|
|
{
|
|
if (schema.ActualProperties.TryGetValue("tags", out var tags))
|
|
{
|
|
tags.IsNullableRaw = false;
|
|
tags.IsRequired = true;
|
|
}
|
|
}
|
|
|
|
if (typeName.Equals("LanguageDto"))
|
|
{
|
|
schema.Properties.Remove("nativeName");
|
|
}
|
|
|
|
if (typeName.Equals("AppDto") || typeName.Equals("TeamDto"))
|
|
{
|
|
if (schema.ActualProperties.ContainsKey("created") && !schema.ActualProperties.ContainsKey("createdBy"))
|
|
{
|
|
schema.Properties["createdBy"] = new JsonSchemaProperty
|
|
{
|
|
Description = "The user that has created the app.",
|
|
Type = JsonObjectType.String,
|
|
IsNullableRaw = true,
|
|
IsRequired = false,
|
|
IsReadOnly = true,
|
|
};
|
|
}
|
|
|
|
if (schema.ActualProperties.ContainsKey("lastModified") && !schema.ActualProperties.ContainsKey("lastModifiedBy"))
|
|
{
|
|
schema.Properties["lastModifiedBy"] = new JsonSchemaProperty
|
|
{
|
|
Description = "The user that has updated the app.",
|
|
Type = JsonObjectType.String,
|
|
IsNullableRaw = true,
|
|
IsRequired = false,
|
|
IsReadOnly = true,
|
|
};
|
|
}
|
|
}
|
|
|
|
foreach (var (name, property) in schema.ActualProperties)
|
|
{
|
|
property.IsReadOnly = true;
|
|
|
|
if (property.Type == JsonObjectType.String && !property.IsRequired)
|
|
{
|
|
property.IsNullableRaw = true;
|
|
}
|
|
|
|
if (name.Equals("referenceFields"))
|
|
{
|
|
property.IsNullableRaw = false;
|
|
property.IsRequired = true;
|
|
}
|
|
|
|
if (name.Equals("schemaName"))
|
|
{
|
|
property.IsNullableRaw = false;
|
|
property.IsRequired = true;
|
|
}
|
|
|
|
if (name.Equals("schemaDisplayName"))
|
|
{
|
|
property.IsNullableRaw = false;
|
|
property.IsRequired = true;
|
|
}
|
|
}
|
|
|
|
if (document.Components.Schemas.TryGetValue("ErrorDto", out var error))
|
|
{
|
|
document.Components.Schemas.Remove("ErrorDto");
|
|
document.Components.Schemas["ServerErrorDto"] = error;
|
|
}
|
|
|
|
if (!typeName.EndsWith("Dto") && schema.Type == JsonObjectType.Object)
|
|
{
|
|
document.Components.Schemas.Remove(typeName);
|
|
document.Components.Schemas[$"{typeName}Dto"] = schema;
|
|
}
|
|
}
|
|
|
|
var extensionFile = Path.Combine(rootPath, @"src\\app\\shared\\model\\custom.ts");
|
|
var extensionCode = File.ReadAllText(extensionFile);
|
|
|
|
var classes =
|
|
ClassNameRegex().Matches(extensionCode)
|
|
.Select(m => m.Groups["ClassName"].Value)
|
|
.ToArray();
|
|
|
|
var settings = new TypeScriptClientGeneratorSettings
|
|
{
|
|
GenerateClientClasses = false,
|
|
GenerateClientInterfaces = false,
|
|
};
|
|
settings.TypeScriptGeneratorSettings.EnumStyle = TypeScriptEnumStyle.StringLiteral;
|
|
settings.TypeScriptGeneratorSettings.ExportTypes = true;
|
|
settings.TypeScriptGeneratorSettings.ExtendedClasses = classes;
|
|
settings.TypeScriptGeneratorSettings.ExtensionCode = extensionCode;
|
|
settings.TypeScriptGeneratorSettings.GenerateConstructorInterface = true;
|
|
settings.TypeScriptGeneratorSettings.InlineNamedDictionaries = true;
|
|
settings.TypeScriptGeneratorSettings.TemplateDirectory = Path.Combine(codePath, "Templates");
|
|
|
|
var generator = new TypeScriptClientGenerator(document, settings);
|
|
|
|
var code = generator.GenerateFile();
|
|
|
|
code = code.Replace("I{ [key: string]", "{ [key: string]");
|
|
code = code.Replace(": Date,", ": DateTime,");
|
|
code = code.Replace(": Date;", ": DateTime;");
|
|
code = code.Replace(": Date |", ": DateTime |");
|
|
code = code.Replace("DtoDto", "Dto");
|
|
|
|
var targetFolder = Path.Combine(rootPath, @"src\\app\\shared\\model\\generated.ts");
|
|
|
|
ValidateComputed(code);
|
|
|
|
File.WriteAllText(targetFolder, code);
|
|
Console.WriteLine("Code Generation completed");
|
|
}
|
|
|
|
private static (string RootPath, string CodePath) GetCodePath()
|
|
{
|
|
var folder = new DirectoryInfo(Directory.GetCurrentDirectory());
|
|
|
|
while (folder != null)
|
|
{
|
|
var subFolders = folder.GetDirectories();
|
|
if (subFolders.Any(x => x.Name == "src"))
|
|
{
|
|
return (folder.FullName, Path.Combine(folder.FullName, "generator/Generator"));
|
|
}
|
|
|
|
folder = folder.Parent;
|
|
}
|
|
|
|
throw new InvalidOperationException("Cannot find code folder.");
|
|
}
|
|
|
|
private static void ValidateComputed(string code)
|
|
{
|
|
var lines = code.Split('\n');
|
|
|
|
var i = 0;
|
|
foreach (var line in lines)
|
|
{
|
|
ValidateLine(lines, line, i);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
private static void ValidateLine(string[] lines, string line, int index)
|
|
{
|
|
var computed = ComputedRegex().Match(line);
|
|
if (!computed.Success)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var cacheKey = computed.Groups["Name"].Value;
|
|
|
|
var previousLine = lines[index - 1];
|
|
var property = PropertyRegex().Match(previousLine);
|
|
if (!property.Success)
|
|
{
|
|
Console.WriteLine($"Line {index}: Cannot find property for computed '{cacheKey}'");
|
|
return;
|
|
}
|
|
|
|
var propertyName = property.Groups["Name"].Value;
|
|
if (propertyName != cacheKey)
|
|
{
|
|
Console.WriteLine($"Line {index}: Invalid cache key '{cacheKey}' for property '{propertyName}'");
|
|
}
|
|
}
|
|
|
|
[GeneratedRegex("return this\\.compute\\('(?<Name>[^']*)',")]
|
|
private static partial Regex ComputedRegex();
|
|
|
|
[GeneratedRegex("class (?<ClassName>[^\\)]*) extends generated\\.")]
|
|
private static partial Regex ClassNameRegex();
|
|
|
|
[GeneratedRegex("public get (?<Name>[^(]*)\\(\\) {")]
|
|
private static partial Regex PropertyRegex();
|
|
}
|