Add prelimianry support for extensions to Razor (#2012)
* Add prelimianry support for extensions to Razor
This PR adds MSBuild insfrastructure to the SDK that can understand
concepts we need to expose to the project, code generator and runtime
like:
- Language version
- Configuration
- Extensions (plugins)
As an example of how this works, I've done the wireup for MVC. This will
now generate assembly attributes in your application that can act as a
source-of-truth for what should be included in runtime compilation, and
it's all based on the project-file. This means that it can be delivered
and configured by packages.
The next step here is to implement a loader for RazorProjectEngine based
on these primitives, and then use it in our CLI tools and MVC.
The next step after that is to expose it in VS and VS4Mac through the
project system.
(cherry picked from commit 5b28c06d64)
This commit is contained in:
parent
eb5abc6ac5
commit
870f023aa9
|
|
@ -822,6 +822,20 @@ namespace Microsoft.AspNetCore.Razor.Language
|
|||
internal static string FormatSectionDirective_NameToken_Name()
|
||||
=> GetString("SectionDirective_NameToken_Name");
|
||||
|
||||
/// <summary>
|
||||
/// The Razor language version '{0}' is unrecognized or not supported by this version of Razor.
|
||||
/// </summary>
|
||||
internal static string RazorLanguageVersion_InvalidVersion
|
||||
{
|
||||
get => GetString("RazorLanguageVersion_InvalidVersion");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Razor language version '{0}' is unrecognized or not supported by this version of Razor.
|
||||
/// </summary>
|
||||
internal static string FormatRazorLanguageVersion_InvalidVersion(object p0)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("RazorLanguageVersion_InvalidVersion"), p0);
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
|
|
|||
|
|
@ -2,25 +2,58 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Language
|
||||
{
|
||||
public sealed class RazorConfiguration
|
||||
{
|
||||
public static readonly RazorConfiguration DefaultRuntime = new RazorConfiguration(RazorLanguageVersion.Latest, designTime: false);
|
||||
public static readonly RazorConfiguration DefaultDesignTime = new RazorConfiguration(RazorLanguageVersion.Latest, designTime: true);
|
||||
public static readonly RazorConfiguration Default = new RazorConfiguration(
|
||||
RazorLanguageVersion.Latest,
|
||||
"unnamed",
|
||||
Array.Empty<RazorExtension>(),
|
||||
designTime: false);
|
||||
|
||||
public RazorConfiguration(RazorLanguageVersion languageVersion, bool designTime)
|
||||
// This is used only in some back-compat scenarios. We don't expose it because there's no
|
||||
// use case for anyone else to use it.
|
||||
internal static readonly RazorConfiguration DefaultDesignTime = new RazorConfiguration(
|
||||
RazorLanguageVersion.Latest,
|
||||
"unnamed",
|
||||
Array.Empty<RazorExtension>(),
|
||||
designTime: true);
|
||||
|
||||
public RazorConfiguration(
|
||||
RazorLanguageVersion languageVersion,
|
||||
string configurationName,
|
||||
IEnumerable<RazorExtension> extensions,
|
||||
bool designTime)
|
||||
{
|
||||
if (languageVersion == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(languageVersion));
|
||||
}
|
||||
|
||||
if (configurationName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurationName));
|
||||
}
|
||||
|
||||
if (extensions == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(extensions));
|
||||
}
|
||||
|
||||
LanguageVersion = languageVersion;
|
||||
ConfigurationName = configurationName;
|
||||
Extensions = extensions.ToArray();
|
||||
DesignTime = designTime;
|
||||
}
|
||||
|
||||
public string ConfigurationName { get; }
|
||||
|
||||
public IReadOnlyList<RazorExtension> Extensions { get; }
|
||||
|
||||
public RazorLanguageVersion LanguageVersion { get; }
|
||||
|
||||
public bool DesignTime { get; }
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Razor.Language
|
|||
return Create(configure: null);
|
||||
}
|
||||
|
||||
public static RazorEngine Create(Action<IRazorEngineBuilder> configure) => CreateCore(RazorConfiguration.DefaultRuntime, configure);
|
||||
public static RazorEngine Create(Action<IRazorEngineBuilder> configure) => CreateCore(RazorConfiguration.Default, configure);
|
||||
|
||||
public static RazorEngine CreateDesignTime()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
// Copyright(c) .NET Foundation.All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Language
|
||||
{
|
||||
public abstract class RazorExtension
|
||||
{
|
||||
public abstract string ExtensionName { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -2,10 +2,12 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Language
|
||||
{
|
||||
public sealed class RazorLanguageVersion : IEquatable<RazorLanguageVersion>
|
||||
[DebuggerDisplay("{" + nameof(DebuggerToString) + "(),nq}")]
|
||||
public sealed class RazorLanguageVersion : IEquatable<RazorLanguageVersion>, IComparable<RazorLanguageVersion>
|
||||
{
|
||||
public static readonly RazorLanguageVersion Version_1_0 = new RazorLanguageVersion(1, 0);
|
||||
|
||||
|
|
@ -17,6 +19,60 @@ namespace Microsoft.AspNetCore.Razor.Language
|
|||
|
||||
public static readonly RazorLanguageVersion Latest = Version_2_1;
|
||||
|
||||
public static bool TryParse(string languageVersion, out RazorLanguageVersion version)
|
||||
{
|
||||
if (languageVersion == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(languageVersion));
|
||||
}
|
||||
|
||||
if (string.Equals(languageVersion, "latest", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
version = Version_2_1;
|
||||
return true;
|
||||
}
|
||||
else if (languageVersion == "2.1")
|
||||
{
|
||||
version = Version_2_1;
|
||||
return true;
|
||||
}
|
||||
else if (languageVersion == "2.0")
|
||||
{
|
||||
version = Version_2_0;
|
||||
return true;
|
||||
}
|
||||
else if (languageVersion == "1.1")
|
||||
{
|
||||
version = Version_1_1;
|
||||
return true;
|
||||
}
|
||||
else if (languageVersion == "1.0")
|
||||
{
|
||||
version = Version_1_0;
|
||||
return true;
|
||||
}
|
||||
|
||||
version = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static RazorLanguageVersion Parse(string languageVersion)
|
||||
{
|
||||
if (languageVersion == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(languageVersion));
|
||||
}
|
||||
|
||||
if (TryParse(languageVersion, out var parsed))
|
||||
{
|
||||
return parsed;
|
||||
}
|
||||
|
||||
throw new ArgumentException(
|
||||
Resources.FormatRazorLanguageVersion_InvalidVersion(languageVersion),
|
||||
nameof(languageVersion));
|
||||
}
|
||||
|
||||
// Don't want anyone else constructing language versions.
|
||||
private RazorLanguageVersion(int major, int minor)
|
||||
{
|
||||
|
|
@ -28,6 +84,22 @@ namespace Microsoft.AspNetCore.Razor.Language
|
|||
|
||||
public int Minor { get; }
|
||||
|
||||
public int CompareTo(RazorLanguageVersion other)
|
||||
{
|
||||
if (other == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(other));
|
||||
}
|
||||
|
||||
var result = Major.CompareTo(other.Major);
|
||||
if (result != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return Minor.CompareTo(other.Minor);
|
||||
}
|
||||
|
||||
public bool Equals(RazorLanguageVersion other)
|
||||
{
|
||||
if (other == null)
|
||||
|
|
@ -44,7 +116,9 @@ namespace Microsoft.AspNetCore.Razor.Language
|
|||
// We don't need to do anything special for our hash code since reference equality is what we're going for.
|
||||
return base.GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString() => $"{Major}.{Minor}";
|
||||
|
||||
public override string ToString() => $"Razor '{Major}.{Minor}'";
|
||||
private string DebuggerToString() => $"Razor '{Major}.{Minor}'";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,9 @@ namespace Microsoft.AspNetCore.Razor.Language
|
|||
{
|
||||
var allowMinimizedBooleanTagHelperAttributes = false;
|
||||
|
||||
if (version == RazorLanguageVersion.Version_2_1)
|
||||
if (version.CompareTo(RazorLanguageVersion.Version_2_1) >= 0)
|
||||
{
|
||||
// Added in 2.1
|
||||
allowMinimizedBooleanTagHelperAttributes = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -291,4 +291,7 @@
|
|||
<data name="SectionDirective_NameToken_Name" xml:space="preserve">
|
||||
<value>SectionName</value>
|
||||
</data>
|
||||
<data name="RazorLanguageVersion_InvalidVersion" xml:space="preserve">
|
||||
<value>The Razor language version '{0}' is unrecognized or not supported by this version of Razor.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Hosting
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the name of a Razor configuration as defined by the Razor SDK.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This attribute is applied to an application's entry point assembly by the Razor SDK during the build,
|
||||
/// so that the Razor configuration can be loaded at runtime based on the settings provided by the project
|
||||
/// file.
|
||||
/// </remarks>
|
||||
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false, Inherited = false)]
|
||||
public sealed class RazorConfigurationNameAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="RazorConfigurationNameAttribute"/>.
|
||||
/// </summary>
|
||||
/// <param name="configurationName">The name of the Razor configuration.</param>
|
||||
public RazorConfigurationNameAttribute(string configurationName)
|
||||
{
|
||||
if (configurationName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurationName));
|
||||
}
|
||||
|
||||
ConfigurationName = configurationName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the Razor configuration.
|
||||
/// </summary>
|
||||
public string ConfigurationName { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Hosting
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the name of a Razor extension as defined by the Razor SDK.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This attribute is applied to an application's entry point assembly by the Razor SDK during the build,
|
||||
/// so that the Razor configuration can be loaded at runtime based on the settings provided by the project
|
||||
/// file.
|
||||
/// </remarks>
|
||||
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)]
|
||||
public sealed class RazorExtensionAssemblyNameAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="RazorExtensionAssemblyNameAttribute"/>.
|
||||
/// </summary>
|
||||
/// <param name="extensionName">The name of the extension.</param>
|
||||
/// <param name="assemblyName">The assembly name of the extension.</param>
|
||||
public RazorExtensionAssemblyNameAttribute(string extensionName, string assemblyName)
|
||||
{
|
||||
if (extensionName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(extensionName));
|
||||
}
|
||||
|
||||
if (assemblyName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(assemblyName));
|
||||
}
|
||||
|
||||
ExtensionName = extensionName;
|
||||
AssemblyName = assemblyName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the assembly name of the extension.
|
||||
/// </summary>
|
||||
public string AssemblyName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the extension.
|
||||
/// </summary>
|
||||
public string ExtensionName { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Hosting
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the name of a Razor configuration as defined by the Razor SDK.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This attribute is part of a set of metadata attributes that can be applied to an assembly at build
|
||||
/// time by the Razor SDK. These attributes allow the Razor configuration to be loaded at runtime based
|
||||
/// on the settings originally provided by the project file.
|
||||
/// </remarks>
|
||||
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false, Inherited = false)]
|
||||
public sealed class RazorLanguageVersionAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="RazorLanguageVersionAttribute"/>.
|
||||
/// </summary>
|
||||
/// <param name="languageVersion">The language version of Razor</param>
|
||||
public RazorLanguageVersionAttribute(string languageVersion)
|
||||
{
|
||||
if (languageVersion == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(languageVersion));
|
||||
}
|
||||
|
||||
LanguageVersion = languageVersion;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Razor language version.
|
||||
/// </summary>
|
||||
public string LanguageVersion { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -43,7 +43,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
|||
var project = FindProject(projectPath);
|
||||
var configuration = (project?.Configuration as MvcExtensibilityConfiguration) ?? DefaultConfiguration;
|
||||
var razorLanguageVersion = configuration.LanguageVersion;
|
||||
var razorConfiguration = new RazorConfiguration(razorLanguageVersion, designTime: true);
|
||||
var razorConfiguration = new RazorConfiguration(razorLanguageVersion, "unnamed", Array.Empty<RazorExtension>(), designTime: true);
|
||||
|
||||
RazorEngine engine;
|
||||
if (razorLanguageVersion.Major == 1)
|
||||
|
|
|
|||
Loading…
Reference in New Issue