diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/src/MvcImportProjectFeature.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/src/MvcImportProjectFeature.cs index 254c57c1c4..e117a5298c 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/src/MvcImportProjectFeature.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/src/MvcImportProjectFeature.cs @@ -21,6 +21,12 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X throw new ArgumentNullException(nameof(projectItem)); } + // Don't add MVC imports for a component - this shouldn't happen for v1, but just in case. + if (string.Equals(projectItem.FileKind, FileKinds.Component, StringComparison.OrdinalIgnoreCase)) + { + return Array.Empty(); + } + var imports = new List(); AddDefaultDirectivesImport(imports); diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/src/RazorExtensions.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/src/RazorExtensions.cs index 55e8929457..f8cf7f5cb4 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/src/RazorExtensions.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/src/RazorExtensions.cs @@ -37,7 +37,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X builder.Features.Add(new ModelExpressionPass()); builder.Features.Add(new MvcViewDocumentClassifierPass()); - builder.SetImportFeature(new MvcImportProjectFeature()); + builder.Features.Add(new MvcImportProjectFeature()); } public static void RegisterViewComponentTagHelpers(RazorProjectEngineBuilder builder) diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/InjectDirectiveTest.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/InjectDirectiveTest.cs index a5579d645a..63560c0f1f 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/InjectDirectiveTest.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/InjectDirectiveTest.cs @@ -1,6 +1,7 @@ // 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.Text; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Intermediate; @@ -173,7 +174,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X private RazorEngine CreateEngine() { - return RazorProjectEngine.Create(b => + var configuration = RazorConfiguration.Create(RazorLanguageVersion.Version_1_1, "test", Array.Empty()); + return RazorProjectEngine.Create(configuration, RazorProjectFileSystem.Empty, b => { // Notice we're not registering the InjectDirective.Pass here so we can run it on demand. b.AddDirective(InjectDirective.Directive); diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/ModelDirectiveTest.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/ModelDirectiveTest.cs index cc6cf53097..7a4c811dbd 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/ModelDirectiveTest.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/ModelDirectiveTest.cs @@ -11,8 +11,10 @@ using Xunit; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X { - public class ModelDirectiveTest + public class ModelDirectiveTest : RazorProjectEngineTestBase { + protected override RazorLanguageVersion Version => RazorLanguageVersion.Version_1_1; + [Fact] public void ModelDirective_GetModelType_GetsTypeFromFirstWellFormedDirective() { @@ -23,7 +25,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X @model "); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var irDocument = CreateIRDocument(engine, codeDocument); @@ -40,7 +42,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X // Arrange var codeDocument = CreateDocument(@" "); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var irDocument = CreateIRDocument(engine, codeDocument); @@ -60,7 +62,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X @model Type1 "); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var pass = new ModelDirective.Pass() { Engine = engine, @@ -87,7 +89,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X @model Type2 "); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var pass = new ModelDirective.Pass() { Engine = engine, @@ -113,7 +115,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X @model Type1 "); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var pass = new ModelDirective.Pass() { Engine = engine, @@ -138,7 +140,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X @inherits BaseType "); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var pass = new ModelDirective.Pass() { Engine = engine, @@ -234,7 +236,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X return visitor.Node; } - private RazorEngine CreateEngine() + private RazorEngine CreateRuntimeEngine() { return CreateEngineCore(); } @@ -246,7 +248,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X private RazorEngine CreateEngineCore(bool designTime = false) { - return RazorProjectEngine.Create(b => + return CreateProjectEngine(b => { // Notice we're not registering the ModelDirective.Pass here so we can run it on demand. b.AddDirective(ModelDirective.Directive); diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/MvcRazorTemplateEngineTest.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/MvcRazorTemplateEngineTest.cs index 45186848ae..eca2b8d49b 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/MvcRazorTemplateEngineTest.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/MvcRazorTemplateEngineTest.cs @@ -8,8 +8,10 @@ using Xunit; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X { - public class MvcRazorTemplateEngineTest + public class MvcRazorTemplateEngineTest : RazorProjectEngineTestBase { + protected override RazorLanguageVersion Version => RazorLanguageVersion.Version_1_1; + [Fact] public void GetDefaultImports_IncludesDefaultImports() { @@ -25,7 +27,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X "@using Microsoft.AspNetCore.Mvc.ViewFeatures", }; var mvcRazorTemplateEngine = new MvcRazorTemplateEngine( - RazorProjectEngine.Create().Engine, + CreateProjectEngine().Engine, new TestRazorProjectFileSystem()); // Act @@ -51,7 +53,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X "@inject global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider", }; var mvcRazorTemplateEngine = new MvcRazorTemplateEngine( - RazorProjectEngine.Create().Engine, + CreateProjectEngine().Engine, new TestRazorProjectFileSystem()); // Act @@ -69,7 +71,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X { // Arrange var mvcRazorTemplateEngine = new MvcRazorTemplateEngine( - RazorProjectEngine.Create().Engine, + CreateProjectEngine().Engine, new TestRazorProjectFileSystem()); // Act diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/MvcViewDocumentClassifierPassTest.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/MvcViewDocumentClassifierPassTest.cs index 663aff4518..a0a3825267 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/MvcViewDocumentClassifierPassTest.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/test/MvcViewDocumentClassifierPassTest.cs @@ -7,8 +7,10 @@ using Xunit; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X { - public class MvcViewDocumentClassifierPassTest + public class MvcViewDocumentClassifierPassTest : RazorProjectEngineTestBase { + protected override RazorLanguageVersion Version => RazorLanguageVersion.Version_1_1; + [Fact] public void MvcViewDocumentClassifierPass_SetsDocumentKind() { @@ -217,8 +219,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X Assert.Equal(new[] { "public", "async", "override" }, visitor.Method.Modifiers); } - private static RazorProjectEngine CreateProjectEngine() => RazorProjectEngine.Create(); - private static DocumentIntermediateNode CreateIRDocument(RazorProjectEngine engine, RazorCodeDocument codeDocument) { for (var i = 0; i < engine.Phases.Count; i++) diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/src/MvcImportProjectFeature.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/src/MvcImportProjectFeature.cs index c25cb0d063..d7844d9eee 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/src/MvcImportProjectFeature.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/src/MvcImportProjectFeature.cs @@ -21,6 +21,12 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X throw new ArgumentNullException(nameof(projectItem)); } + // Don't add MVC imports for a component - this shouldn't happen for v2, but just in case. + if (string.Equals(projectItem.FileKind, FileKinds.Component, StringComparison.OrdinalIgnoreCase)) + { + return Array.Empty(); + } + var imports = new List(); AddDefaultDirectivesImport(imports); diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/src/RazorExtensions.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/src/RazorExtensions.cs index 69cf7e2055..0e52eb00d1 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/src/RazorExtensions.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/src/RazorExtensions.cs @@ -17,6 +17,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X throw new ArgumentNullException(nameof(builder)); } + FunctionsDirective.Register(builder); InjectDirective.Register(builder); ModelDirective.Register(builder); NamespaceDirective.Register(builder); @@ -42,7 +43,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X builder.Features.Add(new AssemblyAttributeInjectionPass()); builder.Features.Add(new InstrumentationPass()); - builder.SetImportFeature(new MvcImportProjectFeature()); + builder.Features.Add(new MvcImportProjectFeature()); } } } diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/src/RazorPageDocumentClassifierPass.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/src/RazorPageDocumentClassifierPass.cs index a5de7d0783..b11912ff81 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/src/RazorPageDocumentClassifierPass.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/src/RazorPageDocumentClassifierPass.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X public static readonly string RouteTemplateKey = "RouteTemplate"; private static readonly RazorProjectEngine LeadingDirectiveParsingEngine = RazorProjectEngine.Create( - RazorConfiguration.Default, + RazorConfiguration.Create(RazorLanguageVersion.Version_2_1, "leading-directive-parser", Array.Empty()), RazorProjectFileSystem.Create("/"), builder => { diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/AssemblyAttributeInjectionPassTest.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/AssemblyAttributeInjectionPassTest.cs index 4dbe6c72b4..29127a5cd3 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/AssemblyAttributeInjectionPassTest.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/AssemblyAttributeInjectionPassTest.cs @@ -7,8 +7,10 @@ using Xunit; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X { - public class AssemblyAttributeInjectionPassTest + public class AssemblyAttributeInjectionPassTest : RazorProjectEngineTestBase { + protected override RazorLanguageVersion Version => RazorLanguageVersion.Version_2_1; + [Fact] public void Execute_NoOps_IfNamespaceNodeIsMissing() { @@ -20,7 +22,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X var pass = new AssemblyAttributeInjectionPass { - Engine = RazorProjectEngine.Create().Engine, + Engine = CreateProjectEngine().Engine, }; // Act @@ -45,7 +47,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X var pass = new AssemblyAttributeInjectionPass { - Engine = RazorProjectEngine.Create().Engine, + Engine = CreateProjectEngine().Engine, }; // Act @@ -71,7 +73,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X var pass = new AssemblyAttributeInjectionPass { - Engine = RazorProjectEngine.Create().Engine, + Engine = CreateProjectEngine().Engine, }; // Act @@ -112,7 +114,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X var pass = new AssemblyAttributeInjectionPass { - Engine = RazorProjectEngine.Create().Engine, + Engine = CreateProjectEngine().Engine, }; // Act @@ -147,7 +149,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X var pass = new AssemblyAttributeInjectionPass { - Engine = RazorProjectEngine.Create().Engine, + Engine = CreateProjectEngine().Engine, }; // Act @@ -190,7 +192,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X var pass = new AssemblyAttributeInjectionPass { - Engine = RazorProjectEngine.Create().Engine, + Engine = CreateProjectEngine().Engine, }; var source = TestRazorSourceDocument.Create("test", new RazorSourceDocumentProperties(filePath: null, relativePath: "/Views/Index.cshtml")); @@ -237,7 +239,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X var pass = new AssemblyAttributeInjectionPass { - Engine = RazorProjectEngine.Create().Engine, + Engine = CreateProjectEngine().Engine, }; var source = TestRazorSourceDocument.Create("test", new RazorSourceDocumentProperties(filePath: null, relativePath: "/Views/Index.cshtml")); @@ -290,7 +292,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X var pass = new AssemblyAttributeInjectionPass { - Engine = RazorProjectEngine.Create().Engine, + Engine = CreateProjectEngine().Engine, }; var source = TestRazorSourceDocument.Create("test", new RazorSourceDocumentProperties(filePath: null, relativePath: "\\test\\\"Index.cshtml")); @@ -349,7 +351,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X var pass = new AssemblyAttributeInjectionPass { - Engine = RazorProjectEngine.Create().Engine, + Engine = CreateProjectEngine().Engine, }; var source = TestRazorSourceDocument.Create("test", new RazorSourceDocumentProperties(filePath: null, relativePath: "/Views/Index.cshtml")); @@ -404,7 +406,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X var pass = new AssemblyAttributeInjectionPass { - Engine = RazorProjectEngine.Create().Engine, + Engine = CreateProjectEngine().Engine, }; var source = TestRazorSourceDocument.Create("test", new RazorSourceDocumentProperties(filePath: null, relativePath: "test\\\"Index.cshtml")); diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/IntegrationTests/InstrumentationPassIntegrationTest.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/IntegrationTests/InstrumentationPassIntegrationTest.cs index 604100a335..58d6a46df0 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/IntegrationTests/InstrumentationPassIntegrationTest.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/IntegrationTests/InstrumentationPassIntegrationTest.cs @@ -6,12 +6,28 @@ using System.Collections.Generic; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Extensions; using Microsoft.AspNetCore.Razor.Language.IntegrationTests; +using Microsoft.CodeAnalysis.CSharp; using Xunit; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X.IntegrationTests { public class InstrumentationPassIntegrationTest : IntegrationTestBase { + private readonly static CSharpCompilation DefaultBaseCompilation = MvcShim.BaseCompilation.WithAssemblyName("AppCode"); + + public InstrumentationPassIntegrationTest() + : base(generateBaselines: null) + { + Configuration = RazorConfiguration.Create( + RazorLanguageVersion.Version_2_0, + "MVC-2.1", + new[] { new AssemblyExtension("MVC-2.1", typeof(ExtensionInitializer).Assembly) }); + } + + protected override CSharpCompilation BaseCompilation => DefaultBaseCompilation; + + protected override RazorConfiguration Configuration { get; } + [Fact] public void BasicTest() { diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/ModelDirectiveTest.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/ModelDirectiveTest.cs index eedc94d581..d01195906b 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/ModelDirectiveTest.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/ModelDirectiveTest.cs @@ -1,8 +1,6 @@ // 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.IO; using System.Text; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Extensions; @@ -11,8 +9,10 @@ using Xunit; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X { - public class ModelDirectiveTest + public class ModelDirectiveTest : RazorProjectEngineTestBase { + protected override RazorLanguageVersion Version => RazorLanguageVersion.Version_2_1; + [Fact] public void ModelDirective_GetModelType_GetsTypeFromFirstWellFormedDirective() { @@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X @model "); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var irDocument = CreateIRDocument(engine, codeDocument); @@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X // Arrange var codeDocument = CreateDocument(@" "); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var irDocument = CreateIRDocument(engine, codeDocument); @@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X @model Type1 "); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var pass = new ModelDirective.Pass() { Engine = engine, @@ -87,7 +87,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X @model Type2 "); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var pass = new ModelDirective.Pass() { Engine = engine, @@ -113,7 +113,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X @model Type1 "); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var pass = new ModelDirective.Pass() { Engine = engine, @@ -138,7 +138,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X @inherits BaseType "); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var pass = new ModelDirective.Pass() { Engine = engine, @@ -234,7 +234,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X return visitor.Node; } - private RazorEngine CreateEngine() + private RazorEngine CreateRuntimeEngine() { return CreateEngineCore(); } @@ -246,7 +246,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X private RazorEngine CreateEngineCore(bool designTime = false) { - return RazorProjectEngine.Create(b => + return CreateProjectEngine(b => { // Notice we're not registering the ModelDirective.Pass here so we can run it on demand. b.AddDirective(ModelDirective.Directive); diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/MvcViewDocumentClassifierPassTest.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/MvcViewDocumentClassifierPassTest.cs index 2d437c158d..455ed1ba21 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/MvcViewDocumentClassifierPassTest.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/MvcViewDocumentClassifierPassTest.cs @@ -7,8 +7,10 @@ using Xunit; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X { - public class MvcViewDocumentClassifierPassTest + public class MvcViewDocumentClassifierPassTest : RazorProjectEngineTestBase { + protected override RazorLanguageVersion Version => RazorLanguageVersion.Version_2_1; + [Fact] public void MvcViewDocumentClassifierPass_SetsDocumentKind() { @@ -217,8 +219,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X Assert.Equal(new[] { "public", "async", "override" }, visitor.Method.Modifiers); } - private static RazorProjectEngine CreateProjectEngine() => RazorProjectEngine.Create(); - private static DocumentIntermediateNode CreateIRDocument(RazorProjectEngine projectEngine, RazorCodeDocument codeDocument) { for (var i = 0; i < projectEngine.Phases.Count; i++) diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/RazorPageDocumentClassifierPassTest.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/RazorPageDocumentClassifierPassTest.cs index 74acfa0c13..8e9f111579 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/RazorPageDocumentClassifierPassTest.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/RazorPageDocumentClassifierPassTest.cs @@ -9,8 +9,10 @@ using Xunit; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X { - public class RazorPageDocumentClassifierPassTest + public class RazorPageDocumentClassifierPassTest : RazorProjectEngineTestBase { + protected override RazorLanguageVersion Version => RazorLanguageVersion.Version_2_1; + [Fact] public void RazorPageDocumentClassifierPass_LogsErrorForImportedPageDirectives() { @@ -20,7 +22,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X var importDocument = RazorSourceDocument.Create("@page", "import.cshtml"); var sourceDocument = RazorSourceDocument.Create("

