protected override void ExecuteCore(RazorCodeDocument codeDocument) { var options = codeDocument.GetParserOptions() ?? _optionsFeature.GetOptions(); var syntaxTree = RazorSyntaxTree.Parse(codeDocument.Source, options); codeDocument.SetSyntaxTree(syntaxTree); var importSyntaxTrees = new RazorSyntaxTree[codeDocument.Imports.Count]; for (var i = 0; i < codeDocument.Imports.Count; i++) { importSyntaxTrees[i] = RazorSyntaxTree.Parse(codeDocument.Imports[i], options); } codeDocument.SetImportSyntaxTrees(importSyntaxTrees); }
protected override void ExecuteCore(RazorCodeDocument codeDocument) { var syntaxTree = codeDocument.GetSyntaxTree(); ThrowForMissingDocumentDependency(syntaxTree); var descriptors = codeDocument.GetTagHelpers(); if (descriptors == null) { var feature = Engine.GetFeature <ITagHelperFeature>(); if (feature == null) { // No feature, nothing to do. return; } descriptors = feature.GetDescriptors(); } var parserOptions = codeDocument.GetParserOptions(); // We need to find directives in all of the *imports* as well as in the main razor file // // The imports come logically before the main razor file and are in the order they // should be processed. DirectiveVisitor visitor; if (FileKinds.IsComponent(codeDocument.GetFileKind()) && (parserOptions == null || parserOptions.FeatureFlags.AllowComponentFileKind)) { codeDocument.TryComputeNamespace(fallbackToRootNamespace: true, out var currentNamespace); visitor = new ComponentDirectiveVisitor(codeDocument.Source.FilePath, descriptors, currentNamespace); } else { visitor = new TagHelperDirectiveVisitor(descriptors); } var imports = codeDocument.GetImportSyntaxTrees(); if (imports != null) { for (var i = 0; i < imports.Count; i++) { var import = imports[i]; visitor.Visit(import); } } visitor.Visit(syntaxTree); // This will always be null for a component document. var tagHelperPrefix = visitor.TagHelperPrefix; descriptors = visitor.Matches.ToArray(); var context = TagHelperDocumentContext.Create(tagHelperPrefix, descriptors); codeDocument.SetTagHelperContext(context); if (descriptors.Count == 0) { // No descriptors, no-op. return; } var rewrittenSyntaxTree = TagHelperParseTreeRewriter.Rewrite(syntaxTree, tagHelperPrefix, descriptors); codeDocument.SetSyntaxTree(rewrittenSyntaxTree); }
/// <inheritdoc /> protected override void OnDocumentStructureCreated( RazorCodeDocument codeDocument, NamespaceDeclarationIntermediateNode @namespace, ClassDeclarationIntermediateNode @class, MethodDeclarationIntermediateNode method) { if (!codeDocument.TryComputeNamespace(fallbackToRootNamespace: true, out var computedNamespace) || !TryComputeClassName(codeDocument, out var computedClass)) { // If we can't compute a nice namespace (no relative path) then just generate something // mangled. computedNamespace = FallbackRootNamespace; var checksum = Checksum.BytesToString(codeDocument.Source.GetChecksum()); computedClass = $"AspNetCore_{checksum}"; } var documentNode = codeDocument.GetDocumentIntermediateNode(); if (char.IsLower(computedClass, 0)) { // We don't allow component names to start with a lowercase character. documentNode.Diagnostics.Add( ComponentDiagnosticFactory.Create_ComponentNamesCannotStartWithLowerCase(computedClass, documentNode.Source)); } if (MangleClassNames) { computedClass = ComponentMetadata.MangleClassName(computedClass); } @namespace.Content = computedNamespace; @class.ClassName = computedClass; @class.Modifiers.Clear(); @class.Modifiers.Add("public"); @class.Modifiers.Add("partial"); if (FileKinds.IsComponentImport(codeDocument.GetFileKind())) { // We don't want component imports to be considered as real component. // But we still want to generate code for it so we can get diagnostics. @class.BaseType = typeof(object).FullName; method.ReturnType = "void"; method.MethodName = "Execute"; method.Modifiers.Clear(); method.Modifiers.Add("protected"); method.Parameters.Clear(); } else { @class.BaseType = ComponentsApi.ComponentBase.FullTypeName; // Constrained type parameters are only supported in Razor language versions v6.0 var razorLanguageVersion = codeDocument.GetParserOptions()?.Version ?? RazorLanguageVersion.Latest; var directiveType = razorLanguageVersion.CompareTo(RazorLanguageVersion.Version_6_0) >= 0 ? ComponentConstrainedTypeParamDirective.Directive : ComponentTypeParamDirective.Directive; var typeParamReferences = documentNode.FindDirectiveReferences(directiveType); 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, Constraints = typeParamNode.Tokens.Skip(1).FirstOrDefault()?.Content }); } method.ReturnType = "void"; method.MethodName = ComponentsApi.ComponentBase.BuildRenderTree; method.Modifiers.Clear(); method.Modifiers.Add("protected"); method.Modifiers.Add("override"); method.Parameters.Clear(); method.Parameters.Add(new MethodParameter() { ParameterName = ComponentsApi.RenderTreeBuilder.BuilderParameter, TypeName = ComponentsApi.RenderTreeBuilder.FullTypeName, }); } }
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { if (codeDocument == null) { throw new ArgumentNullException(nameof(codeDocument)); } if (documentNode == null) { throw new ArgumentNullException(nameof(documentNode)); } if (!IsComponentDocument(documentNode)) { return; } if (documentNode.Options.SuppressPrimaryMethodBody) { // There's no benefit running the whitespace trimmer if we're not emitting // the method bodies. return; } // There's no benefit running the whitespace trimmer during design-time builds if (documentNode.Options.DesignTime) { return; } var razorLanguageVersion = codeDocument.GetParserOptions().Version; var useLegacyBehavior = razorLanguageVersion.CompareTo(RazorLanguageVersion.Version_5_0) < 0; if (useLegacyBehavior) { // Prior to 5.0, the whitespace pass only applied to the BuildRenderTree method, and // only removed the top-level leading and trailing whitespace var method = documentNode.FindPrimaryMethod(); if (method != null) { RemoveContiguousWhitespace(method.Children, TraversalDirection.Forwards); RemoveContiguousWhitespace(method.Children, TraversalDirection.Backwards); } } else { // From 5.0 onwards, the whitespace pass applies as broadly as possible. It removes leading // and trailing whitespace from all methods, elements, and child component blocks. There's // also a directive that can disable it. // Respect @preservewhitespace directives if (PreserveWhitespaceIsEnabled(documentNode)) { return; } var @class = documentNode.FindPrimaryClass(); if (@class != null) { var visitor = new Visitor(); visitor.Visit(@class); } } }