diff --git a/bunit.sln b/bunit.sln
index e5b5294d4..f782ca9f9 100644
--- a/bunit.sln
+++ b/bunit.sln
@@ -62,46 +62,136 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "bunit.tests", "tests\bunit.
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "bunit.generators.tests", "tests\bunit.generators.tests\bunit.generators.tests.csproj", "{D08F7F1D-74B1-4A76-86A2-94918863740C}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "bunit.anglesharp", "src\bunit.anglesharp\bunit.anglesharp.csproj", "{4591042C-410C-4BA1-A075-653F77891EDA}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1DA6EFDE-81A1-4324-A56C-40BEE14A75BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1DA6EFDE-81A1-4324-A56C-40BEE14A75BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1DA6EFDE-81A1-4324-A56C-40BEE14A75BA}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {1DA6EFDE-81A1-4324-A56C-40BEE14A75BA}.Debug|x64.Build.0 = Debug|Any CPU
+ {1DA6EFDE-81A1-4324-A56C-40BEE14A75BA}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {1DA6EFDE-81A1-4324-A56C-40BEE14A75BA}.Debug|x86.Build.0 = Debug|Any CPU
{1DA6EFDE-81A1-4324-A56C-40BEE14A75BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1DA6EFDE-81A1-4324-A56C-40BEE14A75BA}.Release|Any CPU.Build.0 = Release|Any CPU
- {1DA6EFDE-81A1-4324-A56C-40BEE14A75BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1DA6EFDE-81A1-4324-A56C-40BEE14A75BA}.Release|x64.ActiveCfg = Release|Any CPU
+ {1DA6EFDE-81A1-4324-A56C-40BEE14A75BA}.Release|x64.Build.0 = Release|Any CPU
+ {1DA6EFDE-81A1-4324-A56C-40BEE14A75BA}.Release|x86.ActiveCfg = Release|Any CPU
+ {1DA6EFDE-81A1-4324-A56C-40BEE14A75BA}.Release|x86.Build.0 = Release|Any CPU
{6127D121-9387-451B-B15D-8350A32D3001}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6127D121-9387-451B-B15D-8350A32D3001}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {6127D121-9387-451B-B15D-8350A32D3001}.Debug|x64.Build.0 = Debug|Any CPU
+ {6127D121-9387-451B-B15D-8350A32D3001}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {6127D121-9387-451B-B15D-8350A32D3001}.Debug|x86.Build.0 = Debug|Any CPU
{6127D121-9387-451B-B15D-8350A32D3001}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6127D121-9387-451B-B15D-8350A32D3001}.Release|x64.ActiveCfg = Release|Any CPU
+ {6127D121-9387-451B-B15D-8350A32D3001}.Release|x64.Build.0 = Release|Any CPU
+ {6127D121-9387-451B-B15D-8350A32D3001}.Release|x86.ActiveCfg = Release|Any CPU
+ {6127D121-9387-451B-B15D-8350A32D3001}.Release|x86.Build.0 = Release|Any CPU
{7972A80F-30DC-4EF4-9294-7D4DD2965882}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7972A80F-30DC-4EF4-9294-7D4DD2965882}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7972A80F-30DC-4EF4-9294-7D4DD2965882}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {7972A80F-30DC-4EF4-9294-7D4DD2965882}.Debug|x64.Build.0 = Debug|Any CPU
+ {7972A80F-30DC-4EF4-9294-7D4DD2965882}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7972A80F-30DC-4EF4-9294-7D4DD2965882}.Debug|x86.Build.0 = Debug|Any CPU
{7972A80F-30DC-4EF4-9294-7D4DD2965882}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7972A80F-30DC-4EF4-9294-7D4DD2965882}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7972A80F-30DC-4EF4-9294-7D4DD2965882}.Release|x64.ActiveCfg = Release|Any CPU
+ {7972A80F-30DC-4EF4-9294-7D4DD2965882}.Release|x64.Build.0 = Release|Any CPU
+ {7972A80F-30DC-4EF4-9294-7D4DD2965882}.Release|x86.ActiveCfg = Release|Any CPU
+ {7972A80F-30DC-4EF4-9294-7D4DD2965882}.Release|x86.Build.0 = Release|Any CPU
{0FF92169-7D8F-46A2-8327-A2F028CB426F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0FF92169-7D8F-46A2-8327-A2F028CB426F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0FF92169-7D8F-46A2-8327-A2F028CB426F}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {0FF92169-7D8F-46A2-8327-A2F028CB426F}.Debug|x64.Build.0 = Debug|Any CPU
+ {0FF92169-7D8F-46A2-8327-A2F028CB426F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0FF92169-7D8F-46A2-8327-A2F028CB426F}.Debug|x86.Build.0 = Debug|Any CPU
{0FF92169-7D8F-46A2-8327-A2F028CB426F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0FF92169-7D8F-46A2-8327-A2F028CB426F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0FF92169-7D8F-46A2-8327-A2F028CB426F}.Release|x64.ActiveCfg = Release|Any CPU
+ {0FF92169-7D8F-46A2-8327-A2F028CB426F}.Release|x64.Build.0 = Release|Any CPU
+ {0FF92169-7D8F-46A2-8327-A2F028CB426F}.Release|x86.ActiveCfg = Release|Any CPU
+ {0FF92169-7D8F-46A2-8327-A2F028CB426F}.Release|x86.Build.0 = Release|Any CPU
{DE975A0C-0672-4248-913E-D267C1001801}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DE975A0C-0672-4248-913E-D267C1001801}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DE975A0C-0672-4248-913E-D267C1001801}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {DE975A0C-0672-4248-913E-D267C1001801}.Debug|x64.Build.0 = Debug|Any CPU
+ {DE975A0C-0672-4248-913E-D267C1001801}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {DE975A0C-0672-4248-913E-D267C1001801}.Debug|x86.Build.0 = Debug|Any CPU
{DE975A0C-0672-4248-913E-D267C1001801}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DE975A0C-0672-4248-913E-D267C1001801}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DE975A0C-0672-4248-913E-D267C1001801}.Release|x64.ActiveCfg = Release|Any CPU
+ {DE975A0C-0672-4248-913E-D267C1001801}.Release|x64.Build.0 = Release|Any CPU
+ {DE975A0C-0672-4248-913E-D267C1001801}.Release|x86.ActiveCfg = Release|Any CPU
+ {DE975A0C-0672-4248-913E-D267C1001801}.Release|x86.Build.0 = Release|Any CPU
{AE3DFB52-2BF4-4806-AD82-7FB7B38AC17F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AE3DFB52-2BF4-4806-AD82-7FB7B38AC17F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AE3DFB52-2BF4-4806-AD82-7FB7B38AC17F}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {AE3DFB52-2BF4-4806-AD82-7FB7B38AC17F}.Debug|x64.Build.0 = Debug|Any CPU
+ {AE3DFB52-2BF4-4806-AD82-7FB7B38AC17F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {AE3DFB52-2BF4-4806-AD82-7FB7B38AC17F}.Debug|x86.Build.0 = Debug|Any CPU
{AE3DFB52-2BF4-4806-AD82-7FB7B38AC17F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AE3DFB52-2BF4-4806-AD82-7FB7B38AC17F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AE3DFB52-2BF4-4806-AD82-7FB7B38AC17F}.Release|x64.ActiveCfg = Release|Any CPU
+ {AE3DFB52-2BF4-4806-AD82-7FB7B38AC17F}.Release|x64.Build.0 = Release|Any CPU
+ {AE3DFB52-2BF4-4806-AD82-7FB7B38AC17F}.Release|x86.ActiveCfg = Release|Any CPU
+ {AE3DFB52-2BF4-4806-AD82-7FB7B38AC17F}.Release|x86.Build.0 = Release|Any CPU
{A7C6A2AA-FF8F-4ED1-8590-5324FC566059}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A7C6A2AA-FF8F-4ED1-8590-5324FC566059}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A7C6A2AA-FF8F-4ED1-8590-5324FC566059}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {A7C6A2AA-FF8F-4ED1-8590-5324FC566059}.Debug|x64.Build.0 = Debug|Any CPU
+ {A7C6A2AA-FF8F-4ED1-8590-5324FC566059}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A7C6A2AA-FF8F-4ED1-8590-5324FC566059}.Debug|x86.Build.0 = Debug|Any CPU
{A7C6A2AA-FF8F-4ED1-8590-5324FC566059}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A7C6A2AA-FF8F-4ED1-8590-5324FC566059}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A7C6A2AA-FF8F-4ED1-8590-5324FC566059}.Release|x64.ActiveCfg = Release|Any CPU
+ {A7C6A2AA-FF8F-4ED1-8590-5324FC566059}.Release|x64.Build.0 = Release|Any CPU
+ {A7C6A2AA-FF8F-4ED1-8590-5324FC566059}.Release|x86.ActiveCfg = Release|Any CPU
+ {A7C6A2AA-FF8F-4ED1-8590-5324FC566059}.Release|x86.Build.0 = Release|Any CPU
{56889DE7-5E66-4E9C-815B-CBCFC9961612}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{56889DE7-5E66-4E9C-815B-CBCFC9961612}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {56889DE7-5E66-4E9C-815B-CBCFC9961612}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {56889DE7-5E66-4E9C-815B-CBCFC9961612}.Debug|x64.Build.0 = Debug|Any CPU
+ {56889DE7-5E66-4E9C-815B-CBCFC9961612}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {56889DE7-5E66-4E9C-815B-CBCFC9961612}.Debug|x86.Build.0 = Debug|Any CPU
{56889DE7-5E66-4E9C-815B-CBCFC9961612}.Release|Any CPU.ActiveCfg = Release|Any CPU
{56889DE7-5E66-4E9C-815B-CBCFC9961612}.Release|Any CPU.Build.0 = Release|Any CPU
+ {56889DE7-5E66-4E9C-815B-CBCFC9961612}.Release|x64.ActiveCfg = Release|Any CPU
+ {56889DE7-5E66-4E9C-815B-CBCFC9961612}.Release|x64.Build.0 = Release|Any CPU
+ {56889DE7-5E66-4E9C-815B-CBCFC9961612}.Release|x86.ActiveCfg = Release|Any CPU
+ {56889DE7-5E66-4E9C-815B-CBCFC9961612}.Release|x86.Build.0 = Release|Any CPU
{D08F7F1D-74B1-4A76-86A2-94918863740C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D08F7F1D-74B1-4A76-86A2-94918863740C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D08F7F1D-74B1-4A76-86A2-94918863740C}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {D08F7F1D-74B1-4A76-86A2-94918863740C}.Debug|x64.Build.0 = Debug|Any CPU
+ {D08F7F1D-74B1-4A76-86A2-94918863740C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D08F7F1D-74B1-4A76-86A2-94918863740C}.Debug|x86.Build.0 = Debug|Any CPU
{D08F7F1D-74B1-4A76-86A2-94918863740C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D08F7F1D-74B1-4A76-86A2-94918863740C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D08F7F1D-74B1-4A76-86A2-94918863740C}.Release|x64.ActiveCfg = Release|Any CPU
+ {D08F7F1D-74B1-4A76-86A2-94918863740C}.Release|x64.Build.0 = Release|Any CPU
+ {D08F7F1D-74B1-4A76-86A2-94918863740C}.Release|x86.ActiveCfg = Release|Any CPU
+ {D08F7F1D-74B1-4A76-86A2-94918863740C}.Release|x86.Build.0 = Release|Any CPU
+ {4591042C-410C-4BA1-A075-653F77891EDA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4591042C-410C-4BA1-A075-653F77891EDA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4591042C-410C-4BA1-A075-653F77891EDA}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {4591042C-410C-4BA1-A075-653F77891EDA}.Debug|x64.Build.0 = Debug|Any CPU
+ {4591042C-410C-4BA1-A075-653F77891EDA}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {4591042C-410C-4BA1-A075-653F77891EDA}.Debug|x86.Build.0 = Debug|Any CPU
+ {4591042C-410C-4BA1-A075-653F77891EDA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4591042C-410C-4BA1-A075-653F77891EDA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4591042C-410C-4BA1-A075-653F77891EDA}.Release|x64.ActiveCfg = Release|Any CPU
+ {4591042C-410C-4BA1-A075-653F77891EDA}.Release|x64.Build.0 = Release|Any CPU
+ {4591042C-410C-4BA1-A075-653F77891EDA}.Release|x86.ActiveCfg = Release|Any CPU
+ {4591042C-410C-4BA1-A075-653F77891EDA}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -116,6 +206,7 @@ Global
{A7C6A2AA-FF8F-4ED1-8590-5324FC566059} = {9A2B3B34-D41C-43E8-BC7D-246BEBE48D59}
{56889DE7-5E66-4E9C-815B-CBCFC9961612} = {6EA09ED4-B714-4E6F-B0E1-4D987F8AE520}
{D08F7F1D-74B1-4A76-86A2-94918863740C} = {6EA09ED4-B714-4E6F-B0E1-4D987F8AE520}
+ {4591042C-410C-4BA1-A075-653F77891EDA} = {9A2B3B34-D41C-43E8-BC7D-246BEBE48D59}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {24106918-1C86-4769-BDA6-9C80E64CD260}
diff --git a/src/bunit.anglesharp/Directory.Build.props b/src/bunit.anglesharp/Directory.Build.props
new file mode 100644
index 000000000..6c80b1779
--- /dev/null
+++ b/src/bunit.anglesharp/Directory.Build.props
@@ -0,0 +1,7 @@
+
+
+
+
+ true
+
+
diff --git a/src/bunit/Extensions/Internal/AngleSharpWrapperExtensions.cs b/src/bunit.anglesharp/Extensions/AngleSharpWrapperExtensions.cs
similarity index 91%
rename from src/bunit/Extensions/Internal/AngleSharpWrapperExtensions.cs
rename to src/bunit.anglesharp/Extensions/AngleSharpWrapperExtensions.cs
index ffb6f391d..77a019de5 100644
--- a/src/bunit/Extensions/Internal/AngleSharpWrapperExtensions.cs
+++ b/src/bunit.anglesharp/Extensions/AngleSharpWrapperExtensions.cs
@@ -1,3 +1,4 @@
+using System.Collections.Generic;
using AngleSharp.Dom;
namespace Bunit.Web.AngleSharp;
@@ -5,7 +6,7 @@ namespace Bunit.Web.AngleSharp;
///
/// Extensions for wrapped inside types.
///
-internal static class AngleSharpWrapperExtensions
+public static class AngleSharpWrapperExtensions
{
///
/// Unwraps a wrapped AngleSharp object, if it has been wrapped.
diff --git a/src/bunit.anglesharp/Placeholder.cs b/src/bunit.anglesharp/Placeholder.cs
new file mode 100644
index 000000000..2b88fcebe
--- /dev/null
+++ b/src/bunit.anglesharp/Placeholder.cs
@@ -0,0 +1,7 @@
+// This file is a placeholder to ensure the project compiles
+namespace Bunit.Web.AngleSharp
+{
+ internal static class Placeholder
+ {
+ }
+}
diff --git a/src/bunit.anglesharp/bunit.anglesharp.csproj b/src/bunit.anglesharp/bunit.anglesharp.csproj
new file mode 100644
index 000000000..9ffaebade
--- /dev/null
+++ b/src/bunit.anglesharp/bunit.anglesharp.csproj
@@ -0,0 +1,18 @@
+
+
+ net8.0;net9.0;net10.0
+ Bunit.Web.AngleSharp
+ false
+ disable
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/bunit.generators.internal/Web.AngleSharp/WrapperElementGenerator.cs b/src/bunit.generators.internal/Web.AngleSharp/WrapperElementGenerator.cs
index 81d0039e7..be5968ea6 100644
--- a/src/bunit.generators.internal/Web.AngleSharp/WrapperElementGenerator.cs
+++ b/src/bunit.generators.internal/Web.AngleSharp/WrapperElementGenerator.cs
@@ -1,4 +1,5 @@
using Microsoft.CodeAnalysis;
+using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
@@ -10,7 +11,10 @@ internal static class WrapperElementGenerator
{
internal static string GenerateWrapperTypeSource(StringBuilder source, INamedTypeSymbol elm)
{
- var name = $"{elm.Name.Substring(1)}Wrapper";
+ // Element interface names start with 'I' (e.g., IElement -> ElementWrapper)
+ var name = elm.Name.Length > 1 && elm.Name.StartsWith("I", StringComparison.Ordinal)
+ ? $"{elm.Name[1..]}Wrapper"
+ : $"{elm.Name}Wrapper";
var wrappedTypeName = elm.ToDisplayString(GeneratorConfig.SymbolFormat);
source.AppendLine("#nullable enable");
diff --git a/src/bunit.generators.internal/Web.AngleSharp/WrapperElementsGenerator.cs b/src/bunit.generators.internal/Web.AngleSharp/WrapperElementsGenerator.cs
index facb2e810..be0950b2a 100644
--- a/src/bunit.generators.internal/Web.AngleSharp/WrapperElementsGenerator.cs
+++ b/src/bunit.generators.internal/Web.AngleSharp/WrapperElementsGenerator.cs
@@ -1,7 +1,9 @@
+#nullable enable
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using System;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Text;
@@ -14,26 +16,41 @@ public class WrapperElementsGenerator : IIncrementalGenerator
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// Finds the AngleSharp assembly referenced by the target project
- // This should prevent the source generator from running unless a
- // new symbol is returned.
- var angleSharpAssemblyReference = context
+ // and collects element interface type names into cacheable records.
+ var elementInterfaces = context
.CompilationProvider
.Select((compilation, cancellationToken) =>
{
var meta = compilation.References.FirstOrDefault(x => x.Display?.EndsWith($"{Path.DirectorySeparatorChar}AngleSharp.dll", StringComparison.Ordinal) ?? false);
- return compilation.GetAssemblyOrModuleSymbol(meta);
+ var assembly = compilation.GetAssemblyOrModuleSymbol(meta);
+
+ if (assembly is not IAssemblySymbol angleSharpAssembly)
+ return null;
+
+ var elementInterfaceTypes = FindElementInterfaces(angleSharpAssembly);
+ // Create cacheable records with just the essential info needed for generation
+ // Store metadata names instead of symbols for cacheability
+ return new ElementInterfacesData(
+ elementInterfaceTypes.Select(t => new ElementTypeInfo(
+ t.Name,
+ t.ToDisplayString(GeneratorConfig.SymbolFormat),
+ GetMetadataName(t)
+ )).ToImmutableArray());
});
+ // Combine with compilation to retrieve symbols during execution
+ var elementInterfacesWithCompilation = elementInterfaces.Combine(context.CompilationProvider);
+
// Output the hardcoded source files
- context.RegisterSourceOutput(angleSharpAssemblyReference, GenerateStaticContent);
+ context.RegisterSourceOutput(elementInterfaces, GenerateStaticContent);
// Output the generated wrapper types
- context.RegisterSourceOutput(angleSharpAssemblyReference, GenerateWrapperTypes);
+ context.RegisterSourceOutput(elementInterfacesWithCompilation, GenerateWrapperTypes);
}
- private static void GenerateStaticContent(SourceProductionContext context, ISymbol assembly)
+ private static void GenerateStaticContent(SourceProductionContext context, ElementInterfacesData? data)
{
- if (assembly is not IAssemblySymbol)
+ if (data is null)
return;
context.AddSource("IElementWrapperFactory.g.cs", ReadEmbeddedResource("Bunit.Web.AngleSharp.IElementWrapperFactory.cs"));
@@ -41,15 +58,28 @@ private static void GenerateStaticContent(SourceProductionContext context, ISymb
context.AddSource("WrapperBase.g.cs", ReadEmbeddedResource("Bunit.Web.AngleSharp.WrapperBase.cs"));
}
- private static void GenerateWrapperTypes(SourceProductionContext context, ISymbol assembly)
+ private static void GenerateWrapperTypes(SourceProductionContext context, (ElementInterfacesData? data, Compilation compilation) input)
{
+ var (data, compilation) = input;
+ if (data is null)
+ return;
+
+ // Find the AngleSharp assembly in the compilation
+ var meta = compilation.References.FirstOrDefault(x => x.Display?.EndsWith($"{Path.DirectorySeparatorChar}AngleSharp.dll", StringComparison.Ordinal) ?? false);
+ var assembly = compilation.GetAssemblyOrModuleSymbol(meta);
+
if (assembly is not IAssemblySymbol angleSharpAssembly)
return;
- var elementInterfacetypes = FindElementInterfaces(angleSharpAssembly);
+ // Retrieve the actual symbols from the assembly for code generation
+ var elementSymbols = data.ElementTypes
+ .Select(t => angleSharpAssembly.GetTypeByMetadataName(t.MetadataName))
+ .Where(s => s is not null)
+ .Cast()
+ .ToList();
var source = new StringBuilder();
- foreach (var elm in elementInterfacetypes)
+ foreach (var elm in elementSymbols)
{
source.Clear();
var name = WrapperElementGenerator.GenerateWrapperTypeSource(source, elm);
@@ -57,11 +87,11 @@ private static void GenerateWrapperTypes(SourceProductionContext context, ISymbo
}
source.Clear();
- GenerateWrapperFactory(source, elementInterfacetypes);
+ GenerateWrapperFactory(source, data.ElementTypes);
context.AddSource($"WrapperExtensions.g.cs", SourceText.From(source.ToString(), Encoding.UTF8));
}
- private static void GenerateWrapperFactory(StringBuilder source, IEnumerable elementInterfacetypes)
+ private static void GenerateWrapperFactory(StringBuilder source, ImmutableArray elementTypes)
{
source.AppendLine("""namespace Bunit.Web.AngleSharp;""");
source.AppendLine();
@@ -78,10 +108,13 @@ private static void GenerateWrapperFactory(StringBuilder source, IEnumerable(this global::AngleSharp.Dom.IElement element, TElementFactory elementFactory) where TElementFactory : Bunit.Web.AngleSharp.IElementWrapperFactory => element switch");
source.AppendLine("\t{");
- foreach (var elm in elementInterfacetypes)
+ foreach (var elm in elementTypes)
{
- var wrapperName = $"{elm.Name.Substring(1)}Wrapper";
- source.AppendLine($"\t\t{elm.ToDisplayString(GeneratorConfig.SymbolFormat)} e => new {wrapperName}(e, elementFactory),");
+ // Element interface names start with 'I' (e.g., IElement -> ElementWrapper)
+ var wrapperName = elm.Name.Length > 1 && elm.Name.StartsWith("I", StringComparison.Ordinal)
+ ? $"{elm.Name[1..]}Wrapper"
+ : $"{elm.Name}Wrapper";
+ source.AppendLine($"\t\t{elm.FullyQualifiedName} e => new {wrapperName}(e, elementFactory),");
}
source.AppendLine($"\t\t_ => new ElementWrapper(element, elementFactory),");
@@ -90,6 +123,17 @@ private static void GenerateWrapperFactory(StringBuilder source, IEnumerable FindElementInterfaces(IAssemblySymbol angleSharpAssembly)
{
var htmlDomNamespace = angleSharpAssembly
@@ -104,6 +148,9 @@ private static IReadOnlyList FindElementInterfaces(IAssemblySy
var elementInterfaceSymbol = angleSharpAssembly
.GetTypeByMetadataName("AngleSharp.Dom.IElement");
+ if (elementInterfaceSymbol is null)
+ return Array.Empty();
+
var result = htmlDomNamespace
.GetTypeMembers()
.Where(typeSymbol => typeSymbol.TypeKind == TypeKind.Interface && typeSymbol.AllInterfaces.Contains(elementInterfaceSymbol))
@@ -139,3 +186,13 @@ private static string ReadEmbeddedResource(string resourceName)
return reader.ReadToEnd();
}
}
+
+// Cacheable data structure that stores minimal information about element interfaces
+// This allows the incremental generator to cache and reuse results across builds
+internal sealed record ElementInterfacesData(
+ ImmutableArray ElementTypes);
+
+internal sealed record ElementTypeInfo(
+ string Name,
+ string FullyQualifiedName,
+ string MetadataName);
diff --git a/src/bunit/bunit.csproj b/src/bunit/bunit.csproj
index 3a5511a05..0f2da07d1 100644
--- a/src/bunit/bunit.csproj
+++ b/src/bunit/bunit.csproj
@@ -44,8 +44,7 @@
-
+