Add AddVisitor method and Configure hook (#3897)
Fixes https://github.com/microsoft/typespec/issues/3827 Also adds a Configure hook so that AddVisitor can be called directly from the Plugin. Considered just using the ctor but that would mean we would have virtual property calls in a ctor.
This commit is contained in:
Родитель
2c16b4b089
Коммит
998440879a
|
@ -41,6 +41,14 @@ namespace Microsoft.Generator.CSharp
|
|||
_inputLibrary = new(() => new InputLibrary(Instance.Configuration.OutputDirectory));
|
||||
}
|
||||
|
||||
// for mocking
|
||||
protected CodeModelPlugin()
|
||||
{
|
||||
// should be mocked
|
||||
Configuration = null!;
|
||||
_inputLibrary = new(() => null!);
|
||||
}
|
||||
|
||||
private Lazy<InputLibrary> _inputLibrary;
|
||||
|
||||
// Extensibility points to be implemented by a plugin
|
||||
|
@ -50,5 +58,9 @@ namespace Microsoft.Generator.CSharp
|
|||
public InputLibrary InputLibrary => _inputLibrary.Value;
|
||||
public virtual TypeProviderWriter GetWriter(TypeProvider provider) => new(provider);
|
||||
public virtual IReadOnlyList<MetadataReference> AdditionalMetadataReferences => Array.Empty<MetadataReference>();
|
||||
|
||||
public virtual void Configure()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace Microsoft.Generator.CSharp
|
|||
{
|
||||
public class OutputLibrary
|
||||
{
|
||||
private List<OutputLibraryVisitor> _visitors = new();
|
||||
public OutputLibrary()
|
||||
{
|
||||
}
|
||||
|
@ -57,6 +58,11 @@ namespace Microsoft.Generator.CSharp
|
|||
}
|
||||
|
||||
// TODO - make this more additive instead of replace https://github.com/microsoft/typespec/issues/3827
|
||||
protected internal virtual IEnumerable<OutputLibraryVisitor> GetOutputLibraryVisitors() => [];
|
||||
protected internal virtual IEnumerable<OutputLibraryVisitor> GetOutputLibraryVisitors() => _visitors;
|
||||
|
||||
public void AddVisitor(OutputLibraryVisitor visitor)
|
||||
{
|
||||
_visitors.Add(visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,26 +13,32 @@ namespace Microsoft.Generator.CSharp
|
|||
public void LoadPlugin(CommandLineOptions options)
|
||||
{
|
||||
using DirectoryCatalog directoryCatalog = new(AppContext.BaseDirectory);
|
||||
using (CompositionContainer container = new(directoryCatalog))
|
||||
{
|
||||
container.ComposeExportedValue(new GeneratorContext(Configuration.Load(options.OutputDirectory)));
|
||||
container.ComposeParts(this);
|
||||
bool loaded = false;
|
||||
foreach (var plugin in Plugins!)
|
||||
{
|
||||
if (plugin.Metadata.PluginName == options.PluginName)
|
||||
{
|
||||
CodeModelPlugin.Instance = plugin.Value;
|
||||
loaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
using CompositionContainer container = new(directoryCatalog);
|
||||
|
||||
if (!loaded)
|
||||
container.ComposeExportedValue(new GeneratorContext(Configuration.Load(options.OutputDirectory)));
|
||||
container.ComposeParts(this);
|
||||
|
||||
SelectPlugin(options.PluginName!);
|
||||
}
|
||||
|
||||
internal void SelectPlugin(string pluginName)
|
||||
{
|
||||
bool loaded = false;
|
||||
foreach (var plugin in Plugins!)
|
||||
{
|
||||
if (plugin.Metadata.PluginName == pluginName)
|
||||
{
|
||||
throw new InvalidOperationException($"Plugin {options.PluginName} not found.");
|
||||
CodeModelPlugin.Instance = plugin.Value;
|
||||
loaded = true;
|
||||
CodeModelPlugin.Instance.Configure();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!loaded)
|
||||
{
|
||||
throw new InvalidOperationException($"Plugin {pluginName} not found.");
|
||||
}
|
||||
}
|
||||
|
||||
[ImportMany]
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Generator.CSharp.Providers;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
@ -16,7 +18,7 @@ namespace Microsoft.Generator.CSharp.Tests
|
|||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_outputLibrary = new MockOutputLibrary();
|
||||
_outputLibrary = new TestOutputLibrary();
|
||||
}
|
||||
|
||||
// Tests that the BuildTypeProviders method is successfully overridden.
|
||||
|
@ -26,9 +28,54 @@ namespace Microsoft.Generator.CSharp.Tests
|
|||
Assert.Throws<NotImplementedException>(() => { object shouldFail = _outputLibrary.TypeProviders; });
|
||||
}
|
||||
|
||||
internal class MockOutputLibrary : OutputLibrary
|
||||
[Test]
|
||||
public void CanAddVisitors()
|
||||
{
|
||||
public MockOutputLibrary() : base() { }
|
||||
_outputLibrary.AddVisitor(new TestOutputLibraryVisitor());
|
||||
Assert.AreEqual(1, _outputLibrary.GetOutputLibraryVisitors().Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanOverrideGetOutputLibraryVisitors()
|
||||
{
|
||||
var outputLibrary = new TestOutputLibraryOverridingVisitors(new [] { new TestOutputLibraryVisitor() });
|
||||
Assert.AreEqual(1, outputLibrary.GetOutputLibraryVisitors().Count());
|
||||
|
||||
outputLibrary.AddVisitor(new TestOutputLibraryVisitor());
|
||||
Assert.AreEqual(2, outputLibrary.GetOutputLibraryVisitors().Count());
|
||||
}
|
||||
|
||||
private class TestOutputLibraryVisitor : OutputLibraryVisitor
|
||||
{
|
||||
}
|
||||
|
||||
private class TestOutputLibrary : OutputLibrary
|
||||
{
|
||||
protected override TypeProvider[] BuildTypeProviders()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private class TestOutputLibraryOverridingVisitors : OutputLibrary
|
||||
{
|
||||
private readonly IEnumerable<OutputLibraryVisitor>? _visitors;
|
||||
public TestOutputLibraryOverridingVisitors(IEnumerable<OutputLibraryVisitor>? visitors = null)
|
||||
{
|
||||
_visitors = visitors;
|
||||
}
|
||||
|
||||
protected internal override IEnumerable<OutputLibraryVisitor> GetOutputLibraryVisitors()
|
||||
{
|
||||
foreach (var visitor in base.GetOutputLibraryVisitors())
|
||||
{
|
||||
yield return visitor;
|
||||
}
|
||||
foreach (var visitor in _visitors ?? [])
|
||||
{
|
||||
yield return visitor;
|
||||
}
|
||||
}
|
||||
|
||||
protected override TypeProvider[] BuildTypeProviders()
|
||||
{
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Microsoft.Generator.CSharp.Tests.StartUp
|
||||
{
|
||||
public class PluginHandlerTests
|
||||
{
|
||||
[Test]
|
||||
public void SelectPluginFindsMatchingPlugin()
|
||||
{
|
||||
var pluginHandler = new PluginHandler();
|
||||
var metadataMock = new Mock<IMetadata>();
|
||||
metadataMock.SetupGet(m => m.PluginName).Returns("MockPlugin");
|
||||
var mockPlugin = new Mock<CodeModelPlugin>();
|
||||
|
||||
pluginHandler.Plugins = new List<System.Lazy<CodeModelPlugin, IMetadata>>
|
||||
{
|
||||
new(() => mockPlugin.Object, metadataMock.Object),
|
||||
};
|
||||
|
||||
Assert.DoesNotThrow(() => pluginHandler.SelectPlugin("MockPlugin"));
|
||||
mockPlugin.Verify(p => p.Configure(), Times.Once);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SelectPluginThrowsWhenNoMatch()
|
||||
{
|
||||
var pluginHandler = new PluginHandler();
|
||||
var metadataMock = new Mock<IMetadata>();
|
||||
metadataMock.SetupGet(m => m.PluginName).Returns("MockPlugin");
|
||||
var mockPlugin = new Mock<CodeModelPlugin>();
|
||||
|
||||
pluginHandler.Plugins = new List<System.Lazy<CodeModelPlugin, IMetadata>>
|
||||
{
|
||||
new(() => mockPlugin.Object, metadataMock.Object),
|
||||
};
|
||||
|
||||
Assert.Throws<System.InvalidOperationException>(() => pluginHandler.SelectPlugin("NonExistentPlugin"));
|
||||
mockPlugin.Verify(p => p.Configure(), Times.Never);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Generator.CSharp.ClientModel;
|
||||
namespace SamplePlugin
|
||||
{
|
||||
public class SamplePluginOutputLibrary : ScmOutputLibrary
|
||||
{
|
||||
protected override IEnumerable<SamplePluginOutputLibraryVisitor> GetOutputLibraryVisitors() => [new SamplePluginOutputLibraryVisitor()];
|
||||
}
|
||||
}
|
|
@ -14,6 +14,9 @@ namespace SamplePlugin
|
|||
{
|
||||
public override SamplePluginTypeFactory TypeFactory { get; } = new SamplePluginTypeFactory();
|
||||
|
||||
public override OutputLibrary OutputLibrary { get; } = new SamplePluginOutputLibrary();
|
||||
public override void Configure()
|
||||
{
|
||||
OutputLibrary.AddVisitor(new SamplePluginOutputLibraryVisitor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче