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.
135 lines
5.2 KiB
135 lines
5.2 KiB
// ==========================================================================
|
|
// Squidex Headless CMS
|
|
// ==========================================================================
|
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
// All rights reserved. Licensed under the MIT license.
|
|
// ==========================================================================
|
|
|
|
using System.Text;
|
|
using HandlebarsDotNet;
|
|
using Microsoft.CodeAnalysis;
|
|
using Microsoft.CodeAnalysis.CSharp;
|
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
using Microsoft.CodeAnalysis.Text;
|
|
|
|
namespace Squidex.Data.Tests.CodeGenerator;
|
|
|
|
[Generator]
|
|
public class CodeGenerator : IIncrementalGenerator
|
|
{
|
|
public void Initialize(IncrementalGeneratorInitializationContext context)
|
|
{
|
|
static TestModel? TransformTest(GeneratorSyntaxContext ctx)
|
|
{
|
|
var classSyntax = (ClassDeclarationSyntax)ctx.Node;
|
|
|
|
var className = classSyntax.Identifier.Text;
|
|
if (!className.StartsWith("EF", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (!classSyntax.Modifiers.Any(x => x.IsKind(SyntaxKind.AbstractKeyword)))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (classSyntax.TypeParameterList == null ||
|
|
classSyntax.TypeParameterList.Parameters.Count == 0 ||
|
|
classSyntax.TypeParameterList.Parameters[0].Identifier.Text != "TContext")
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var reuseLabel = "default";
|
|
foreach (var attributeList in classSyntax.AttributeLists)
|
|
{
|
|
foreach (var attribute in attributeList.Attributes)
|
|
{
|
|
var name = attribute.Name.ToString();
|
|
if (name != "ReuseLabel" && name != "ReuseLabelAttribute")
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (attribute.ArgumentList?.Arguments.Count != 1)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var value = attribute.ArgumentList.Arguments[0];
|
|
if (value.Expression is not LiteralExpressionSyntax literal)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var candidate = literal.Token.ValueText;
|
|
if (!string.IsNullOrWhiteSpace(candidate))
|
|
{
|
|
reuseLabel = candidate;
|
|
}
|
|
}
|
|
}
|
|
|
|
var namespaceDeclaration =
|
|
classSyntax.Ancestors()
|
|
.OfType<BaseNamespaceDeclarationSyntax>().First();
|
|
|
|
return new TestModel
|
|
{
|
|
BaseName = classSyntax.Identifier.Text,
|
|
ClassName = classSyntax.Identifier.Text.Substring(2),
|
|
ClassNamespace = namespaceDeclaration.Name.ToString(),
|
|
CollectionSuffix = reuseLabel.ToPascalCase(),
|
|
CollectionLabel = reuseLabel,
|
|
HasContentContext = classSyntax.TypeParameterList.Parameters.Count == 2,
|
|
};
|
|
}
|
|
|
|
var fieldDeclarations = context.SyntaxProvider.CreateSyntaxProvider(
|
|
static (node, _) =>
|
|
{
|
|
return node is ClassDeclarationSyntax;
|
|
},
|
|
static (ctx, _) => TransformTest(ctx))
|
|
.Where(x => x != null);
|
|
|
|
WriteTests(context, fieldDeclarations);
|
|
WriteFixtures(context, fieldDeclarations!);
|
|
}
|
|
|
|
private static void WriteTests(IncrementalGeneratorInitializationContext context, IncrementalValuesProvider<TestModel?> fieldDeclarations)
|
|
{
|
|
var testTemplateStream = typeof(CodeGenerator).Assembly.GetManifestResourceStream("Squidex.TestTemplate.handlebar")!;
|
|
var testTemplateText = new StreamReader(testTemplateStream).ReadToEnd();
|
|
var testTemplateFunc = Handlebars.Compile(testTemplateText);
|
|
|
|
context.RegisterSourceOutput(fieldDeclarations, (context, model) =>
|
|
{
|
|
var source = testTemplateFunc(model);
|
|
|
|
context.AddSource($"{model!.BaseName}_Tests.cs", SourceText.From(source, Encoding.UTF8));
|
|
});
|
|
}
|
|
|
|
private static void WriteFixtures(IncrementalGeneratorInitializationContext context, IncrementalValuesProvider<TestModel> fieldDeclarations)
|
|
{
|
|
var fixtureTemplateStream = typeof(CodeGenerator).Assembly.GetManifestResourceStream("Squidex.FixtureTemplate.handlebar")!;
|
|
var fixtureTemplateText = new StreamReader(fixtureTemplateStream).ReadToEnd();
|
|
var fixtureTemplateFunc = Handlebars.Compile(fixtureTemplateText);
|
|
|
|
var fixtureDeclarations = fieldDeclarations.Select(
|
|
static (x, ct) =>
|
|
{
|
|
return new FixtureModel { Label = x.CollectionLabel, Name = x.CollectionSuffix };
|
|
})
|
|
.Collect().SelectMany((values, _) => values.GroupBy(x => x.Label).Select(x => x.First()));
|
|
|
|
context.RegisterSourceOutput(fixtureDeclarations, (context, model) =>
|
|
{
|
|
var source = fixtureTemplateFunc(model);
|
|
|
|
context.AddSource($"{model.Name}_Fixtures.cs", SourceText.From(source, Encoding.UTF8));
|
|
});
|
|
}
|
|
}
|
|
|