Skip to content
This repository has been archived by the owner on Oct 29, 2024. It is now read-only.

Add Component source generator project #323

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CI/CI.Windows.proj
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
<ProjectToBuild Include="..\src\Microsoft.MobileBlazorBindings.ProtectedStorage\Microsoft.MobileBlazorBindings.ProtectedStorage.csproj" />
<ProjectToBuild Include="..\src\Microsoft.MobileBlazorBindings.Authentication\Microsoft.MobileBlazorBindings.Authentication.csproj" />
<ProjectToBuild Include="..\src\Microsoft.MobileBlazorBindings.Authentication.Msal\Microsoft.MobileBlazorBindings.Authentication.Msal.csproj" />
<ProjectToBuild Include="..\src\Microsoft.MobileBlazorBindings.ComponentGenerator\Microsoft.MobileBlazorBindings.ComponentGenerator.csproj" />
<ProjectToBuild Include="..\src\ComponentWrapperGenerator\ComponentWrapperGenerator.csproj" />
</ItemGroup>
</Project>
30 changes: 30 additions & 0 deletions MobileBlazorBindings.sln
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinFormsBlazorSample", "sam
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.MobileBlazorBindings.WindowsForms", "src\Microsoft.MobileBlazorBindings.WindowsForms\Microsoft.MobileBlazorBindings.WindowsForms.csproj", "{1D22DA82-38EB-410C-88EA-37D3D786CCC5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.MobileBlazorBindings.ComponentGenerator", "src\Microsoft.MobileBlazorBindings.ComponentGenerator\Microsoft.MobileBlazorBindings.ComponentGenerator.csproj", "{514BC0B0-9097-47CF-9CEA-CEB431B828D9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.MobileBlazorBindings.PancakeView.SourceGenerator", "samples\MobileBlazorBindingsWeather\Microsoft.MobileBlazorBindings.PancakeView.SourceGenerator\Microsoft.MobileBlazorBindings.PancakeView.SourceGenerator.csproj", "{EEA60BDC-FCAB-4154-B64B-F5BA15337A30}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -1067,6 +1071,30 @@ Global
{1D22DA82-38EB-410C-88EA-37D3D786CCC5}.Release|iPhone.Build.0 = Release|Any CPU
{1D22DA82-38EB-410C-88EA-37D3D786CCC5}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{1D22DA82-38EB-410C-88EA-37D3D786CCC5}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{514BC0B0-9097-47CF-9CEA-CEB431B828D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{514BC0B0-9097-47CF-9CEA-CEB431B828D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{514BC0B0-9097-47CF-9CEA-CEB431B828D9}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{514BC0B0-9097-47CF-9CEA-CEB431B828D9}.Debug|iPhone.Build.0 = Debug|Any CPU
{514BC0B0-9097-47CF-9CEA-CEB431B828D9}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{514BC0B0-9097-47CF-9CEA-CEB431B828D9}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{514BC0B0-9097-47CF-9CEA-CEB431B828D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{514BC0B0-9097-47CF-9CEA-CEB431B828D9}.Release|Any CPU.Build.0 = Release|Any CPU
{514BC0B0-9097-47CF-9CEA-CEB431B828D9}.Release|iPhone.ActiveCfg = Release|Any CPU
{514BC0B0-9097-47CF-9CEA-CEB431B828D9}.Release|iPhone.Build.0 = Release|Any CPU
{514BC0B0-9097-47CF-9CEA-CEB431B828D9}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{514BC0B0-9097-47CF-9CEA-CEB431B828D9}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{EEA60BDC-FCAB-4154-B64B-F5BA15337A30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EEA60BDC-FCAB-4154-B64B-F5BA15337A30}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EEA60BDC-FCAB-4154-B64B-F5BA15337A30}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{EEA60BDC-FCAB-4154-B64B-F5BA15337A30}.Debug|iPhone.Build.0 = Debug|Any CPU
{EEA60BDC-FCAB-4154-B64B-F5BA15337A30}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{EEA60BDC-FCAB-4154-B64B-F5BA15337A30}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{EEA60BDC-FCAB-4154-B64B-F5BA15337A30}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EEA60BDC-FCAB-4154-B64B-F5BA15337A30}.Release|Any CPU.Build.0 = Release|Any CPU
{EEA60BDC-FCAB-4154-B64B-F5BA15337A30}.Release|iPhone.ActiveCfg = Release|Any CPU
{EEA60BDC-FCAB-4154-B64B-F5BA15337A30}.Release|iPhone.Build.0 = Release|Any CPU
{EEA60BDC-FCAB-4154-B64B-F5BA15337A30}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{EEA60BDC-FCAB-4154-B64B-F5BA15337A30}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -1154,6 +1182,8 @@ Global
{965EEC08-D454-44D3-8E53-5DC12CB8801C} = {50192AAF-25B6-447A-99AA-BA8161DBB594}
{DA6F7E8F-9A53-42BB-B29E-169C07EA1FD0} = {965EEC08-D454-44D3-8E53-5DC12CB8801C}
{1D22DA82-38EB-410C-88EA-37D3D786CCC5} = {175AB6E2-5FB5-4C15-94C2-DCA2EE6B0703}
{514BC0B0-9097-47CF-9CEA-CEB431B828D9} = {175AB6E2-5FB5-4C15-94C2-DCA2EE6B0703}
{EEA60BDC-FCAB-4154-B64B-F5BA15337A30} = {9B1F38B1-0661-4883-AD4D-ADA9ECA6941B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A645A7FF-3F09-414D-A391-7E50C3597F05}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<None Remove="component-generator.json" />
</ItemGroup>

<ItemGroup>
<AdditionalFiles Include="component-generator.json" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Xamarin.Forms.PancakeView" Version="1.4.2" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\Microsoft.MobileBlazorBindings\Microsoft.MobileBlazorBindings.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.MobileBlazorBindings.ComponentGenerator\Microsoft.MobileBlazorBindings.ComponentGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"rootNamespace": "Microsoft.MobileBlazorBindings.PancakeView.Elements",
"typesToGenerate": [
"Xamarin.Forms.PancakeView.PancakeView"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Microsoft.MobileBlazorBindings.PancakeView\Microsoft.MobileBlazorBindings.PancakeView.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.MobileBlazorBindings\Microsoft.MobileBlazorBindings.csproj" />
<ProjectReference Include="..\Microsoft.MobileBlazorBindings.PancakeView.SourceGenerator\Microsoft.MobileBlazorBindings.PancakeView.SourceGenerator.csproj" />
</ItemGroup>
</Project>
23 changes: 0 additions & 23 deletions src/ComponentWrapperGenerator/ComponentLocation.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>

Expand All @@ -17,6 +17,8 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.8.0" />
<PackageReference Include="Xamarin.Forms" Version="5.0.0.1874">
<IncludeAssets></IncludeAssets>
<PrivateAssets></PrivateAssets>
Expand All @@ -29,6 +31,10 @@
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Microsoft.MobileBlazorBindings.ComponentGenerator\Microsoft.MobileBlazorBindings.ComponentGenerator.csproj" />
</ItemGroup>

<Target Name="CopyXmlDocsToOutput" AfterTargets="Build">
<Message Text="Xamarin.Forms package location: $(PkgXamarin_Forms)" />
<Copy SourceFiles="$(PkgXamarin_Forms)\lib\netstandard2.0\Xamarin.Forms.Core.xml" DestinationFolder="$(OutDir)" />
Expand Down
11 changes: 0 additions & 11 deletions src/ComponentWrapperGenerator/GeneratorSettings.cs

This file was deleted.

95 changes: 50 additions & 45 deletions src/ComponentWrapperGenerator/Program.cs
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

using Microsoft.CodeAnalysis;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using System.Reflection;
using System.Threading.Tasks;

namespace ComponentWrapperGenerator
{
using Microsoft.MobileBlazorBindings.ComponentGenerator;

internal class Program
{
private static readonly List<ComponentLocation> ComponentLocations =
new List<ComponentLocation>
{
new ComponentLocation(typeof(Xamarin.Forms.Element).Assembly, "Xamarin.Forms", "XF", @"bin\Debug\netcoreapp3.0\Xamarin.Forms.Core.xml"),
new ComponentLocation(typeof(Xamarin.Forms.DualScreen.TwoPaneView).Assembly, "Xamarin.Forms.DualScreen", "XFD", null),
};

[System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1303:Do not pass literals as localized parameters", Justification = "<Pending>")]
internal static int Main(string[] args)
internal static async Task<int> Main(string[] args)
{
// Un-comment these lines for easier debugging
if (args.Length == 0)
Expand All @@ -45,9 +39,8 @@ internal static int Main(string[] args)
RootNamespace = "Microsoft.MobileBlazorBindings.Elements",
};

var xmlDocs = LoadXmlDocs(ComponentLocations.Select(loc => loc.XmlDocFilename).Where(loc => loc != null));

var generator = new ComponentWrapperGenerator(settings, xmlDocs);
var compilation = await GetRoslynCompilationAsync().ConfigureAwait(false);
var generator = new ComponentWrapperGenerator(settings);

foreach (var typeNameToGenerate in listOfTypeNamesToGenerate)
{
Expand All @@ -62,59 +55,71 @@ internal static int Main(string[] args)
continue;
}

if (!TryGetTypeToGenerate(typeNameToGenerate, out var typeToGenerate))
var typeToGenerate = compilation.GetTypeByMetadataName(typeNameToGenerate);

if (typeToGenerate == null)
{
Console.WriteLine($"WARNING: Couldn't find type {typeNameToGenerate}.");
Console.WriteLine();
continue;
}
generator.GenerateComponentWrapper(typeToGenerate, outputFolder);

var generatedSources = generator.GenerateComponentWrapper(typeToGenerate);
WriteFiles(generatedSources, outputFolder);

Console.WriteLine();
}

return 0;
}

private static IList<XmlDocument> LoadXmlDocs(IEnumerable<string> xmlDocLocations)
private static void WriteFiles((string HintName, string Source)[] generatedSources, string outputFolder)
{
var xmlDocs = new List<XmlDocument>();
foreach (var xmlDocLocation in xmlDocLocations)
foreach(var (hintName, source) in generatedSources)
{
var xmlDoc = new XmlDocument();
var fileName = $"{hintName}.generated.cs";
var path = hintName.EndsWith("Handler", StringComparison.Ordinal)
? Path.Combine(outputFolder, "Handlers")
: outputFolder;

// Depending on whether you run from VS or command line, the relative path of the XML docs will be
// different. There's undoubtedly a better way to do this, but this works great.
var xmlDocPath = Path.Combine(Directory.GetCurrentDirectory(), xmlDocLocation);
if (!File.Exists(xmlDocPath))
{
xmlDocPath = Path.Combine(Directory.GetCurrentDirectory(), Path.GetFileName(xmlDocLocation));
}
Directory.CreateDirectory(path);

xmlDoc.Load(xmlDocPath);
xmlDocs.Add(xmlDoc);
File.WriteAllText(Path.Combine(path, fileName), source);
}
return xmlDocs;
}

private static bool IsCommentLine(string typeNameToGenerate)
private static async Task<Compilation> GetRoslynCompilationAsync()
{
return typeNameToGenerate[0] == '#';
var metadataReferences = new[] {
MetadataReferenceFromAssembly(typeof(Xamarin.Forms.Element).Assembly),
MetadataReferenceFromAssembly(typeof(Xamarin.Forms.DualScreen.TwoPaneView).Assembly),
MetadataReferenceFromAssembly(typeof(object).Assembly),
MetadataReferenceFromAssembly(Assembly.Load(new AssemblyName("System.Runtime"))),
MetadataReferenceFromAssembly(Assembly.Load(new AssemblyName("netstandard")))
};

var projectName = "NewProject";
var projectInfo = ProjectInfo.Create(ProjectId.CreateNewId(), VersionStamp.Create(), projectName, projectName, LanguageNames.CSharp,
metadataReferences: metadataReferences);

using var workspace = new AdhocWorkspace();
var project = workspace.AddProject(projectInfo);

return await project.GetCompilationAsync().ConfigureAwait(false);
}

private static bool TryGetTypeToGenerate(string typeName, out Type typeToGenerate)
private static PortableExecutableReference MetadataReferenceFromAssembly(Assembly assembly)
{
foreach (var componentLocation in ComponentLocations)
{
var fullTypeName = componentLocation.NamespaceName + "." + typeName;
typeToGenerate = componentLocation.Assembly.GetType(fullTypeName);
if (typeToGenerate != null)
{
return true;
}
}
var assemblyPath = assembly.Location;
var xmlDocPath = Path.ChangeExtension(assemblyPath, "xml");
var docProvider = File.Exists(xmlDocPath) ? XmlDocumentationProvider.CreateFromFile(xmlDocPath) : null;

return MetadataReference.CreateFromFile(assemblyPath, documentation: docProvider);
}

typeToGenerate = null;
return false;
private static bool IsCommentLine(string typeNameToGenerate)
{
return typeNameToGenerate[0] == '#';
}
}
}
Loading