// 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; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using Microsoft.AspNetCore.Razor.Language.CodeGeneration; using Microsoft.AspNetCore.Razor.Language.Intermediate; namespace Microsoft.AspNetCore.Razor.Language { public static class RazorProjectEngineBuilderExtensions { /// /// Registers a class configuration delegate that gets invoked during code generation. /// /// The . /// invoked to configure /// during code generation. /// The . public static RazorProjectEngineBuilder ConfigureClass( this RazorProjectEngineBuilder builder, Action configureClass) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (configureClass == null) { throw new ArgumentNullException(nameof(configureClass)); } var configurationFeature = GetDefaultDocumentClassifierPassFeature(builder); configurationFeature.ConfigureClass.Add(configureClass); return builder; } /// /// Sets the base type for generated types. /// /// The . /// The name of the base type. /// The . public static RazorProjectEngineBuilder SetBaseType(this RazorProjectEngineBuilder builder, string baseType) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } var configurationFeature = GetDefaultDocumentClassifierPassFeature(builder); configurationFeature.ConfigureClass.Add((document, @class) => @class.BaseType = baseType); return builder; } /// /// Sets the namespace for generated types. /// /// The . /// The name of the namespace. /// The . public static RazorProjectEngineBuilder SetNamespace(this RazorProjectEngineBuilder builder, string namespaceName) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } var configurationFeature = GetDefaultDocumentClassifierPassFeature(builder); configurationFeature.ConfigureNamespace.Add((document, @namespace) => @namespace.Content = namespaceName); return builder; } public static void SetImportFeature(this RazorProjectEngineBuilder builder, IImportProjectFeature feature) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (feature == null) { throw new ArgumentNullException(nameof(builder)); } // Remove any existing import features in favor of the new one we're given. var existingFeatures = builder.Features.OfType().ToArray(); foreach (var existingFeature in existingFeatures) { builder.Features.Remove(existingFeature); } builder.Features.Add(feature); } /// /// Adds the specified . /// /// The . /// The to add. /// The . public static RazorProjectEngineBuilder AddTargetExtension(this RazorProjectEngineBuilder builder, ICodeTargetExtension extension) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (extension == null) { throw new ArgumentNullException(nameof(extension)); } var targetExtensionFeature = GetTargetExtensionFeature(builder); targetExtensionFeature.TargetExtensions.Add(extension); return builder; } /// /// Adds the specified . /// /// The . /// The to add. /// The . public static RazorProjectEngineBuilder AddDirective(this RazorProjectEngineBuilder builder, DirectiveDescriptor directive) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (directive == null) { throw new ArgumentNullException(nameof(directive)); } var directiveFeature = GetDirectiveFeature(builder); directiveFeature.Directives.Add(directive); return builder; } /// /// Adds the provided s as imports to all project items processed /// by the . /// /// The . /// The collection of imports. /// The . public static RazorProjectEngineBuilder AddDefaultImports(this RazorProjectEngineBuilder builder, params string[] imports) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } var existingImportFeature = builder.Features.OfType().First(); var testImportFeature = new AdditionalImportsProjectFeature(existingImportFeature, imports); builder.SetImportFeature(testImportFeature); return builder; } private static IRazorDirectiveFeature GetDirectiveFeature(RazorProjectEngineBuilder builder) { var directiveFeature = builder.Features.OfType().FirstOrDefault(); if (directiveFeature == null) { directiveFeature = new DefaultRazorDirectiveFeature(); builder.Features.Add(directiveFeature); } return directiveFeature; } private static IRazorTargetExtensionFeature GetTargetExtensionFeature(RazorProjectEngineBuilder builder) { var targetExtensionFeature = builder.Features.OfType().FirstOrDefault(); if (targetExtensionFeature == null) { targetExtensionFeature = new DefaultRazorTargetExtensionFeature(); builder.Features.Add(targetExtensionFeature); } return targetExtensionFeature; } private static DefaultDocumentClassifierPassFeature GetDefaultDocumentClassifierPassFeature(RazorProjectEngineBuilder builder) { var configurationFeature = builder.Features.OfType().FirstOrDefault(); if (configurationFeature == null) { configurationFeature = new DefaultDocumentClassifierPassFeature(); builder.Features.Add(configurationFeature); } return configurationFeature; } private class AdditionalImportsProjectFeature : RazorProjectEngineFeatureBase, IImportProjectFeature { private readonly IImportProjectFeature _existingImportFeature; private readonly IEnumerable _imports; public override RazorProjectEngine ProjectEngine { get => base.ProjectEngine; set { _existingImportFeature.ProjectEngine = value; base.ProjectEngine = value; } } public AdditionalImportsProjectFeature(IImportProjectFeature existingImportFeature, params string[] imports) { _existingImportFeature = existingImportFeature; _imports = imports.Select(import => new InMemoryProjectItem(import)); } public IReadOnlyList GetImports(RazorProjectItem projectItem) { var imports = _existingImportFeature.GetImports(projectItem).ToList(); imports.AddRange(_imports); return imports; } private class InMemoryProjectItem : RazorProjectItem { private readonly byte[] _importBytes; public InMemoryProjectItem(string content) { if (string.IsNullOrEmpty(content)) { throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(content)); } var preamble = Encoding.UTF8.GetPreamble(); var contentBytes = Encoding.UTF8.GetBytes(content); _importBytes = new byte[preamble.Length + contentBytes.Length]; preamble.CopyTo(_importBytes, 0); contentBytes.CopyTo(_importBytes, preamble.Length); } public override string BasePath => null; public override string FilePath => null; public override string PhysicalPath => null; public override bool Exists => true; public override Stream Read() => new MemoryStream(_importBytes); } } } }