Hello World

", "main.cshtml"); var codeDocument = RazorCodeDocument.Create(sourceDocument, new[] { importDocument }); - var engine = CreateEngine(); + var engine = CreateProjectEngine().Engine; var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -55,7 +57,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X "; var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create(content, "Test.cshtml")); - var engine = CreateEngine(); + var engine = CreateProjectEngine().Engine; var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -85,7 +87,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X "; var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create(content, "Test.cshtml")); - var engine = CreateEngine(); + var engine = CreateProjectEngine().Engine; var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -109,7 +111,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X // Arrange var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page", "Test.cshtml")); - var engine = CreateEngine(); + var engine = CreateProjectEngine().Engine; var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -129,7 +131,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X // Arrange var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page", "Test.cshtml")); - var engine = CreateEngine(); + var engine = CreateProjectEngine().Engine; var irDocument = CreateIRDocument(engine, codeDocument); irDocument.DocumentKind = "some-value"; var pass = new RazorPageDocumentClassifierPass @@ -150,7 +152,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X // Arrange var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page+1", "Test.cshtml")); - var engine = CreateEngine(); + var engine = CreateProjectEngine().Engine; var irDocument = CreateIRDocument(engine, codeDocument); irDocument.DocumentKind = "some-value"; var pass = new RazorPageDocumentClassifierPass @@ -171,7 +173,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X // Arrange var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page", "Test.cshtml")); - var engine = CreateEngine(); + var engine = CreateProjectEngine().Engine; var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -194,7 +196,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X var properties = new RazorSourceDocumentProperties(filePath: "ignored", relativePath: "Test.cshtml"); var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page", properties)); - var engine = CreateEngine(); + var engine = CreateProjectEngine().Engine; var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -219,7 +221,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X var properties = new RazorSourceDocumentProperties(filePath: null, relativePath: null); var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page", properties)); - var engine = CreateEngine(); + var engine = CreateProjectEngine().Engine; var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -246,7 +248,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X var properties = new RazorSourceDocumentProperties(filePath: "ignored", relativePath: relativePath); var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page", properties)); - var engine = CreateEngine(); + var engine = CreateProjectEngine().Engine; var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -269,7 +271,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X var properties = new RazorSourceDocumentProperties(filePath: @"x::\application\Views\Home\Index.cshtml", relativePath: null); var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page", properties)); - var engine = CreateEngine(); + var engine = CreateProjectEngine().Engine; var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -292,7 +294,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X var properties = new RazorSourceDocumentProperties(filePath: @"x:\Test.cshtml", relativePath: "path.with+invalid-chars"); var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page", properties)); - var engine = CreateEngine(); + var engine = CreateProjectEngine().Engine; var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -314,7 +316,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X // Arrange var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page", "Test.cshtml")); - var engine = CreateEngine(); + var engine = CreateProjectEngine().Engine; var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -339,7 +341,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X var properties = new RazorSourceDocumentProperties(filePath: "ignored", relativePath: "Test.cshtml"); var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page \"some-route\"", properties)); - var engine = CreateEngine(); + var engine = CreateProjectEngine().Engine; var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -357,14 +359,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X Assert.Equal("some-route", attributeNode.Value); } - private static RazorEngine CreateEngine() + protected override void ConfigureProjectEngine(RazorProjectEngineBuilder builder) { - return RazorProjectEngine.Create(b => - { - PageDirective.Register(b); - }).Engine; + PageDirective.Register(builder); } - + private static DocumentIntermediateNode CreateIRDocument(RazorEngine engine, RazorCodeDocument codeDocument) { for (var i = 0; i < engine.Phases.Count; i++) diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/TestFiles/IntegrationTests/InstrumentationPassIntegrationTest/BasicTest.codegen.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/TestFiles/IntegrationTests/InstrumentationPassIntegrationTest/BasicTest.codegen.cs index 8c5b2e0f79..804cb2af89 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/TestFiles/IntegrationTests/InstrumentationPassIntegrationTest/BasicTest.codegen.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/TestFiles/IntegrationTests/InstrumentationPassIntegrationTest/BasicTest.codegen.cs @@ -1,12 +1,20 @@ #pragma checksum "TestFiles/IntegrationTests/InstrumentationPassIntegrationTest/BasicTest.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "78993008d95836bec2b9175d4294bf7bd5f5f109" // #pragma warning disable 1591 -[assembly: global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemAttribute(typeof(Razor.Template), @"default", @"/TestFiles/IntegrationTests/InstrumentationPassIntegrationTest/BasicTest.cshtml")] -namespace Razor +[assembly: global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemAttribute(typeof(AspNetCore.TestFiles_IntegrationTests_InstrumentationPassIntegrationTest_BasicTest), @"mvc.1.0.view", @"/TestFiles/IntegrationTests/InstrumentationPassIntegrationTest/BasicTest.cshtml")] +[assembly:global::Microsoft.AspNetCore.Mvc.Razor.Compilation.RazorViewAttribute(@"/TestFiles/IntegrationTests/InstrumentationPassIntegrationTest/BasicTest.cshtml", typeof(AspNetCore.TestFiles_IntegrationTests_InstrumentationPassIntegrationTest_BasicTest))] +namespace AspNetCore { #line hidden + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Rendering; + using Microsoft.AspNetCore.Mvc.ViewFeatures; [global::Microsoft.AspNetCore.Razor.Hosting.RazorSourceChecksumAttribute(@"SHA1", @"78993008d95836bec2b9175d4294bf7bd5f5f109", @"/TestFiles/IntegrationTests/InstrumentationPassIntegrationTest/BasicTest.cshtml")] - public class Template + public class TestFiles_IntegrationTests_InstrumentationPassIntegrationTest_BasicTest : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage { private static readonly global::Microsoft.AspNetCore.Razor.TagHelpers.TagHelperAttribute __tagHelperAttribute_0 = new global::Microsoft.AspNetCore.Razor.TagHelpers.TagHelperAttribute("value", "Hello", global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.DoubleQuotes); private static readonly global::Microsoft.AspNetCore.Razor.TagHelpers.TagHelperAttribute __tagHelperAttribute_1 = new global::Microsoft.AspNetCore.Razor.TagHelpers.TagHelperAttribute("type", new global::Microsoft.AspNetCore.Html.HtmlString("text"), global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.SingleQuotes); @@ -34,9 +42,12 @@ namespace Razor #pragma warning disable 1998 public async override global::System.Threading.Tasks.Task ExecuteAsync() { + BeginContext(31, 28, true); BeginContext(31, 28, true); WriteLiteral("Hola\r\n"); EndContext(); + EndContext(); + BeginContext(61, 7, false); BeginContext(61, 7, false); #line 3 "TestFiles/IntegrationTests/InstrumentationPassIntegrationTest/BasicTest.cshtml" Write("Hello"); @@ -44,14 +55,21 @@ Write("Hello"); #line default #line hidden EndContext(); + EndContext(); + BeginContext(69, 2, true); BeginContext(69, 2, true); WriteLiteral("\r\n"); EndContext(); + EndContext(); + BeginContext(71, 87, false); BeginContext(71, 87, false); __tagHelperExecutionContext = __tagHelperScopeManager.Begin("form", global::Microsoft.AspNetCore.Razor.TagHelpers.TagMode.StartTagAndEndTag, "test", async() => { + BeginContext(91, 6, true); BeginContext(91, 6, true); WriteLiteral("\r\n "); EndContext(); + EndContext(); + BeginContext(97, 52, false); BeginContext(97, 52, false); __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", global::Microsoft.AspNetCore.Razor.TagHelpers.TagMode.SelfClosing, "test", async() => { } @@ -75,9 +93,12 @@ __InputTagHelper.BarProp = DateTime.Now; Write(__tagHelperExecutionContext.Output); __tagHelperExecutionContext = __tagHelperScopeManager.End(); EndContext(); + EndContext(); + BeginContext(149, 2, true); BeginContext(149, 2, true); WriteLiteral("\r\n"); EndContext(); + EndContext(); } ); __FormTagHelper = CreateTagHelper(); @@ -91,19 +112,27 @@ __InputTagHelper.BarProp = DateTime.Now; Write(__tagHelperExecutionContext.Output); __tagHelperExecutionContext = __tagHelperScopeManager.End(); EndContext(); + EndContext(); + BeginContext(158, 31, true); BeginContext(158, 31, true); WriteLiteral("\r\n\r\nHere is some content "); EndContext(); + EndContext(); + BeginContext(207, 9, true); BeginContext(207, 9, true); WriteLiteral("\r\n"); EndContext(); + EndContext(); + BeginContext(217, 29, false); BeginContext(217, 29, false); #line 9 "TestFiles/IntegrationTests/InstrumentationPassIntegrationTest/BasicTest.cshtml" -Write(Foo(item => new Template(async(__razor_template_writer) => { +Write(Foo(item => new global::Microsoft.AspNetCore.Mvc.Razor.HelperResult(async(__razor_template_writer) => { PushWriter(__razor_template_writer); BeginContext(222, 24, true); + BeginContext(222, 24, true); WriteLiteral("Hello world"); EndContext(); + EndContext(); PopWriter(); } ))); @@ -111,8 +140,19 @@ Write(Foo(item => new Template(async(__razor_template_writer) => { #line default #line hidden EndContext(); + EndContext(); } #pragma warning restore 1998 + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } } } #pragma warning restore 1591 diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/TestFiles/IntegrationTests/InstrumentationPassIntegrationTest/BasicTest.ir.txt b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/TestFiles/IntegrationTests/InstrumentationPassIntegrationTest/BasicTest.ir.txt index 6ac51fb0e8..a54315062c 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/TestFiles/IntegrationTests/InstrumentationPassIntegrationTest/BasicTest.ir.txt +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/TestFiles/IntegrationTests/InstrumentationPassIntegrationTest/BasicTest.ir.txt @@ -1,8 +1,17 @@ Document - RazorCompiledItemAttribute - - NamespaceDeclaration - - Razor + CSharpCode - + IntermediateToken - - CSharp - [assembly:global::Microsoft.AspNetCore.Mvc.Razor.Compilation.RazorViewAttribute(@"/TestFiles/IntegrationTests/InstrumentationPassIntegrationTest/BasicTest.cshtml", typeof(AspNetCore.TestFiles_IntegrationTests_InstrumentationPassIntegrationTest_BasicTest))] + NamespaceDeclaration - - AspNetCore + UsingDirective - (1:0,1 [14] ) - System + UsingDirective - (16:1,1 [34] ) - System.Collections.Generic + UsingDirective - (51:2,1 [19] ) - System.Linq + UsingDirective - (71:3,1 [30] ) - System.Threading.Tasks + UsingDirective - (102:4,1 [32] ) - Microsoft.AspNetCore.Mvc + UsingDirective - (135:5,1 [42] ) - Microsoft.AspNetCore.Mvc.Rendering + UsingDirective - (178:6,1 [45] ) - Microsoft.AspNetCore.Mvc.ViewFeatures RazorSourceChecksumAttribute - - ClassDeclaration - - public - Template - - + ClassDeclaration - - public - TestFiles_IntegrationTests_InstrumentationPassIntegrationTest_BasicTest - global::Microsoft.AspNetCore.Mvc.Razor.RazorPage - PreallocatedTagHelperPropertyValue - - __tagHelperAttribute_0 - value - Hello - HtmlAttributeValueStyle.DoubleQuotes PreallocatedTagHelperHtmlAttributeValue - - __tagHelperAttribute_1 - type - text - HtmlAttributeValueStyle.SingleQuotes PreallocatedTagHelperHtmlAttributeValue - - __tagHelperAttribute_2 - unbound - foo - HtmlAttributeValueStyle.DoubleQuotes @@ -10,6 +19,8 @@ Document - FieldDeclaration - - private - global::FormTagHelper - __FormTagHelper FieldDeclaration - - private - global::InputTagHelper - __InputTagHelper MethodDeclaration - - public async override - global::System.Threading.Tasks.Task - ExecuteAsync + CSharpCode - + IntermediateToken - - CSharp - BeginContext(31, 28, true); CSharpCode - IntermediateToken - - CSharp - BeginContext(31, 28, true); HtmlContent - (31:1,0 [28] BasicTest.cshtml) @@ -21,28 +32,46 @@ Document - IntermediateToken - (57:1,26 [2] BasicTest.cshtml) - Html - \n CSharpCode - IntermediateToken - - CSharp - EndContext(); + CSharpCode - + IntermediateToken - - CSharp - EndContext(); + CSharpCode - + IntermediateToken - - CSharp - BeginContext(61, 7, false); CSharpCode - IntermediateToken - - CSharp - BeginContext(61, 7, false); CSharpExpression - (61:2,2 [7] BasicTest.cshtml) IntermediateToken - (61:2,2 [7] BasicTest.cshtml) - CSharp - "Hello" CSharpCode - IntermediateToken - - CSharp - EndContext(); + CSharpCode - + IntermediateToken - - CSharp - EndContext(); + CSharpCode - + IntermediateToken - - CSharp - BeginContext(69, 2, true); CSharpCode - IntermediateToken - - CSharp - BeginContext(69, 2, true); HtmlContent - (69:2,10 [2] BasicTest.cshtml) IntermediateToken - (69:2,10 [2] BasicTest.cshtml) - Html - \n CSharpCode - IntermediateToken - - CSharp - EndContext(); + CSharpCode - + IntermediateToken - - CSharp - EndContext(); + CSharpCode - + IntermediateToken - - CSharp - BeginContext(71, 87, false); CSharpCode - IntermediateToken - - CSharp - BeginContext(71, 87, false); TagHelper - (71:3,0 [87] BasicTest.cshtml) - form - TagMode.StartTagAndEndTag DefaultTagHelperBody - + CSharpCode - + IntermediateToken - - CSharp - BeginContext(91, 6, true); CSharpCode - IntermediateToken - - CSharp - BeginContext(91, 6, true); HtmlContent - (91:3,20 [6] BasicTest.cshtml) IntermediateToken - (91:3,20 [6] BasicTest.cshtml) - Html - \n CSharpCode - IntermediateToken - - CSharp - EndContext(); + CSharpCode - + IntermediateToken - - CSharp - EndContext(); + CSharpCode - + IntermediateToken - - CSharp - BeginContext(97, 52, false); CSharpCode - IntermediateToken - - CSharp - BeginContext(97, 52, false); TagHelper - (97:4,4 [52] BasicTest.cshtml) - input - TagMode.SelfClosing @@ -56,17 +85,27 @@ Document - DefaultTagHelperExecute - CSharpCode - IntermediateToken - - CSharp - EndContext(); + CSharpCode - + IntermediateToken - - CSharp - EndContext(); + CSharpCode - + IntermediateToken - - CSharp - BeginContext(149, 2, true); CSharpCode - IntermediateToken - - CSharp - BeginContext(149, 2, true); HtmlContent - (149:4,56 [2] BasicTest.cshtml) IntermediateToken - (149:4,56 [2] BasicTest.cshtml) - Html - \n CSharpCode - IntermediateToken - - CSharp - EndContext(); + CSharpCode - + IntermediateToken - - CSharp - EndContext(); DefaultTagHelperCreate - - FormTagHelper PreallocatedTagHelperHtmlAttribute - - __tagHelperAttribute_2 DefaultTagHelperExecute - CSharpCode - IntermediateToken - - CSharp - EndContext(); + CSharpCode - + IntermediateToken - - CSharp - EndContext(); + CSharpCode - + IntermediateToken - - CSharp - BeginContext(158, 31, true); CSharpCode - IntermediateToken - - CSharp - BeginContext(158, 31, true); HtmlContent - (158:5,7 [31] BasicTest.cshtml) @@ -76,6 +115,10 @@ Document - IntermediateToken - (168:7,6 [21] BasicTest.cshtml) - Html - Here is some content CSharpCode - IntermediateToken - - CSharp - EndContext(); + CSharpCode - + IntermediateToken - - CSharp - EndContext(); + CSharpCode - + IntermediateToken - - CSharp - BeginContext(207, 9, true); CSharpCode - IntermediateToken - - CSharp - BeginContext(207, 9, true); HtmlContent - (207:7,45 [9] BasicTest.cshtml) @@ -83,11 +126,17 @@ Document - IntermediateToken - (214:7,52 [2] BasicTest.cshtml) - Html - \n CSharpCode - IntermediateToken - - CSharp - EndContext(); + CSharpCode - + IntermediateToken - - CSharp - EndContext(); + CSharpCode - + IntermediateToken - - CSharp - BeginContext(217, 29, false); CSharpCode - IntermediateToken - - CSharp - BeginContext(217, 29, false); CSharpExpression - (217:8,1 [29] BasicTest.cshtml) IntermediateToken - (217:8,1 [4] BasicTest.cshtml) - CSharp - Foo( Template - (222:8,6 [24] BasicTest.cshtml) + CSharpCode - + IntermediateToken - - CSharp - BeginContext(222, 24, true); CSharpCode - IntermediateToken - - CSharp - BeginContext(222, 24, true); HtmlContent - (222:8,6 [24] BasicTest.cshtml) @@ -97,6 +146,15 @@ Document - IntermediateToken - (239:8,23 [7] BasicTest.cshtml) - Html - CSharpCode - IntermediateToken - - CSharp - EndContext(); + CSharpCode - + IntermediateToken - - CSharp - EndContext(); IntermediateToken - (246:8,30 [1] BasicTest.cshtml) - CSharp - ) CSharpCode - IntermediateToken - - CSharp - EndContext(); + CSharpCode - + IntermediateToken - - CSharp - EndContext(); + Inject - + Inject - + Inject - + Inject - + Inject - diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/MvcImportProjectFeature.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/MvcImportProjectFeature.cs index 5c6ee7361d..5a56cd19d0 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/MvcImportProjectFeature.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/MvcImportProjectFeature.cs @@ -21,6 +21,12 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions throw new ArgumentNullException(nameof(projectItem)); } + // Don't add MVC imports for a component + if (string.Equals(projectItem.FileKind, FileKinds.Component, StringComparison.OrdinalIgnoreCase)) + { + return Array.Empty(); + } + var imports = new List(); AddDefaultDirectivesImport(imports); diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/RazorExtensions.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/RazorExtensions.cs index 99e202724a..26e641d7aa 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/RazorExtensions.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/RazorExtensions.cs @@ -21,8 +21,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions ModelDirective.Register(builder); NamespaceDirective.Register(builder); PageDirective.Register(builder); - - InheritsDirective.Register(builder); + SectionDirective.Register(builder); builder.Features.Add(new DefaultTagHelperDescriptorProvider()); @@ -40,7 +39,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions builder.Features.Add(new RazorPageDocumentClassifierPass()); builder.Features.Add(new MvcViewDocumentClassifierPass()); - builder.SetImportFeature(new MvcImportProjectFeature()); + builder.Features.Add(new MvcImportProjectFeature()); } } } diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/RazorPageDocumentClassifierPass.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/RazorPageDocumentClassifierPass.cs index c6c0df9345..96a05cfc22 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/RazorPageDocumentClassifierPass.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/src/RazorPageDocumentClassifierPass.cs @@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions public static readonly string RouteTemplateKey = "RouteTemplate"; private static readonly RazorProjectEngine LeadingDirectiveParsingEngine = RazorProjectEngine.Create( - RazorConfiguration.Default, + RazorConfiguration.Create(RazorLanguageVersion.Version_3_0, "leading-directive-parser", Array.Empty()), RazorProjectFileSystem.Create("/"), builder => { diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/InjectDirectiveTest.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/InjectDirectiveTest.cs index 54a2fa4fd1..a935b23bfb 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/InjectDirectiveTest.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/InjectDirectiveTest.cs @@ -1,15 +1,16 @@ // 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.Text; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Intermediate; using Xunit; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions { - public class InjectDirectiveTest + public class InjectDirectiveTest : RazorProjectEngineTestBase { + protected override RazorLanguageVersion Version => RazorLanguageVersion.Version_3_0; + [Fact] public void InjectDirectivePass_Execute_DefinesProperty() { @@ -171,14 +172,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions return visitor.Node; } - private RazorEngine CreateEngine() + protected override void ConfigureProjectEngine(RazorProjectEngineBuilder builder) { - return RazorProjectEngine.Create(b => - { - // Notice we're not registering the InjectDirective.Pass here so we can run it on demand. - b.AddDirective(InjectDirective.Directive); - b.AddDirective(ModelDirective.Directive); - }).Engine; + // Notice we're not registering the InjectDirective.Pass here so we can run it on demand. + builder.AddDirective(InjectDirective.Directive); + builder.AddDirective(ModelDirective.Directive); } private DocumentIntermediateNode CreateIRDocument(RazorEngine engine, RazorCodeDocument codeDocument) diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/IntegrationTests/CodeGenerationIntegrationTest.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/IntegrationTests/CodeGenerationIntegrationTest.cs index 8273810ca3..05d14e1184 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/IntegrationTests/CodeGenerationIntegrationTest.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/IntegrationTests/CodeGenerationIntegrationTest.cs @@ -181,6 +181,20 @@ public class MyModel AssertCSharpDocumentMatchesBaseline(compiled.CodeDocument.GetCSharpDocument()); } + [Fact] + public void BasicComponent_Runtime() + { + // Arrange + var projectItem = CreateProjectItemFromFile(fileKind: FileKinds.Component); + + // Act + var compiled = CompileToAssembly(projectItem, designTime: false); + + // Assert + AssertDocumentNodeMatchesBaseline(compiled.CodeDocument.GetDocumentIntermediateNode()); + AssertCSharpDocumentMatchesBaseline(compiled.CodeDocument.GetCSharpDocument()); + } + [Fact] public void Sections_Runtime() { @@ -631,6 +645,21 @@ public class MyModel AssertSourceMappingsMatchBaseline(compiled.CodeDocument); } + [Fact] + public void BasicComponent_DesignTime() + { + // Arrange + var projectItem = CreateProjectItemFromFile(fileKind: FileKinds.Component); + + // Act + var compiled = CompileToAssembly(projectItem, designTime: true); + + // Assert + AssertDocumentNodeMatchesBaseline(compiled.CodeDocument.GetDocumentIntermediateNode()); + AssertCSharpDocumentMatchesBaseline(compiled.CodeDocument.GetCSharpDocument()); + AssertSourceMappingsMatchBaseline(compiled.CodeDocument); + } + [Fact] public void Sections_DesignTime() { diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/ModelDirectiveTest.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/ModelDirectiveTest.cs index 425b1b41c6..881557aa4d 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/ModelDirectiveTest.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/ModelDirectiveTest.cs @@ -1,8 +1,6 @@ // 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.IO; using System.Text; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Extensions; @@ -11,8 +9,10 @@ using Xunit; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions { - public class ModelDirectiveTest + public class ModelDirectiveTest : RazorProjectEngineTestBase { + protected override RazorLanguageVersion Version => RazorLanguageVersion.Version_3_0; + [Fact] public void ModelDirective_GetModelType_GetsTypeFromFirstWellFormedDirective() { @@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions @model "); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var irDocument = CreateIRDocument(engine, codeDocument); @@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions // Arrange var codeDocument = CreateDocument(@" "); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var irDocument = CreateIRDocument(engine, codeDocument); @@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions @model Type1 "); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var pass = new ModelDirective.Pass() { Engine = engine, @@ -87,7 +87,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions @model Type2 "); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var pass = new ModelDirective.Pass() { Engine = engine, @@ -113,7 +113,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions @model Type1 "); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var pass = new ModelDirective.Pass() { Engine = engine, @@ -138,7 +138,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions @inherits BaseType "); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var pass = new ModelDirective.Pass() { Engine = engine, @@ -234,9 +234,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions return visitor.Node; } - private RazorEngine CreateEngine() + private RazorEngine CreateRuntimeEngine() { - return CreateEngineCore(); + return CreateEngineCore(designTime: false); } private RazorEngine CreateDesignTimeEngine() @@ -246,14 +246,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions private RazorEngine CreateEngineCore(bool designTime = false) { - return RazorProjectEngine.Create(b => + return CreateProjectEngine(b => { // Notice we're not registering the ModelDirective.Pass here so we can run it on demand. b.AddDirective(ModelDirective.Directive); - // There's some special interaction with the inherits directive - InheritsDirective.Register(b); - b.Features.Add(new DesignTimeOptionsFeature(designTime)); }).Engine; } diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/MvcRazorTemplateEngineTest.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/MvcRazorTemplateEngineTest.cs index f6c61c42a6..c5a25d29aa 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/MvcRazorTemplateEngineTest.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/MvcRazorTemplateEngineTest.cs @@ -8,8 +8,10 @@ using Xunit; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions { - public class MvcRazorTemplateEngineTest + public class MvcRazorTemplateEngineTest : RazorProjectEngineTestBase { + protected override RazorLanguageVersion Version => RazorLanguageVersion.Version_3_0; + [Fact] public void GetDefaultImports_IncludesDefaultImports() { @@ -24,8 +26,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions "@using Microsoft.AspNetCore.Mvc.Rendering", "@using Microsoft.AspNetCore.Mvc.ViewFeatures", }; + var mvcRazorTemplateEngine = new MvcRazorTemplateEngine( - RazorProjectEngine.Create().Engine, + CreateProjectEngine().Engine, new TestRazorProjectFileSystem()); // Act @@ -51,7 +54,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions "@inject global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider", }; var mvcRazorTemplateEngine = new MvcRazorTemplateEngine( - RazorProjectEngine.Create().Engine, + CreateProjectEngine().Engine, new TestRazorProjectFileSystem()); // Act @@ -69,7 +72,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions { // Arrange var mvcRazorTemplateEngine = new MvcRazorTemplateEngine( - RazorProjectEngine.Create().Engine, + CreateProjectEngine().Engine, new TestRazorProjectFileSystem()); // Act diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/MvcViewDocumentClassifierPassTest.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/MvcViewDocumentClassifierPassTest.cs index d7c0ae6854..3cb503f9fc 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/MvcViewDocumentClassifierPassTest.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/MvcViewDocumentClassifierPassTest.cs @@ -7,8 +7,10 @@ using Xunit; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions { - public class MvcViewDocumentClassifierPassTest + public class MvcViewDocumentClassifierPassTest : RazorProjectEngineTestBase { + protected override RazorLanguageVersion Version => RazorLanguageVersion.Version_3_0; + [Fact] public void MvcViewDocumentClassifierPass_SetsDocumentKind() { @@ -217,8 +219,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions Assert.Equal(new[] { "public", "async", "override" }, visitor.Method.Modifiers); } - private static RazorProjectEngine CreateProjectEngine() => RazorProjectEngine.Create(); - private static DocumentIntermediateNode CreateIRDocument(RazorProjectEngine projectEngine, RazorCodeDocument codeDocument) { for (var i = 0; i < projectEngine.Phases.Count; i++) diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/RazorPageDocumentClassifierPassTest.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/RazorPageDocumentClassifierPassTest.cs index a0cdbd7f80..286edb49bf 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/RazorPageDocumentClassifierPassTest.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/RazorPageDocumentClassifierPassTest.cs @@ -9,8 +9,10 @@ using Xunit; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions { - public class RazorPageDocumentClassifierPassTest + public class RazorPageDocumentClassifierPassTest : RazorProjectEngineTestBase { + protected override RazorLanguageVersion Version => RazorLanguageVersion.Version_3_0; + [Fact] public void RazorPageDocumentClassifierPass_LogsErrorForImportedPageDirectives() { @@ -20,7 +22,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions var importDocument = RazorSourceDocument.Create("@page", "import.cshtml"); var sourceDocument = RazorSourceDocument.Create("

