|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation;
internal static partial class PageDirectiveFeature
{
private static readonly RazorProjectEngine PageDirectiveEngine = RazorProjectEngine.Create(RazorConfiguration.Default, new EmptyRazorProjectFileSystem(), builder =>
{
for (var i = builder.Phases.Count - 1; i >= 0; i--)
{
var phase = builder.Phases[i];
builder.Phases.RemoveAt(i);
if (phase is IRazorDocumentClassifierPhase)
{
break;
}
}
RazorExtensions.Register(builder);
builder.Features.Add(new PageDirectiveParserOptionsFeature());
});
public static bool TryGetPageDirective(ILogger logger, RazorProjectItem projectItem, [NotNullWhen(true)] out string? template)
{
ArgumentNullException.ThrowIfNull(projectItem);
var codeDocument = PageDirectiveEngine.Process(projectItem);
var documentIRNode = codeDocument.GetDocumentIntermediateNode();
if (PageDirective.TryGetPageDirective(documentIRNode, out var pageDirective))
{
if (pageDirective.DirectiveNode is MalformedDirectiveIntermediateNode malformedNode)
{
Log.MalformedPageDirective(logger, projectItem.FilePath, malformedNode.Diagnostics);
}
template = pageDirective.RouteTemplate;
return true;
}
template = null;
return false;
}
private sealed class PageDirectiveParserOptionsFeature : RazorEngineFeatureBase, IConfigureRazorParserOptionsFeature
{
public int Order { get; }
public void Configure(RazorParserOptionsBuilder options)
{
options.ParseLeadingDirectives = true;
}
}
private sealed class EmptyRazorProjectFileSystem : RazorProjectFileSystem
{
public override IEnumerable<RazorProjectItem> EnumerateItems(string basePath)
{
return Enumerable.Empty<RazorProjectItem>();
}
public override IEnumerable<RazorProjectItem> FindHierarchicalItems(string basePath, string path, string fileName)
{
return Enumerable.Empty<RazorProjectItem>();
}
public override RazorProjectItem GetItem(string path)
{
return GetItem(path, fileKind: null);
}
public override RazorProjectItem GetItem(string path, string? fileKind)
{
return new NotFoundProjectItem(string.Empty, path, fileKind);
}
private sealed class NotFoundProjectItem : RazorProjectItem
{
public NotFoundProjectItem(string basePath, string path, string? fileKind)
{
BasePath = basePath;
FilePath = path;
FileKind = fileKind ?? FileKinds.GetFileKindFromFilePath(FilePath);
}
/// <inheritdoc />
public override string BasePath { get; }
/// <inheritdoc />
public override string FilePath { get; }
/// <inheritdoc />
public override string FileKind { get; }
/// <inheritdoc />
public override bool Exists => false;
/// <inheritdoc />
public override string PhysicalPath => throw new NotSupportedException();
/// <inheritdoc />
public override Stream Read() => throw new NotSupportedException();
}
}
private static partial class Log
{
[LoggerMessage(104, LogLevel.Warning, "The page directive at '{FilePath}' is malformed. Please fix the following issues: {Diagnostics}", EventName = "MalformedPageDirective", SkipEnabledCheck = true)]
private static partial void MalformedPageDirective(ILogger logger, string filePath, string[] diagnostics);
public static void MalformedPageDirective(ILogger logger, string filePath, IList<RazorDiagnostic> diagnostics)
{
if (logger.IsEnabled(LogLevel.Warning))
{
var messages = new string[diagnostics.Count];
for (var i = 0; i < diagnostics.Count; i++)
{
messages[i] = diagnostics[i].GetMessage(CultureInfo.CurrentCulture);
}
MalformedPageDirective(logger, filePath, messages);
}
}
}
}
|