Hello World

", "main.cshtml"); var codeDocument = RazorCodeDocument.Create(sourceDocument, new[] { importDocument }); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -55,7 +57,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions "; var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create(content, "Test.cshtml")); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -85,7 +87,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions "; var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create(content, "Test.cshtml")); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -109,7 +111,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions // Arrange var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page", "Test.cshtml")); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -129,7 +131,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions // Arrange var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page", "Test.cshtml")); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var irDocument = CreateIRDocument(engine, codeDocument); irDocument.DocumentKind = "some-value"; var pass = new RazorPageDocumentClassifierPass @@ -150,7 +152,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions // Arrange var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page+1", "Test.cshtml")); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var irDocument = CreateIRDocument(engine, codeDocument); irDocument.DocumentKind = "some-value"; var pass = new RazorPageDocumentClassifierPass @@ -171,7 +173,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions // Arrange var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page", "Test.cshtml")); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -194,7 +196,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions var properties = new RazorSourceDocumentProperties(filePath: "ignored", relativePath: "Test.cshtml"); var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page", properties)); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -219,7 +221,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions var properties = new RazorSourceDocumentProperties(filePath: null, relativePath: null); var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page", properties)); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -246,7 +248,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions var properties = new RazorSourceDocumentProperties(filePath: "ignored", relativePath: relativePath); var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page", properties)); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -269,7 +271,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions var properties = new RazorSourceDocumentProperties(filePath: @"x::\application\Views\Home\Index.cshtml", relativePath: null); var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page", properties)); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -292,7 +294,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions var properties = new RazorSourceDocumentProperties(filePath: @"x:\Test.cshtml", relativePath: "path.with+invalid-chars"); var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page", properties)); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -314,7 +316,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions // Arrange var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page", "Test.cshtml")); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -339,7 +341,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions var properties = new RazorSourceDocumentProperties(filePath: "ignored", relativePath: "Test.cshtml"); var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page \"some-route\"", properties)); - var engine = CreateEngine(); + var engine = CreateRuntimeEngine(); var irDocument = CreateIRDocument(engine, codeDocument); var pass = new RazorPageDocumentClassifierPass { @@ -357,9 +359,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions Assert.Equal("some-route", attributeNode.Value); } - private static RazorEngine CreateEngine() + private RazorEngine CreateRuntimeEngine() { - return RazorProjectEngine.Create(b => + return CreateProjectEngine(b => { PageDirective.Register(b); }).Engine; diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent.cshtml b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent.cshtml new file mode 100644 index 0000000000..85206b7b78 --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent.cshtml @@ -0,0 +1,9 @@ +@implements IDisposable +
+ Hello world + @string.Format("{0}", "Hello") +
+ +@functions { + void IDisposable.Dispose(){ } +} diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent_DesignTime.codegen.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent_DesignTime.codegen.cs new file mode 100644 index 0000000000..5fe69361a5 --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent_DesignTime.codegen.cs @@ -0,0 +1,53 @@ +// +#pragma warning disable 1591 +namespace AspNetCore +{ + #line hidden + using TModel = global::System.Object; + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Components; + public class BasicComponent : Microsoft.AspNetCore.Components.ComponentBase, IDisposable + { + #pragma warning disable 219 + private void __RazorDirectiveTokenHelpers__() { + ((System.Action)(() => { +#line 1 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent.cshtml" +IDisposable __typeHelper = default(IDisposable); + +#line default +#line hidden + } + ))(); + } + #pragma warning restore 219 + #pragma warning disable 0414 + private static System.Object __o = null; + #pragma warning restore 0414 + #pragma warning disable 1998 + protected override void BuildRenderTree(Microsoft.AspNetCore.Components.RenderTree.RenderTreeBuilder builder) + { + base.BuildRenderTree(builder); +#line 2 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent.cshtml" + __o = this.ToString(); + +#line default +#line hidden +#line 4 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent.cshtml" +__o = string.Format("{0}", "Hello"); + +#line default +#line hidden + } + #pragma warning restore 1998 +#line 7 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent.cshtml" + + void IDisposable.Dispose(){ } + +#line default +#line hidden + } +} +#pragma warning restore 1591 diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent_DesignTime.ir.txt b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent_DesignTime.ir.txt new file mode 100644 index 0000000000..73d65846a2 --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent_DesignTime.ir.txt @@ -0,0 +1,37 @@ +Document - + NamespaceDeclaration - - AspNetCore + UsingDirective - - TModel = global::System.Object + UsingDirective - (1:0,1 [12] ) - System + UsingDirective - (16:1,1 [32] ) - System.Collections.Generic + UsingDirective - (51:2,1 [17] ) - System.Linq + UsingDirective - (71:3,1 [28] ) - System.Threading.Tasks + UsingDirective - (102:4,1 [37] ) - Microsoft.AspNetCore.Components + ClassDeclaration - - public - BasicComponent - Microsoft.AspNetCore.Components.ComponentBase - IDisposable + DesignTimeDirective - + DirectiveToken - (14:0,14 [36] ) - "*, Microsoft.AspNetCore.Components" + DirectiveToken - (12:0,12 [11] BasicComponent.cshtml) - IDisposable + CSharpCode - + IntermediateToken - - CSharp - #pragma warning disable 0414 + CSharpCode - + IntermediateToken - - CSharp - private static System.Object __o = null; + CSharpCode - + IntermediateToken - - CSharp - #pragma warning restore 0414 + MethodDeclaration - - protected override - void - BuildRenderTree + CSharpCode - + IntermediateToken - - CSharp - base.BuildRenderTree(builder); + MarkupElement - (25:1,0 [91] BasicComponent.cshtml) - div + HtmlAttribute - (29:1,4 [25] BasicComponent.cshtml) - class=" - " + CSharpExpressionAttributeValue - (37:1,12 [16] BasicComponent.cshtml) - + IntermediateToken - (38:1,13 [15] BasicComponent.cshtml) - CSharp - this.ToString() + HtmlContent - (55:1,30 [23] BasicComponent.cshtml) + IntermediateToken - (55:1,30 [23] BasicComponent.cshtml) - Html - \n Hello world\n + CSharpExpression - (79:3,5 [29] BasicComponent.cshtml) + IntermediateToken - (79:3,5 [29] BasicComponent.cshtml) - CSharp - string.Format("{0}", "Hello") + HtmlContent - (108:3,34 [2] BasicComponent.cshtml) + IntermediateToken - (108:3,34 [2] BasicComponent.cshtml) - Html - \n + HtmlContent - (116:4,6 [4] BasicComponent.cshtml) + IntermediateToken - (116:4,6 [4] BasicComponent.cshtml) - Html - \n\n + HtmlContent - (170:8,1 [2] BasicComponent.cshtml) + IntermediateToken - (170:8,1 [2] BasicComponent.cshtml) - Html - \n + CSharpCode - (132:6,12 [37] BasicComponent.cshtml) + IntermediateToken - (132:6,12 [37] BasicComponent.cshtml) - CSharp - \n void IDisposable.Dispose(){ }\n diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent_DesignTime.mappings.txt b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent_DesignTime.mappings.txt new file mode 100644 index 0000000000..abc4f51e55 --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent_DesignTime.mappings.txt @@ -0,0 +1,24 @@ +Source Location: (12:0,12 [11] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent.cshtml) +|IDisposable| +Generated Location: (618:17,0 [11] ) +|IDisposable| + +Source Location: (38:1,13 [15] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent.cshtml) +|this.ToString()| +Generated Location: (1214:33,13 [15] ) +|this.ToString()| + +Source Location: (79:3,5 [29] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent.cshtml) +|string.Format("{0}", "Hello")| +Generated Location: (1359:38,6 [29] ) +|string.Format("{0}", "Hello")| + +Source Location: (132:6,12 [37] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent.cshtml) +| + void IDisposable.Dispose(){ } +| +Generated Location: (1573:45,12 [37] ) +| + void IDisposable.Dispose(){ } +| + diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent_Runtime.codegen.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent_Runtime.codegen.cs new file mode 100644 index 0000000000..65fa29f408 --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent_Runtime.codegen.cs @@ -0,0 +1,34 @@ +#pragma checksum "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "d3c3d6059615673cb46fc4974164d61eabadb890" +// +#pragma warning disable 1591 +namespace AspNetCore +{ + #line hidden + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Components; + public class BasicComponent : Microsoft.AspNetCore.Components.ComponentBase, IDisposable + { + #pragma warning disable 1998 + protected override void BuildRenderTree(Microsoft.AspNetCore.Components.RenderTree.RenderTreeBuilder builder) + { + base.BuildRenderTree(builder); + builder.OpenElement(0, "div"); + builder.AddAttribute(1, "class", this.ToString()); + builder.AddContent(2, "\r\n Hello world\r\n "); + builder.AddContent(3, string.Format("{0}", "Hello")); + builder.AddContent(4, "\r\n"); + builder.CloseElement(); + } + #pragma warning restore 1998 +#line 7 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent.cshtml" + + void IDisposable.Dispose(){ } + +#line default +#line hidden + } +} +#pragma warning restore 1591 diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent_Runtime.ir.txt b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent_Runtime.ir.txt new file mode 100644 index 0000000000..58d2bd23dd --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent_Runtime.ir.txt @@ -0,0 +1,24 @@ +Document - + NamespaceDeclaration - - AspNetCore + UsingDirective - (1:0,1 [14] ) - System + UsingDirective - (16:1,1 [34] ) - System.Collections.Generic + UsingDirective - (51:2,1 [19] ) - System.Linq + UsingDirective - (71:3,1 [30] ) - System.Threading.Tasks + UsingDirective - (102:4,1 [37] ) - Microsoft.AspNetCore.Components + ClassDeclaration - - public - BasicComponent - Microsoft.AspNetCore.Components.ComponentBase - IDisposable + MethodDeclaration - - protected override - void - BuildRenderTree + CSharpCode - + IntermediateToken - - CSharp - base.BuildRenderTree(builder); + MarkupElement - (25:1,0 [91] BasicComponent.cshtml) - div + HtmlAttribute - (29:1,4 [25] BasicComponent.cshtml) - class=" - " + CSharpExpressionAttributeValue - (37:1,12 [16] BasicComponent.cshtml) - + IntermediateToken - (38:1,13 [15] BasicComponent.cshtml) - CSharp - this.ToString() + HtmlContent - (55:1,30 [23] BasicComponent.cshtml) + IntermediateToken - (55:1,30 [19] BasicComponent.cshtml) - Html - \n Hello world\n + IntermediateToken - (74:3,0 [4] BasicComponent.cshtml) - Html - + CSharpExpression - (79:3,5 [29] BasicComponent.cshtml) + IntermediateToken - (79:3,5 [29] BasicComponent.cshtml) - CSharp - string.Format("{0}", "Hello") + HtmlContent - (108:3,34 [2] BasicComponent.cshtml) + IntermediateToken - (108:3,34 [2] BasicComponent.cshtml) - Html - \n + CSharpCode - (132:6,12 [37] BasicComponent.cshtml) + IntermediateToken - (132:6,12 [37] BasicComponent.cshtml) - CSharp - \n void IDisposable.Dispose(){ }\n diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/CodeGeneration/DefaultDocumentWriter.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/CodeGeneration/DefaultDocumentWriter.cs index a47295143d..8a6865f7ed 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/CodeGeneration/DefaultDocumentWriter.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/CodeGeneration/DefaultDocumentWriter.cs @@ -257,6 +257,46 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration VisitDefault(node); } + public override void VisitComponent(ComponentIntermediateNode node) + { + Context.NodeWriter.WriteComponent(Context, node); + } + + public override void VisitComponentAttribute(ComponentAttributeIntermediateNode node) + { + Context.NodeWriter.WriteComponentAttribute(Context, node); + } + + public override void VisitComponentChildContent(ComponentChildContentIntermediateNode node) + { + Context.NodeWriter.WriteComponentChildContent(Context, node); + } + + public override void VisitComponentTypeArgument(ComponentTypeArgumentIntermediateNode node) + { + Context.NodeWriter.WriteComponentTypeArgument(Context, node); + } + + public override void VisitComponentTypeInferenceMethod(ComponentTypeInferenceMethodIntermediateNode node) + { + Context.NodeWriter.WriteComponentTypeInferenceMethod(Context, node); + } + + public override void VisitMarkupElement(MarkupElementIntermediateNode node) + { + Context.NodeWriter.WriteMarkupElement(Context, node); + } + + public override void VisitMarkupBlock(MarkupBlockIntermediateNode node) + { + Context.NodeWriter.WriteMarkupBlock(Context, node); + } + + public override void VisitReferenceCapture(ReferenceCaptureIntermediateNode node) + { + Context.NodeWriter.WriteReferenceCapture(Context, node); + } + public override void VisitDefault(IntermediateNode node) { Context.RenderChildren(node); diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/CodeGeneration/IntermediateNodeWriter.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/CodeGeneration/IntermediateNodeWriter.cs index d8c636f064..c8a3c6659a 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/CodeGeneration/IntermediateNodeWriter.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/CodeGeneration/IntermediateNodeWriter.cs @@ -1,6 +1,7 @@ // 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 Microsoft.AspNetCore.Razor.Language.Intermediate; namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration @@ -23,6 +24,46 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration public abstract void WriteCSharpCodeAttributeValue(CodeRenderingContext context, CSharpCodeAttributeValueIntermediateNode node); + public virtual void WriteComponent(CodeRenderingContext context, ComponentIntermediateNode node) + { + throw new NotSupportedException("This writer does not support components."); + } + + public virtual void WriteComponentAttribute(CodeRenderingContext context, ComponentAttributeIntermediateNode node) + { + throw new NotSupportedException("This writer does not support components."); + } + + public virtual void WriteComponentChildContent(CodeRenderingContext context, ComponentChildContentIntermediateNode node) + { + throw new NotSupportedException("This writer does not support components."); + } + + public virtual void WriteComponentTypeArgument(CodeRenderingContext context, ComponentTypeArgumentIntermediateNode node) + { + throw new NotSupportedException("This writer does not support components."); + } + + public virtual void WriteComponentTypeInferenceMethod(CodeRenderingContext context, ComponentTypeInferenceMethodIntermediateNode node) + { + throw new NotSupportedException("This writer does not support components."); + } + + public virtual void WriteMarkupElement(CodeRenderingContext context, MarkupElementIntermediateNode node) + { + throw new NotSupportedException("This writer does not support components."); + } + + public virtual void WriteMarkupBlock(CodeRenderingContext context, MarkupBlockIntermediateNode node) + { + throw new NotSupportedException("This writer does not support components."); + } + + public virtual void WriteReferenceCapture(CodeRenderingContext context, ReferenceCaptureIntermediateNode node) + { + throw new NotSupportedException("This writer does not support components."); + } + public abstract void BeginWriterScope(CodeRenderingContext context, string writer); public abstract void EndWriterScope(CodeRenderingContext context); diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BlazorCSharpLoweringPhase.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BlazorCSharpLoweringPhase.cs deleted file mode 100644 index fd9a026f13..0000000000 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BlazorCSharpLoweringPhase.cs +++ /dev/null @@ -1,42 +0,0 @@ -// 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 Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.Language.CodeGeneration; -using Microsoft.AspNetCore.Razor.Language.Intermediate; - -namespace Microsoft.AspNetCore.Razor.Language.Components -{ - internal class BlazorRazorCSharpLoweringPhase : RazorEnginePhaseBase, IRazorCSharpLoweringPhase - { - protected override void ExecuteCore(RazorCodeDocument codeDocument) - { - var documentNode = codeDocument.GetDocumentIntermediateNode(); - ThrowForMissingDocumentDependency(documentNode); -#pragma warning disable CS0618 - var writer = new DocumentWriterWorkaround().Create(documentNode.Target, documentNode.Options); -#pragma warning restore CS0618 - try - { - var cSharpDocument = writer.WriteDocument(codeDocument, documentNode); - codeDocument.SetCSharpDocument(cSharpDocument); - } - catch (RazorCompilerException ex) - { - // Currently the Blazor code generation has some 'fatal errors' that can cause code generation - // to fail completely. This class is here to make that implementation work gracefully. - var cSharpDocument = RazorCSharpDocument.Create("", documentNode.Options, new[] { ex.Diagnostic }); - codeDocument.SetCSharpDocument(cSharpDocument); - } - } - - private class DocumentWriterWorkaround : DocumentWriter - { - public override RazorCSharpDocument WriteDocument(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) - { - throw new NotImplementedException(); - } - } - } -} \ No newline at end of file diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BlazorExtensionInitializer.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BlazorExtensionInitializer.cs deleted file mode 100644 index 6a03dc07e8..0000000000 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BlazorExtensionInitializer.cs +++ /dev/null @@ -1,130 +0,0 @@ -// 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.Linq; -using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.Language.Extensions; - -namespace Microsoft.AspNetCore.Razor.Language.Components -{ - /// - /// Initializes the Blazor extension. - /// - public class BlazorExtensionInitializer : RazorExtensionInitializer - { - /// - /// Specifies the declaration configuration. - /// - public static readonly RazorConfiguration DeclarationConfiguration; - - /// - /// Specifies the default configuration. - /// - public static readonly RazorConfiguration DefaultConfiguration; - - static BlazorExtensionInitializer() - { - // The configuration names here need to match what we put in the MSBuild configuration - DeclarationConfiguration = RazorConfiguration.Create( - RazorLanguageVersion.Experimental, - "BlazorDeclaration-0.1", - Array.Empty()); - - DefaultConfiguration = RazorConfiguration.Create( - RazorLanguageVersion.Experimental, - "Blazor-0.1", - Array.Empty()); - } - - /// - /// Registers the Blazor extension. - /// - /// The . - public static void Register(RazorProjectEngineBuilder builder) - { - if (builder == null) - { - throw new ArgumentNullException(nameof(builder)); - } - - FunctionsDirective.Register(builder); - ImplementsDirective.Register(builder); - InheritsDirective.Register(builder); - InjectDirective.Register(builder); - LayoutDirective.Register(builder); - PageDirective.Register(builder); - TypeParamDirective.Register(builder); - - builder.Features.Remove(builder.Features.OfType().Single()); - builder.Features.Add(new BlazorImportProjectFeature()); - - var index = builder.Phases.IndexOf(builder.Phases.OfType().Single()); - builder.Phases[index] = new BlazorRazorCSharpLoweringPhase(); - - builder.Features.Add(new ConfigureBlazorCodeGenerationOptions()); - - builder.AddTargetExtension(new BlazorTemplateTargetExtension()); - - var isDeclarationOnlyCompile = builder.Configuration.ConfigurationName == DeclarationConfiguration.ConfigurationName; - - // Blazor-specific passes, in order. - if (!isDeclarationOnlyCompile) - { - // There's no benefit in this optimization during the declaration-only compile - builder.Features.Add(new TrimWhitespacePass()); - } - builder.Features.Add(new ComponentDocumentClassifierPass()); - builder.Features.Add(new ScriptTagPass()); - builder.Features.Add(new ComplexAttributeContentPass()); - builder.Features.Add(new ComponentLoweringPass()); - builder.Features.Add(new EventHandlerLoweringPass()); - builder.Features.Add(new ReferenceCaptureLoweringPass()); - builder.Features.Add(new BindLoweringPass()); - builder.Features.Add(new TemplateDiagnosticPass()); - builder.Features.Add(new GenericComponentPass()); - builder.Features.Add(new ChildContentDiagnosticPass()); - builder.Features.Add(new HtmlBlockPass()); - - if (isDeclarationOnlyCompile) - { - // This is for 'declaration only' processing. We don't want to try and emit any method bodies during - // the design time build because we can't do it correctly until the set of components is known. - builder.Features.Add(new EliminateMethodBodyPass()); - } - } - - /// - /// Initializes the Blazor extension. - /// - /// The . - public override void Initialize(RazorProjectEngineBuilder builder) - { - if (builder == null) - { - throw new ArgumentNullException(nameof(builder)); - } - - Register(builder); - } - - private class ConfigureBlazorCodeGenerationOptions : IConfigureRazorCodeGenerationOptionsFeature - { - public int Order => 0; - - public RazorEngine Engine { get; set; } - - public void Configure(RazorCodeGenerationOptionsBuilder options) - { - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - // These metadata attributes require a reference to the Razor.Runtime package which we don't - // otherwise need. - options.SuppressMetadataAttributes = true; - } - } - } -} diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/CodeWriterExtensions.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/CodeWriterExtensions.cs deleted file mode 100644 index e458d88d6a..0000000000 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/CodeWriterExtensions.cs +++ /dev/null @@ -1,647 +0,0 @@ -// 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 Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.Language.CodeGeneration; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.Linq; - -// Copied directly from https://github.com/aspnet/Razor/blob/ff40124594b58b17988d50841175430a4b73d1a9/src/Microsoft.AspNetCore.Razor.Language/CodeGeneration/CodeWriterExtensions.cs -// (other than the namespace change) because it's internal - -namespace Microsoft.AspNetCore.Razor.Language.Components -{ - internal static class CodeWriterExtensions - { - private const string InstanceMethodFormat = "{0}.{1}"; - - private static readonly char[] CStyleStringLiteralEscapeChars = - { - '\r', - '\t', - '\"', - '\'', - '\\', - '\0', - '\n', - '\u2028', - '\u2029', - }; - - public static bool IsAtBeginningOfLine(this CodeWriter writer) - { - return writer.Length == 0 || writer[writer.Length - 1] == '\n'; - } - - public static CodeWriter WritePadding(this CodeWriter writer, int offset, SourceSpan? span, CodeRenderingContext context) - { - if (span == null) - { - return writer; - } - - var basePadding = CalculatePadding(); - var resolvedPadding = Math.Max(basePadding - offset, 0); - - if (context.Options.IndentWithTabs) - { - // Avoid writing directly to the StringBuilder here, that will throw off the manual indexing - // done by the base class. - var tabs = resolvedPadding / context.Options.IndentSize; - for (var i = 0; i < tabs; i++) - { - writer.Write("\t"); - } - - var spaces = resolvedPadding % context.Options.IndentSize; - for (var i = 0; i < spaces; i++) - { - writer.Write(" "); - } - } - else - { - for (var i = 0; i < resolvedPadding; i++) - { - writer.Write(" "); - } - } - - return writer; - - int CalculatePadding() - { - var spaceCount = 0; - for (var i = span.Value.AbsoluteIndex - 1; i >= 0; i--) - { - var @char = context.SourceDocument[i]; - if (@char == '\n' || @char == '\r') - { - break; - } - else if (@char == '\t') - { - spaceCount += context.Options.IndentSize; - } - else - { - spaceCount++; - } - } - - return spaceCount; - } - } - - public static CodeWriter WriteVariableDeclaration(this CodeWriter writer, string type, string name, string value) - { - writer.Write(type).Write(" ").Write(name); - if (!string.IsNullOrEmpty(value)) - { - writer.Write(" = ").Write(value); - } - else - { - writer.Write(" = null"); - } - - writer.WriteLine(";"); - - return writer; - } - - public static CodeWriter WriteBooleanLiteral(this CodeWriter writer, bool value) - { - return writer.Write(value.ToString().ToLowerInvariant()); - } - - public static CodeWriter WriteStartAssignment(this CodeWriter writer, string name) - { - return writer.Write(name).Write(" = "); - } - - public static CodeWriter WriteParameterSeparator(this CodeWriter writer) - { - return writer.Write(", "); - } - - public static CodeWriter WriteStartNewObject(this CodeWriter writer, string typeName) - { - return writer.Write("new ").Write(typeName).Write("("); - } - - public static CodeWriter WriteStringLiteral(this CodeWriter writer, string literal) - { - if (literal.Length >= 256 && literal.Length <= 1500 && literal.IndexOf('\0') == -1) - { - WriteVerbatimStringLiteral(writer, literal); - } - else - { - WriteCStyleStringLiteral(writer, literal); - } - - return writer; - } - - public static CodeWriter WriteUsing(this CodeWriter writer, string name) - { - return WriteUsing(writer, name, endLine: true); - } - - public static CodeWriter WriteUsing(this CodeWriter writer, string name, bool endLine) - { - writer.Write("using "); - writer.Write(name); - - if (endLine) - { - writer.WriteLine(";"); - } - - return writer; - } - - public static CodeWriter WriteLineNumberDirective(this CodeWriter writer, SourceSpan span) - { - if (writer.Length >= writer.NewLine.Length && !IsAtBeginningOfLine(writer)) - { - writer.WriteLine(); - } - - var lineNumberAsString = (span.LineIndex + 1).ToString(CultureInfo.InvariantCulture); - return writer.Write("#line ").Write(lineNumberAsString).Write(" \"").Write(span.FilePath).WriteLine("\""); - } - - public static CodeWriter WriteStartMethodInvocation(this CodeWriter writer, string methodName) - { - writer.Write(methodName); - - return writer.Write("("); - } - - public static CodeWriter WriteEndMethodInvocation(this CodeWriter writer) - { - return WriteEndMethodInvocation(writer, endLine: true); - } - - public static CodeWriter WriteEndMethodInvocation(this CodeWriter writer, bool endLine) - { - writer.Write(")"); - if (endLine) - { - writer.WriteLine(";"); - } - - return writer; - } - - // Writes a method invocation for the given instance name. - public static CodeWriter WriteInstanceMethodInvocation( - this CodeWriter writer, - string instanceName, - string methodName, - params string[] parameters) - { - if (instanceName == null) - { - throw new ArgumentNullException(nameof(instanceName)); - } - - if (methodName == null) - { - throw new ArgumentNullException(nameof(methodName)); - } - - return WriteInstanceMethodInvocation(writer, instanceName, methodName, endLine: true, parameters: parameters); - } - - // Writes a method invocation for the given instance name. - public static CodeWriter WriteInstanceMethodInvocation( - this CodeWriter writer, - string instanceName, - string methodName, - bool endLine, - params string[] parameters) - { - if (instanceName == null) - { - throw new ArgumentNullException(nameof(instanceName)); - } - - if (methodName == null) - { - throw new ArgumentNullException(nameof(methodName)); - } - - return WriteMethodInvocation( - writer, - string.Format(CultureInfo.InvariantCulture, InstanceMethodFormat, instanceName, methodName), - endLine, - parameters); - } - - public static CodeWriter WriteStartInstanceMethodInvocation(this CodeWriter writer, string instanceName, string methodName) - { - if (instanceName == null) - { - throw new ArgumentNullException(nameof(instanceName)); - } - - if (methodName == null) - { - throw new ArgumentNullException(nameof(methodName)); - } - - return WriteStartMethodInvocation( - writer, - string.Format(CultureInfo.InvariantCulture, InstanceMethodFormat, instanceName, methodName)); - } - - public static CodeWriter WriteField(this CodeWriter writer, IList modifiers, string typeName, string fieldName) - { - if (modifiers == null) - { - throw new ArgumentNullException(nameof(modifiers)); - } - - if (typeName == null) - { - throw new ArgumentNullException(nameof(typeName)); - } - - if (fieldName == null) - { - throw new ArgumentNullException(nameof(fieldName)); - } - - for (var i = 0; i < modifiers.Count; i++) - { - writer.Write(modifiers[i]); - writer.Write(" "); - } - - writer.Write(typeName); - writer.Write(" "); - writer.Write(fieldName); - writer.Write(";"); - writer.WriteLine(); - - return writer; - } - - public static CodeWriter WriteMethodInvocation(this CodeWriter writer, string methodName, params string[] parameters) - { - return WriteMethodInvocation(writer, methodName, endLine: true, parameters: parameters); - } - - public static CodeWriter WriteMethodInvocation(this CodeWriter writer, string methodName, bool endLine, params string[] parameters) - { - return - WriteStartMethodInvocation(writer, methodName) - .Write(string.Join(", ", parameters)) - .WriteEndMethodInvocation(endLine); - } - - public static CodeWriter WriteAutoPropertyDeclaration(this CodeWriter writer, IList modifiers, string typeName, string propertyName) - { - if (modifiers == null) - { - throw new ArgumentNullException(nameof(modifiers)); - } - - if (typeName == null) - { - throw new ArgumentNullException(nameof(typeName)); - } - - if (propertyName == null) - { - throw new ArgumentNullException(nameof(propertyName)); - } - - for (var i = 0; i < modifiers.Count; i++) - { - writer.Write(modifiers[i]); - writer.Write(" "); - } - - writer.Write(typeName); - writer.Write(" "); - writer.Write(propertyName); - writer.Write(" { get; set; }"); - writer.WriteLine(); - - return writer; - } - - public static CSharpCodeWritingScope BuildScope(this CodeWriter writer) - { - return new CSharpCodeWritingScope(writer); - } - - public static CSharpCodeWritingScope BuildLambda(this CodeWriter writer, params string[] parameterNames) - { - return BuildLambda(writer, async: false, parameterNames: parameterNames); - } - - public static CSharpCodeWritingScope BuildAsyncLambda(this CodeWriter writer, params string[] parameterNames) - { - return BuildLambda(writer, async: true, parameterNames: parameterNames); - } - - private static CSharpCodeWritingScope BuildLambda(CodeWriter writer, bool async, string[] parameterNames) - { - if (async) - { - writer.Write("async"); - } - - writer.Write("(").Write(string.Join(", ", parameterNames)).Write(") => "); - - var scope = new CSharpCodeWritingScope(writer); - - return scope; - } - - public static CSharpCodeWritingScope BuildNamespace(this CodeWriter writer, string name) - { - writer.Write("namespace ").WriteLine(name); - - return new CSharpCodeWritingScope(writer); - } - - public static CSharpCodeWritingScope BuildClassDeclaration( - this CodeWriter writer, - IList modifiers, - string name, - string baseType, - IEnumerable interfaces) - { - for (var i = 0; i < modifiers.Count; i++) - { - writer.Write(modifiers[i]); - writer.Write(" "); - } - - writer.Write("class "); - writer.Write(name); - - var hasBaseType = !string.IsNullOrEmpty(baseType); - var hasInterfaces = interfaces != null && interfaces.Count() > 0; - - if (hasBaseType || hasInterfaces) - { - writer.Write(" : "); - - if (hasBaseType) - { - writer.Write(baseType); - - if (hasInterfaces) - { - WriteParameterSeparator(writer); - } - } - - if (hasInterfaces) - { - writer.Write(string.Join(", ", interfaces)); - } - } - - writer.WriteLine(); - - return new CSharpCodeWritingScope(writer); - } - - public static CSharpCodeWritingScope BuildMethodDeclaration( - this CodeWriter writer, - string accessibility, - string returnType, - string name, - IEnumerable> parameters) - { - writer.Write(accessibility) - .Write(" ") - .Write(returnType) - .Write(" ") - .Write(name) - .Write("(") - .Write(string.Join(", ", parameters.Select(p => p.Key + " " + p.Value))) - .WriteLine(")"); - - return new CSharpCodeWritingScope(writer); - } - - public static IDisposable BuildLinePragma(this CodeWriter writer, SourceSpan? span) - { - if (string.IsNullOrEmpty(span?.FilePath)) - { - // Can't build a valid line pragma without a file path. - return NullDisposable.Default; - } - - return new LinePragmaWriter(writer, span.Value); - } - - private static void WriteVerbatimStringLiteral(CodeWriter writer, string literal) - { - writer.Write("@\""); - - // We need to suppress indenting during the writing of the string's content. A - // verbatim string literal could contain newlines that don't get escaped. - var indent = writer.CurrentIndent; - writer.CurrentIndent = 0; - - // We need to find the index of each '"' (double-quote) to escape it. - var start = 0; - int end; - while ((end = literal.IndexOf('\"', start)) > -1) - { - writer.Write(literal, start, end - start); - - writer.Write("\"\""); - - start = end + 1; - } - - Debug.Assert(end == -1); // We've hit all of the double-quotes. - - // Write the remainder after the last double-quote. - writer.Write(literal, start, literal.Length - start); - - writer.Write("\""); - - writer.CurrentIndent = indent; - } - - private static void WriteCStyleStringLiteral(CodeWriter writer, string literal) - { - // From CSharpCodeGenerator.QuoteSnippetStringCStyle in CodeDOM - writer.Write("\""); - - // We need to find the index of each escapable character to escape it. - var start = 0; - int end; - while ((end = literal.IndexOfAny(CStyleStringLiteralEscapeChars, start)) > -1) - { - writer.Write(literal, start, end - start); - - switch (literal[end]) - { - case '\r': - writer.Write("\\r"); - break; - case '\t': - writer.Write("\\t"); - break; - case '\"': - writer.Write("\\\""); - break; - case '\'': - writer.Write("\\\'"); - break; - case '\\': - writer.Write("\\\\"); - break; - case '\0': - writer.Write("\\\0"); - break; - case '\n': - writer.Write("\\n"); - break; - case '\u2028': - case '\u2029': - writer.Write("\\u"); - writer.Write(((int)literal[end]).ToString("X4", CultureInfo.InvariantCulture)); - break; - default: - Debug.Assert(false, "Unknown escape character."); - break; - } - - start = end + 1; - } - - Debug.Assert(end == -1); // We've hit all of chars that need escaping. - - // Write the remainder after the last escaped char. - writer.Write(literal, start, literal.Length - start); - - writer.Write("\""); - } - - public struct CSharpCodeWritingScope : IDisposable - { - private CodeWriter _writer; - private bool _autoSpace; - private int _tabSize; - private int _startIndent; - - public CSharpCodeWritingScope(CodeWriter writer, int tabSize = 4, bool autoSpace = true) - { - _writer = writer; - _autoSpace = autoSpace; - _tabSize = tabSize; - _startIndent = -1; // Set in WriteStartScope - - WriteStartScope(); - } - - public void Dispose() - { - WriteEndScope(); - } - - private void WriteStartScope() - { - TryAutoSpace(" "); - - _writer.WriteLine("{"); - _writer.CurrentIndent += _tabSize; - _startIndent = _writer.CurrentIndent; - } - - private void WriteEndScope() - { - TryAutoSpace(_writer.NewLine); - - // Ensure the scope hasn't been modified - if (_writer.CurrentIndent == _startIndent) - { - _writer.CurrentIndent -= _tabSize; - } - - _writer.WriteLine("}"); - } - - private void TryAutoSpace(string spaceCharacter) - { - if (_autoSpace && - _writer.Length > 0 && - !char.IsWhiteSpace(_writer[_writer.Length - 1])) - { - _writer.Write(spaceCharacter); - } - } - } - - private class LinePragmaWriter : IDisposable - { - private readonly CodeWriter _writer; - private readonly int _startIndent; - - public LinePragmaWriter(CodeWriter writer, SourceSpan span) - { - if (writer == null) - { - throw new ArgumentNullException(nameof(writer)); - } - - _writer = writer; - _startIndent = _writer.CurrentIndent; - _writer.CurrentIndent = 0; - WriteLineNumberDirective(writer, span); - } - - public void Dispose() - { - // Need to add an additional line at the end IF there wasn't one already written. - // This is needed to work with the C# editor's handling of #line ... - var endsWithNewline = _writer.Length > 0 && _writer[_writer.Length - 1] == '\n'; - - // Always write at least 1 empty line to potentially separate code from pragmas. - _writer.WriteLine(); - - // Check if the previous empty line wasn't enough to separate code from pragmas. - if (!endsWithNewline) - { - _writer.WriteLine(); - } - - _writer - .WriteLine("#line default") - .WriteLine("#line hidden"); - - _writer.CurrentIndent = _startIndent; - } - } - - private class NullDisposable : IDisposable - { - public static readonly NullDisposable Default = new NullDisposable(); - - private NullDisposable() - { - } - - public void Dispose() - { - } - } - } -} diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BindLoweringPass.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentBindLoweringPass.cs similarity index 99% rename from src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BindLoweringPass.cs rename to src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentBindLoweringPass.cs index 34fdd2d26c..9e979b515f 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BindLoweringPass.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentBindLoweringPass.cs @@ -8,13 +8,18 @@ using Microsoft.AspNetCore.Razor.Language.Intermediate; namespace Microsoft.AspNetCore.Razor.Language.Components { - internal class BindLoweringPass : IntermediateNodePassBase, IRazorOptimizationPass + internal class ComponentBindLoweringPass : ComponentIntermediateNodePassBase, IRazorOptimizationPass { // Run after event handler pass public override int Order => 100; protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { + if (!IsComponentDocument(documentNode)) + { + return; + } + var @namespace = documentNode.FindPrimaryNamespace(); var @class = documentNode.FindPrimaryClass(); if (@namespace == null || @class == null) diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ChildContentDiagnosticPass.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentChildContentDiagnosticPass.cs similarity index 93% rename from src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ChildContentDiagnosticPass.cs rename to src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentChildContentDiagnosticPass.cs index c004e51bca..ea102fa9c9 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ChildContentDiagnosticPass.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentChildContentDiagnosticPass.cs @@ -2,12 +2,11 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Intermediate; namespace Microsoft.AspNetCore.Razor.Language.Components { - internal class ChildContentDiagnosticPass : IntermediateNodePassBase, IRazorOptimizationPass + internal class ComponentChildContentDiagnosticPass : ComponentIntermediateNodePassBase, IRazorOptimizationPass { // Runs after components/eventhandlers/ref/bind/templates. We want to validate every component // and it's usage of ChildContent. @@ -15,6 +14,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Components protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { + if (!IsComponentDocument(documentNode)) + { + return; + } + var visitor = new Visitor(); visitor.Visit(documentNode); } diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BlazorCodeTarget.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentCodeTarget.cs similarity index 71% rename from src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BlazorCodeTarget.cs rename to src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentCodeTarget.cs index 1437e5432b..a106dd5d5d 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BlazorCodeTarget.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentCodeTarget.cs @@ -3,29 +3,28 @@ using System.Collections.Generic; using System.Linq; -using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.CodeGeneration; namespace Microsoft.AspNetCore.Razor.Language.Components { - /// - /// Directs a to use . - /// - internal class BlazorCodeTarget : CodeTarget + internal class ComponentCodeTarget : CodeTarget { private readonly RazorCodeGenerationOptions _options; - public BlazorCodeTarget(RazorCodeGenerationOptions options, IEnumerable extensions) + public ComponentCodeTarget(RazorCodeGenerationOptions options, IEnumerable extensions) { _options = options; - Extensions = extensions.ToArray(); + + // Components provide some built-in target extensions that don't apply to + // legacy documents. + Extensions = new[] { new ComponentTemplateTargetExtension(), }.Concat(extensions).ToArray(); } public ICodeTargetExtension[] Extensions { get; } public override IntermediateNodeWriter CreateNodeWriter() { - return _options.DesignTime ? (BlazorNodeWriter)new BlazorDesignTimeNodeWriter() : new BlazorRuntimeNodeWriter(); + return _options.DesignTime ? (IntermediateNodeWriter)new ComponentDesignTimeNodeWriter() : new ComponentRuntimeNodeWriter(); } public override TExtension GetExtension() diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComplexAttributeContentPass.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentComplexAttributeContentPass.cs similarity index 94% rename from src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComplexAttributeContentPass.cs rename to src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentComplexAttributeContentPass.cs index f500fedcb2..8b7c73d306 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComplexAttributeContentPass.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentComplexAttributeContentPass.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Linq; -using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Intermediate; namespace Microsoft.AspNetCore.Razor.Language.Components @@ -12,13 +11,18 @@ namespace Microsoft.AspNetCore.Razor.Language.Components // // This is where a lot of the complexity in the Razor/TagHelpers model creeps in and we // might be able to avoid it if these features aren't needed. - internal class ComplexAttributeContentPass : IntermediateNodePassBase, IRazorOptimizationPass + internal class ComponentComplexAttributeContentPass : ComponentIntermediateNodePassBase, IRazorOptimizationPass { - // Run before other Blazor passes + // Run before other Component passes public override int Order => -1000; protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { + if (!IsComponentDocument(documentNode)) + { + return; + } + var nodes = documentNode.FindDescendantNodes(); for (var i = 0; i < nodes.Count; i++) { diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BlazorDesignTimeNodeWriter.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentDesignTimeNodeWriter.cs similarity index 98% rename from src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BlazorDesignTimeNodeWriter.cs rename to src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentDesignTimeNodeWriter.cs index 753c220e87..da3c03b2d8 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BlazorDesignTimeNodeWriter.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentDesignTimeNodeWriter.cs @@ -11,13 +11,13 @@ using Microsoft.AspNetCore.Razor.Language.Intermediate; namespace Microsoft.AspNetCore.Razor.Language.Components { // Based on the DesignTimeNodeWriter from Razor repo. - internal class BlazorDesignTimeNodeWriter : BlazorNodeWriter + internal class ComponentDesignTimeNodeWriter : ComponentNodeWriter { private readonly ScopeStack _scopeStack = new ScopeStack(); private static readonly string DesignTimeVariable = "__o"; - public override void WriteHtmlBlock(CodeRenderingContext context, MarkupBlockIntermediateNode node) + public override void WriteMarkupBlock(CodeRenderingContext context, MarkupBlockIntermediateNode node) { if (context == null) { @@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components // Do nothing } - public override void WriteHtmlElement(CodeRenderingContext context, MarkupElementIntermediateNode node) + public override void WriteMarkupElement(CodeRenderingContext context, MarkupElementIntermediateNode node) { if (context == null) { @@ -309,7 +309,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components // Do nothing } - public override void BeginWriteAttribute(CodeWriter codeWriter, string key) + protected override void BeginWriteAttribute(CodeWriter codeWriter, string key) { if (codeWriter == null) { diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentDocumentClassifierPass.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentDocumentClassifierPass.cs index dbf5bb100d..08b9dc7b03 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentDocumentClassifierPass.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentDocumentClassifierPass.cs @@ -3,7 +3,9 @@ using System; 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.Components @@ -25,6 +27,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Components return string.Equals(codeDocument.GetFileKind(), FileKinds.Component); } + protected override CodeTarget CreateTarget(RazorCodeDocument codeDocument, RazorCodeGenerationOptions options) + { + return new ComponentCodeTarget(options, TargetExtensions); + } + protected override void OnDocumentStructureCreated(RazorCodeDocument codeDocument, NamespaceDeclarationIntermediateNode @namespace, ClassDeclarationIntermediateNode @class, MethodDeclarationIntermediateNode method) { base.OnDocumentStructureCreated(codeDocument, @namespace, @class, method); @@ -45,7 +52,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components @namespace.Content = computedNamespace; @class.ClassName = computedClass; - @class.BaseType = $"global::{CodeGenerationConstants.ComponentBase.FullTypeName}"; + @class.BaseType = $"{CodeGenerationConstants.ComponentBase.FullTypeName}"; var filePath = codeDocument.Source.RelativePath ?? codeDocument.Source.FilePath; if (string.IsNullOrEmpty(filePath)) { @@ -61,12 +68,24 @@ namespace Microsoft.AspNetCore.Razor.Language.Components @class.Modifiers.Clear(); @class.Modifiers.Add("public"); - @class.Modifiers.Add("sealed"); + + var documentNode = codeDocument.GetDocumentIntermediateNode(); + var typeParamReferences = documentNode.FindDirectiveReferences(ComponentTypeParamDirective.Directive); + for (var i = 0; i < typeParamReferences.Count; i++) + { + var typeParamNode = (DirectiveIntermediateNode)typeParamReferences[i].Node; + if (typeParamNode.HasDiagnostics) + { + continue; + } + + @class.TypeParameters.Add(new TypeParameter() { ParameterName = typeParamNode.Tokens.First().Content, }); + } method.MethodName = CodeGenerationConstants.ComponentBase.BuildRenderTree; method.ReturnType = "void"; method.Modifiers.Clear(); - method.Modifiers.Add("public"); + method.Modifiers.Add("protected"); method.Modifiers.Add("override"); method.Parameters.Clear(); diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/EventHandlerLoweringPass.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentEventHandlerLoweringPass.cs similarity index 97% rename from src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/EventHandlerLoweringPass.cs rename to src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentEventHandlerLoweringPass.cs index 4ee38ed992..7a731dabdd 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/EventHandlerLoweringPass.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentEventHandlerLoweringPass.cs @@ -8,12 +8,17 @@ using Microsoft.AspNetCore.Razor.Language.Intermediate; namespace Microsoft.AspNetCore.Razor.Language.Components { - internal class EventHandlerLoweringPass : IntermediateNodePassBase, IRazorOptimizationPass + internal class ComponentEventHandlerLoweringPass : ComponentIntermediateNodePassBase, IRazorOptimizationPass { public override int Order => 50; protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { + if (!IsComponentDocument(documentNode)) + { + return; + } + var @namespace = documentNode.FindPrimaryNamespace(); var @class = documentNode.FindPrimaryClass(); if (@namespace == null || @class == null) diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentExtensions.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentExtensions.cs deleted file mode 100644 index 6f7a2affa4..0000000000 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentExtensions.cs +++ /dev/null @@ -1,22 +0,0 @@ -// 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 Microsoft.AspNetCore.Razor.Language.Extensions; - -namespace Microsoft.AspNetCore.Razor.Language.Components -{ - public static class ComponentExtensions - { - public static void Register(RazorProjectEngineBuilder builder) - { - if (builder == null) - { - throw new ArgumentNullException(nameof(builder)); - } - - FunctionsDirective.Register(builder); - builder.Features.Add(new ComponentDocumentClassifierPass()); - } - } -} diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/GenericComponentPass.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentGenericTypePass.cs similarity index 91% rename from src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/GenericComponentPass.cs rename to src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentGenericTypePass.cs index f1932742a0..a3646ba767 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/GenericComponentPass.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentGenericTypePass.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components // 1. Adds diagnostics for missing generic type arguments // 2. Rewrites the type name of the component to substitute generic type arguments // 3. Rewrites the type names of parameters/child content to substitute generic type arguments - internal class GenericComponentPass : IntermediateNodePassBase, IRazorOptimizationPass + internal class ComponentGenericTypePass : ComponentIntermediateNodePassBase, IRazorOptimizationPass { private TypeNameFeature _typeNameFeature; @@ -19,27 +19,42 @@ namespace Microsoft.AspNetCore.Razor.Language.Components // and it's usage of ChildContent. public override int Order => 160; - protected override void OnInitialized() + private TypeNameFeature TypeNameFeature { - _typeNameFeature = GetRequiredFeature(); + get + { + // Doing lazy intialization here to avoid making things really complicated when we don't + // need to exercise this code in tests. + if (_typeNameFeature == null) + { + _typeNameFeature = GetRequiredFeature(); + } + + return _typeNameFeature; + } } protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { - var visitor = new Visitor(_typeNameFeature); + if (!IsComponentDocument(documentNode)) + { + return; + } + + var visitor = new Visitor(this); visitor.Visit(documentNode); } private class Visitor : IntermediateNodeWalker { - private readonly TypeNameFeature _typeNameFeature; + private readonly ComponentGenericTypePass _pass; // Incrementing ID for type inference method names private int _id; - public Visitor(TypeNameFeature typeNameFeature) + public Visitor(ComponentGenericTypePass pass) { - _typeNameFeature = typeNameFeature; + _pass = pass; } public override void VisitComponent(ComponentIntermediateNode node) @@ -82,7 +97,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components if (ValidateTypeArguments(node, bindings)) { var mappings = bindings.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Content); - RewriteTypeNames(_typeNameFeature.CreateGenericTypeRewriter(mappings), node); + RewriteTypeNames(_pass.TypeNameFeature.CreateGenericTypeRewriter(mappings), node); } return; @@ -96,7 +111,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components // Since we're generating code in a different namespace, we need to 'global qualify' all of the types // to avoid clashes with our generated code. - RewriteTypeNames(_typeNameFeature.CreateGlobalQualifiedTypeNameRewriter(bindings.Keys), node); + RewriteTypeNames(_pass.TypeNameFeature.CreateGlobalQualifiedTypeNameRewriter(bindings.Keys), node); // // We need to verify that an argument was provided that 'covers' each type parameter. @@ -122,7 +137,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components continue; } - var typeParameters = _typeNameFeature.ParseTypeParameters(attribute.TypeName); + var typeParameters = _pass.TypeNameFeature.ParseTypeParameters(attribute.TypeName); if (typeParameters.Count == 0) { bindings.Remove(attribute.TypeName); @@ -145,7 +160,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components // helpful as possible. So let's substitute 'object' for all of those type parameters, and add // an error. var mappings = bindings.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Content); - RewriteTypeNames(_typeNameFeature.CreateGenericTypeRewriter(mappings), node); + RewriteTypeNames(_pass.TypeNameFeature.CreateGenericTypeRewriter(mappings), node); node.Diagnostics.Add(ComponentDiagnosticFactory.Create_GenericComponentTypeInferenceUnderspecified(node.Source, node, node.Component.GetTypeParameters())); } diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/HtmlBlockPass.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentHtmlBlockPass.cs similarity index 91% rename from src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/HtmlBlockPass.cs rename to src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentHtmlBlockPass.cs index e2cb256ff8..8327b33318 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/HtmlBlockPass.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentHtmlBlockPass.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components // // Does not preserve insignificant details of the HTML, like tag closing style // or quote style. - internal class HtmlBlockPass : IntermediateNodePassBase, IRazorOptimizationPass + internal class ComponentHtmlBlockPass : ComponentIntermediateNodePassBase, IRazorOptimizationPass { // Runs LATE because we want to destroy structure. public override int Order => 10000; @@ -23,6 +23,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Components RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { + if (!IsComponentDocument(documentNode)) + { + return; + } + if (documentNode.Options.DesignTime) { // Nothing to do during design time. @@ -114,9 +119,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components // We would store both the div and a tag in a list, but make sure to visit // the div first. Then when we process the div (recursively), we would remove // the a from the list. - private class FindHtmlTreeVisitor : - IntermediateNodeWalker, - IExtensionIntermediateNodeVisitor + private class FindHtmlTreeVisitor : IntermediateNodeWalker { private bool _foundNonHtml; @@ -129,7 +132,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components base.VisitDefault(node); } - public void VisitExtension(MarkupElementIntermediateNode node) + public override void VisitMarkupElement(MarkupElementIntermediateNode node) { // We need to restore the state after processing this node. // We might have found a leaf-block of HTML, but that shouldn't @@ -226,9 +229,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components } } - private class RewriteVisitor : - IntermediateNodeWalker, - IExtensionIntermediateNodeVisitor + private class RewriteVisitor : IntermediateNodeWalker { private readonly StringBuilder _encodingBuilder; @@ -243,7 +244,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components public StringBuilder Builder { get; } = new StringBuilder(); - public void VisitExtension(MarkupElementIntermediateNode node) + public override void VisitMarkupElement(MarkupElementIntermediateNode node) { for (var i = 0; i < _trees.Count; i++) { @@ -319,12 +320,24 @@ namespace Microsoft.AspNetCore.Razor.Language.Components public override void VisitHtmlAttributeValue(HtmlAttributeValueIntermediateNode node) { - Builder.Append(node.Children); + for (var i = 0; i < node.Children.Count; i++) + { + if (node.Children[i] is IntermediateToken token) + { + Builder.Append(token.Content); + } + } } public override void VisitHtml(HtmlContentIntermediateNode node) { - Builder.Append(node.Children); + for (var i = 0; i < node.Children.Count; i++) + { + if (node.Children[i] is IntermediateToken token) + { + Builder.Append(token.Content); + } + } } } } diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BlazorImportProjectFeature.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentImportProjectFeature.cs similarity index 79% rename from src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BlazorImportProjectFeature.cs rename to src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentImportProjectFeature.cs index a180d58f74..dea07160f1 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BlazorImportProjectFeature.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentImportProjectFeature.cs @@ -9,7 +9,7 @@ using System.Text; namespace Microsoft.AspNetCore.Razor.Language.Components { - internal class BlazorImportProjectFeature : IImportProjectFeature + internal class ComponentImportProjectFeature : IImportProjectFeature { private const string ImportsFileName = "_ViewImports.cshtml"; @@ -33,6 +33,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Components throw new ArgumentNullException(nameof(projectItem)); } + // Don't add Component imports for a non-component. + if (!string.Equals(projectItem.FileKind, FileKinds.Component, StringComparison.OrdinalIgnoreCase)) + { + return Array.Empty(); + } + var imports = new List() { new VirtualProjectItem(DefaultUsingImportContent), @@ -46,13 +52,15 @@ namespace Microsoft.AspNetCore.Razor.Language.Components // Avoiding the path-specific APIs here, we want to handle all styles of paths // on all platforms var trimLength = projectItem.FilePath.Length + (projectItem.FilePath.StartsWith("/") ? 0 : 1); - var baseDirectory = projectItem.PhysicalPath.Substring(0, projectItem.PhysicalPath.Length - trimLength); - - var lastSlash = baseDirectory.LastIndexOfAny(PathSeparators); - var baseNamespace = lastSlash == -1 ? baseDirectory : baseDirectory.Substring(lastSlash + 1); - if (!string.IsNullOrEmpty(baseNamespace)) + if (projectItem.PhysicalPath.Length > trimLength) { - imports.Add(new VirtualProjectItem($@"@addTagHelper ""*, {baseNamespace}""")); + var baseDirectory = projectItem.PhysicalPath.Substring(0, projectItem.PhysicalPath.Length - trimLength); + var lastSlash = baseDirectory.LastIndexOfAny(PathSeparators); + var baseNamespace = lastSlash == -1 ? baseDirectory : baseDirectory.Substring(lastSlash + 1); + if (!string.IsNullOrEmpty(baseNamespace)) + { + imports.Add(new VirtualProjectItem($@"@addTagHelper ""*, {baseNamespace}""")); + } } } diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentInjectDirective.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentInjectDirective.cs new file mode 100644 index 0000000000..3c9923008b --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentInjectDirective.cs @@ -0,0 +1,36 @@ +// 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.Language.Components +{ + // Much of the following is equivalent to Microsoft.AspNetCore.Mvc.Razor.Extensions's InjectDirective, + // but this one outputs properties annotated for Blazor's property injector, plus it doesn't need to + // support multiple CodeTargets. + + internal class ComponentInjectDirective + { + public static readonly DirectiveDescriptor Directive = DirectiveDescriptor.CreateDirective( + "inject", + DirectiveKind.SingleLine, + builder => + { + builder.AddTypeToken("TypeName", "The type of the service to inject."); + builder.AddMemberToken("PropertyName", "The name of the property."); + builder.Usage = DirectiveUsage.FileScopedMultipleOccurring; + builder.Description = "Inject a service from the application's service container into a property."; + }); + + public static void Register(RazorProjectEngineBuilder builder) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + builder.AddDirective(FileKinds.Component, Directive); + builder.Features.Add(new ComponentInjectDirectivePass()); + } + } +} diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentInjectDirectivePass.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentInjectDirectivePass.cs new file mode 100644 index 0000000000..6ad554b03a --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentInjectDirectivePass.cs @@ -0,0 +1,58 @@ +// 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.Linq; +using Microsoft.AspNetCore.Razor.Language.Intermediate; + +namespace Microsoft.AspNetCore.Razor.Language.Components +{ + internal class ComponentInjectDirectivePass : IntermediateNodePassBase, IRazorDirectiveClassifierPass + { + protected override void ExecuteCore( + RazorCodeDocument codeDocument, + DocumentIntermediateNode documentNode) + { + var visitor = new Visitor(); + visitor.Visit(documentNode); + + var properties = new HashSet(StringComparer.Ordinal); + var classNode = documentNode.FindPrimaryClass(); + + for (var i = visitor.Directives.Count - 1; i >= 0; i--) + { + var directive = visitor.Directives[i]; + var tokens = directive.Tokens.ToArray(); + if (tokens.Length < 2) + { + continue; + } + + var typeName = tokens[0].Content; + var memberName = tokens[1].Content; + + if (!properties.Add(memberName)) + { + continue; + } + + classNode.Children.Add(new ComponentInjectIntermediateNode(typeName, memberName)); + } + } + + private class Visitor : IntermediateNodeWalker + { + public IList Directives { get; } + = new List(); + + public override void VisitDirective(DirectiveIntermediateNode node) + { + if (node.Directive == ComponentInjectDirective.Directive) + { + Directives.Add(node); + } + } + } + } +} diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentInjectIntermediateNode.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentInjectIntermediateNode.cs new file mode 100644 index 0000000000..ee0363fd7e --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentInjectIntermediateNode.cs @@ -0,0 +1,60 @@ +// 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 Microsoft.AspNetCore.Razor.Language.CodeGeneration; +using Microsoft.AspNetCore.Razor.Language.Intermediate; + +namespace Microsoft.AspNetCore.Razor.Language.Components +{ + internal class ComponentInjectIntermediateNode : ExtensionIntermediateNode + { + private static readonly IList _injectedPropertyModifiers = new[] + { + $"[global::{ComponentsApi.InjectAttribute.FullTypeName}]", + "private" // Encapsulation is the default + }; + + public ComponentInjectIntermediateNode(string typeName, string memberName) + { + TypeName = typeName; + MemberName = memberName; + } + + public string TypeName { get; } + + public string MemberName { get; } + + public override IntermediateNodeCollection Children => IntermediateNodeCollection.ReadOnly; + + + public override void Accept(IntermediateNodeVisitor visitor) + { + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + + AcceptExtensionNode(this, visitor); + } + + public override void WriteNode(CodeTarget target, CodeRenderingContext context) + { + if (target == null) + { + throw new ArgumentNullException(nameof(target)); + } + + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + context.CodeWriter.WriteAutoPropertyDeclaration( + _injectedPropertyModifiers, + TypeName, + MemberName); + } + } +} diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentIntermediateNodePassBase.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentIntermediateNodePassBase.cs new file mode 100644 index 0000000000..5aa169ff4f --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentIntermediateNodePassBase.cs @@ -0,0 +1,21 @@ +// 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 Microsoft.AspNetCore.Razor.Language.Intermediate; + +namespace Microsoft.AspNetCore.Razor.Language.Components +{ + internal abstract class ComponentIntermediateNodePassBase : IntermediateNodePassBase + { + protected bool IsComponentDocument(DocumentIntermediateNode document) + { + if (document == null) + { + throw new ArgumentNullException(nameof(document)); + } + + return string.Equals(document.DocumentKind, ComponentDocumentClassifierPass.ComponentDocumentKind, StringComparison.Ordinal); + } + } +} diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/LayoutDirective.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentLayoutDirective.cs similarity index 83% rename from src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/LayoutDirective.cs rename to src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentLayoutDirective.cs index 0d2d586260..c746b75d7b 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/LayoutDirective.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentLayoutDirective.cs @@ -2,11 +2,10 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNetCore.Razor.Language; namespace Microsoft.AspNetCore.Razor.Language.Components { - internal static class LayoutDirective + internal static class ComponentLayoutDirective { public static readonly DirectiveDescriptor Directive = DirectiveDescriptor.CreateDirective( "layout", @@ -25,8 +24,8 @@ namespace Microsoft.AspNetCore.Razor.Language.Components throw new ArgumentNullException(nameof(builder)); } - builder.AddDirective(Directive); - builder.Features.Add(new LayoutDirectivePass()); + builder.AddDirective(FileKinds.Component, Directive); + builder.Features.Add(new ComponentLayoutDirectivePass()); } } } \ No newline at end of file diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/LayoutDirectivePass.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentLayoutDirectivePass.cs similarity index 92% rename from src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/LayoutDirectivePass.cs rename to src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentLayoutDirectivePass.cs index a22160570d..b1c36f3152 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/LayoutDirectivePass.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentLayoutDirectivePass.cs @@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Razor.Language.Intermediate; namespace Microsoft.AspNetCore.Razor.Language.Components { - internal class LayoutDirectivePass : IntermediateNodePassBase, IRazorDirectiveClassifierPass + internal class ComponentLayoutDirectivePass : IntermediateNodePassBase, IRazorDirectiveClassifierPass { protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components return; } - var directives = documentNode.FindDirectiveReferences(LayoutDirective.Directive); + var directives = documentNode.FindDirectiveReferences(ComponentLayoutDirective.Directive); if (directives.Count == 0) { return; diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentLoweringPass.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentLoweringPass.cs index c32df5738d..61fd26cad0 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentLoweringPass.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentLoweringPass.cs @@ -7,13 +7,18 @@ using Microsoft.AspNetCore.Razor.Language.Intermediate; namespace Microsoft.AspNetCore.Razor.Language.Components { - internal class ComponentLoweringPass : IntermediateNodePassBase, IRazorOptimizationPass + internal class ComponentLoweringPass : ComponentIntermediateNodePassBase, IRazorOptimizationPass { // This pass runs earlier than our other passes that 'lower' specific kinds of attributes. public override int Order => 0; protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { + if (!IsComponentDocument(documentNode)) + { + return; + } + var @namespace = documentNode.FindPrimaryNamespace(); var @class = documentNode.FindPrimaryClass(); if (@namespace == null || @class == null) diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BlazorNodeWriter.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentNodeWriter.cs similarity index 88% rename from src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BlazorNodeWriter.cs rename to src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentNodeWriter.cs index 256ffbee8f..0de9d18a89 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BlazorNodeWriter.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentNodeWriter.cs @@ -10,23 +10,9 @@ using Microsoft.AspNetCore.Razor.Language.Intermediate; namespace Microsoft.AspNetCore.Razor.Language.Components { - internal abstract class BlazorNodeWriter : IntermediateNodeWriter + internal abstract class ComponentNodeWriter : IntermediateNodeWriter, ITemplateTargetExtension { - public abstract void BeginWriteAttribute(CodeWriter codeWriter, string key); - - public abstract void WriteComponent(CodeRenderingContext context, ComponentIntermediateNode node); - - public abstract void WriteComponentAttribute(CodeRenderingContext context, ComponentAttributeIntermediateNode node); - - public abstract void WriteComponentChildContent(CodeRenderingContext context, ComponentChildContentIntermediateNode node); - - public abstract void WriteComponentTypeArgument(CodeRenderingContext context, ComponentTypeArgumentIntermediateNode node); - - public abstract void WriteHtmlElement(CodeRenderingContext context, MarkupElementIntermediateNode node); - - public abstract void WriteHtmlBlock(CodeRenderingContext context, MarkupBlockIntermediateNode node); - - public abstract void WriteReferenceCapture(CodeRenderingContext context, ReferenceCaptureIntermediateNode node); + protected abstract void BeginWriteAttribute(CodeWriter codeWriter, string key); protected abstract void WriteReferenceCaptureInnards(CodeRenderingContext context, ReferenceCaptureIntermediateNode node, bool shouldTypeCheck); @@ -53,9 +39,8 @@ namespace Microsoft.AspNetCore.Razor.Language.Components return; } - // Currently the same for design time and runtime - public void WriteComponentTypeInferenceMethod(CodeRenderingContext context, ComponentTypeInferenceMethodIntermediateNode node) + public override void WriteComponentTypeInferenceMethod(CodeRenderingContext context, ComponentTypeInferenceMethodIntermediateNode node) { if (context == null) { diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/PageDirective.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentPageDirective.cs similarity index 82% rename from src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/PageDirective.cs rename to src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentPageDirective.cs index 08b5ec74b8..80ebd9ffca 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/PageDirective.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentPageDirective.cs @@ -2,12 +2,11 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Intermediate; namespace Microsoft.AspNetCore.Razor.Language.Components { - internal class PageDirective + internal class ComponentPageDirective { public static readonly DirectiveDescriptor Directive = DirectiveDescriptor.CreateDirective( "page", @@ -19,7 +18,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components builder.Description = ComponentResources.PageDirective_Description; }); - private PageDirective(string routeTemplate, IntermediateNode directiveNode) + private ComponentPageDirective(string routeTemplate, IntermediateNode directiveNode) { RouteTemplate = routeTemplate; DirectiveNode = directiveNode; @@ -36,8 +35,8 @@ namespace Microsoft.AspNetCore.Razor.Language.Components throw new ArgumentNullException(nameof(builder)); } - builder.AddDirective(Directive); - builder.Features.Add(new PageDirectivePass()); + builder.AddDirective(FileKinds.Component, Directive); + builder.Features.Add(new ComponentPageDirectivePass()); return builder; } } diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/PageDirectivePass.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentPageDirectivePass.cs similarity index 93% rename from src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/PageDirectivePass.cs rename to src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentPageDirectivePass.cs index 224b85b503..0fe0ac5e26 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/PageDirectivePass.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentPageDirectivePass.cs @@ -3,13 +3,11 @@ using System; using System.Linq; -using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.Language.CodeGeneration; using Microsoft.AspNetCore.Razor.Language.Intermediate; namespace Microsoft.AspNetCore.Razor.Language.Components { - internal class PageDirectivePass : IntermediateNodePassBase, IRazorDirectiveClassifierPass + internal class ComponentPageDirectivePass : IntermediateNodePassBase, IRazorDirectiveClassifierPass { protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { @@ -30,7 +28,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components return; } - var directives = documentNode.FindDirectiveReferences(PageDirective.Directive); + var directives = documentNode.FindDirectiveReferences(ComponentPageDirective.Directive); if (directives.Count == 0) { return; diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ReferenceCaptureLoweringPass.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentReferenceCaptureLoweringPass.cs similarity index 93% rename from src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ReferenceCaptureLoweringPass.cs rename to src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentReferenceCaptureLoweringPass.cs index c5a9cbac02..aa66e07c8d 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ReferenceCaptureLoweringPass.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentReferenceCaptureLoweringPass.cs @@ -1,18 +1,22 @@ // 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 Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Intermediate; namespace Microsoft.AspNetCore.Razor.Language.Components { - internal class ReferenceCaptureLoweringPass : IntermediateNodePassBase, IRazorOptimizationPass + internal class ComponentReferenceCaptureLoweringPass : ComponentIntermediateNodePassBase, IRazorOptimizationPass { // Run after component lowering pass public override int Order => 50; protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { + if (!IsComponentDocument(documentNode)) + { + return; + } + var @namespace = documentNode.FindPrimaryNamespace(); var @class = documentNode.FindPrimaryClass(); if (@namespace == null || @class == null) diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BlazorRuntimeNodeWriter.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentRuntimeNodeWriter.cs similarity index 98% rename from src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BlazorRuntimeNodeWriter.cs rename to src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentRuntimeNodeWriter.cs index 4d7fc4db3c..8fcf48ec18 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/BlazorRuntimeNodeWriter.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentRuntimeNodeWriter.cs @@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components /// /// Generates the C# code corresponding to Razor source document contents. /// - internal class BlazorRuntimeNodeWriter : BlazorNodeWriter + internal class ComponentRuntimeNodeWriter : ComponentNodeWriter { private readonly List _currentAttributeValues = new List(); private readonly ScopeStack _scopeStack = new ScopeStack(); @@ -145,7 +145,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components } } - public override void WriteHtmlBlock(CodeRenderingContext context, MarkupBlockIntermediateNode node) + public override void WriteMarkupBlock(CodeRenderingContext context, MarkupBlockIntermediateNode node) { if (context == null) { @@ -165,7 +165,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components .WriteEndMethodInvocation(); } - public override void WriteHtmlElement(CodeRenderingContext context, MarkupElementIntermediateNode node) + public override void WriteMarkupElement(CodeRenderingContext context, MarkupElementIntermediateNode node) { if (context == null) { @@ -641,7 +641,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components }); } } - + private void WriteAttribute(CodeWriter codeWriter, string key, IList value) { BeginWriteAttribute(codeWriter, key); @@ -649,7 +649,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components codeWriter.WriteEndMethodInvocation(); } - public override void BeginWriteAttribute(CodeWriter codeWriter, string key) + protected override void BeginWriteAttribute(CodeWriter codeWriter, string key) { codeWriter .WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{nameof(ComponentsApi.RenderTreeBuilder.AddAttribute)}") diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ScriptTagPass.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentScriptTagPass.cs similarity index 81% rename from src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ScriptTagPass.cs rename to src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentScriptTagPass.cs index 01086ec3ac..6fad5cfca5 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ScriptTagPass.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentScriptTagPass.cs @@ -6,14 +6,14 @@ using Microsoft.AspNetCore.Razor.Language.Intermediate; namespace Microsoft.AspNetCore.Razor.Language.Components { - internal class ScriptTagPass : IntermediateNodePassBase, IRazorDocumentClassifierPass + internal class ComponentScriptTagPass : ComponentIntermediateNodePassBase, IRazorDocumentClassifierPass { // Run as soon as possible after the Component rewrite pass - public override int Order => ComponentDocumentClassifierPass.DefaultFeatureOrder + 2; + public override int Order => 5; protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { - if (documentNode.DocumentKind != ComponentDocumentClassifierPass.ComponentDocumentKind) + if (!IsComponentDocument(documentNode)) { return; } @@ -22,9 +22,9 @@ namespace Microsoft.AspNetCore.Razor.Language.Components visitor.Visit(documentNode); } - private class Visitor : IntermediateNodeWalker, IExtensionIntermediateNodeVisitor + private class Visitor : IntermediateNodeWalker { - public void VisitExtension(MarkupElementIntermediateNode node) + public override void VisitMarkupElement(MarkupElementIntermediateNode node) { // Disallow