/// <summary> /// Merges <see cref="Chunk"/> inherited by default and <see cref="CodeTree"/> instances produced by parsing /// <c>_ViewImports</c> files into the specified <paramref name="codeTree"/>. /// </summary> /// <param name="codeTree">The <see cref="CodeTree"/> to merge in to.</param> /// <param name="inheritedCodeTrees"><see cref="IReadOnlyList{CodeTree}"/> inherited from <c>_ViewImports</c> /// files.</param> /// <param name="defaultModel">The list of chunks to merge.</param> public void MergeInheritedCodeTrees([NotNull] CodeTree codeTree, [NotNull] IReadOnlyList <CodeTree> inheritedCodeTrees, string defaultModel) { var mergerMappings = GetMergerMappings(codeTree, defaultModel); IChunkMerger merger; // We merge chunks into the codeTree in two passes. In the first pass, we traverse the CodeTree visiting // a mapped IChunkMerger for types that are registered. foreach (var chunk in codeTree.Chunks) { if (mergerMappings.TryGetValue(chunk.GetType(), out merger)) { merger.VisitChunk(chunk); } } // In the second phase we invoke IChunkMerger.Merge for each chunk that has a mapped merger. // During this phase, the merger can either add to the CodeTree or ignore the chunk based on the merging // rules. // Read the chunks outside in - that is chunks from the _ViewImports closest to the page get merged in first // and the furthest one last. This allows the merger to ignore a directive like @model that was previously // seen. var chunksToMerge = inheritedCodeTrees.SelectMany(tree => tree.Chunks) .Concat(_defaultInheritedChunks); foreach (var chunk in chunksToMerge) { if (mergerMappings.TryGetValue(chunk.GetType(), out merger)) { merger.Merge(codeTree, chunk); } } }
/// <summary> /// Merges a list of chunks into the specified <paramref name="codeTree"/>. /// </summary> /// <param name="codeTree">The <see cref="CodeTree"/> to merge.</param> /// <param name="inherited">The <see credit="IReadOnlyList{T}"/> of <see cref="Chunk"/> to merge.</param> /// <param name="defaultModel">The list of chunks to merge.</param> public void MergeInheritedChunks([NotNull] CodeTree codeTree, [NotNull] IReadOnlyList <Chunk> inherited, string defaultModel) { var mergerMappings = GetMergerMappings(codeTree, defaultModel); IChunkMerger merger; // We merge chunks into the codeTree in two passes. In the first pass, we traverse the CodeTree visiting // a mapped IChunkMerger for types that are registered. foreach (var chunk in codeTree.Chunks) { if (mergerMappings.TryGetValue(chunk.GetType(), out merger)) { merger.VisitChunk(chunk); } } // In the second phase we invoke IChunkMerger.Merge for each chunk that has a mapped merger. // During this phase, the merger can either add to the CodeTree or ignore the chunk based on the merging // rules. foreach (var chunk in inherited) { if (mergerMappings.TryGetValue(chunk.GetType(), out merger)) { // TODO: When mapping chunks, we should remove mapping information since it would be incorrect // to generate it in the page that inherits it. Tracked by #945 merger.Merge(codeTree, chunk); } } }
private void AddImports(CodeTree codeTree, CSharpCodeWriter writer, IEnumerable <string> defaultImports) { // Write out using directives var usingVisitor = new CSharpUsingVisitor(writer, Context); foreach (Chunk chunk in Tree.Chunks) { usingVisitor.Accept(chunk); } defaultImports = defaultImports.Except(usingVisitor.ImportedUsings); foreach (string import in defaultImports) { writer.WriteUsing(import); } string taskNamespace = typeof(Task).Namespace; // We need to add the task namespace but ONLY if it hasn't been added by the default imports or using imports yet. if (!defaultImports.Contains(taskNamespace) && !usingVisitor.ImportedUsings.Contains(taskNamespace)) { writer.WriteUsing(taskNamespace); } }
/// <summary> /// Generates random code of a given length. /// </summary> /// <param name="symbols">The amount of code to generate, excluding `</param> /// <param name="prepend">True if this code goes before other code</param> /// <returns>Returns a string of code</returns> public static string Generate(int count, bool prepend, Random rng) { if (count < 2 && !prepend || count < 1 && prepend) { throw new ArgumentException("Count must be at least 2. (1 in prepend mode)"); } int slots = 2; CodeTree tree = new CodeTree("`"); while (slots < count) { tree.FillRandom(new CodeTree("`"), rng); slots++; } if (prepend) { tree.FillLast(new Leaf("")); slots--; } for (; slots > 0; slots--) { tree.FillLast(rng.Next() % 2 == 0 ? new Leaf("k") : new Leaf("s")); } return(tree.ToString()); }
/// <summary> /// Returns the type name of the Model specified via a <see cref="ModelChunk"/> in the /// <paramref name="codeTree"/> if specified or the default model type. /// </summary> /// <param name="codeTree">The <see cref="CodeTree"/> to scan for <see cref="ModelChunk"/>s in.</param> /// <param name="defaultModelName">The <see cref="Type"/> name of the default model.</param> /// <returns>The model type name for the generated page.</returns> public static string GetModelTypeName([NotNull] CodeTree codeTree, [NotNull] string defaultModelName) { var modelChunk = GetModelChunk(codeTree); return(modelChunk != null ? modelChunk.ModelType : defaultModelName); }
public GeneratorResults(Block document, IList <RazorError> parserErrors, CodeBuilderResult codeBuilderResult, CodeTree codeTree) : this(parserErrors.Count == 0, document, parserErrors, codeBuilderResult, codeTree) { }
public void Merge_IgnoresNamespacesThatHaveBeenVisitedDuringMerge() { // Arrange var merger = new UsingChunkMerger(); var codeTree = new CodeTree(); // Act merger.Merge(codeTree, new UsingChunk { Namespace = "Microsoft.AspNet.Mvc" }); merger.Merge(codeTree, new UsingChunk { Namespace = "Microsoft.AspNet.Mvc" }); merger.Merge(codeTree, new UsingChunk { Namespace = "Microsoft.AspNet.Mvc.Razor" }); // Assert Assert.Equal(2, codeTree.Chunks.Count); var chunk = Assert.IsType <UsingChunk>(codeTree.Chunks[0]); Assert.Equal("Microsoft.AspNet.Mvc", chunk.Namespace); chunk = Assert.IsType <UsingChunk>(codeTree.Chunks[1]); Assert.Equal("Microsoft.AspNet.Mvc.Razor", chunk.Namespace); }
public void MergeChunks_VisitsChunksPriorToMerging() { // Arrange var codeTree = new CodeTree(); codeTree.Chunks.Add(new LiteralChunk()); codeTree.Chunks.Add(new ExpressionBlockChunk()); codeTree.Chunks.Add(new ExpressionBlockChunk()); var merger = new Mock <IChunkMerger>(); var mockSequence = new MockSequence(); merger.InSequence(mockSequence) .Setup(m => m.VisitChunk(It.IsAny <LiteralChunk>())) .Verifiable(); merger.InSequence(mockSequence) .Setup(m => m.Merge(codeTree, It.IsAny <LiteralChunk>())) .Verifiable(); var inheritedChunks = new List <Chunk> { new CodeAttributeChunk(), new LiteralChunk() }; var utility = new ChunkInheritanceUtility(codeTree, inheritedChunks, "dynamic"); // Act utility.ChunkMergers[typeof(LiteralChunk)] = merger.Object; utility.MergeInheritedChunks(inheritedChunks); // Assert merger.Verify(); }
public virtual bool FillLast(CodeTree toAdd) { if (child2 == null) { child2 = toAdd; return(true); } else if (child2.FillLast(toAdd)) { return(true); } else if (child1 == null) { child1 = toAdd; return(true); } else if (child1.FillLast(toAdd)) { return(true); } else { return(false); } }
/// <summary> /// Instantiates a new instance of <see cref="ChunkInheritanceUtility"/>. /// </summary> /// <param name="codeTree">The <see cref="CodeTree"/> instance to add <see cref="Chunk"/>s to.</param> /// <param name="defaultInheritedChunks">The list of <see cref="Chunk"/>s inherited by default.</param> /// <param name="defaultModel">The model type used in the event no model is specified via the /// <c>@model</c> keyword.</param> public ChunkInheritanceUtility([NotNull] CodeTree codeTree, [NotNull] IReadOnlyList <Chunk> defaultInheritedChunks, [NotNull] string defaultModel) { CodeTree = codeTree; _defaultInheritedChunks = defaultInheritedChunks; ChunkMergers = GetMergerMappings(codeTree, defaultModel); }
/// <summary> /// Returns the <see cref="ModelChunk"/> used to determine the model name for the page generated /// using the specified <paramref name="codeTree"/> /// </summary> /// <param name="codeTree">The <see cref="CodeTree"/> to scan for <see cref="ModelChunk"/>s in.</param> /// <returns>The last <see cref="ModelChunk"/> in the <see cref="CodeTree"/> if found, null otherwise. /// </returns> public static ModelChunk GetModelChunk([NotNull] CodeTree codeTree) { // If there's more than 1 model chunk there will be a Razor error BUT we want intellisense to show up on // the current model chunk that the user is typing. return(codeTree.Chunks .OfType <ModelChunk>() .LastOrDefault()); }
/// <summary> /// Instantiates a new <see cref="GeneratorResults"/> instance. /// </summary> /// <param name="document">The <see cref="Block"/> for the syntax tree.</param> /// <param name="tagHelperDescriptors"><see cref="TagHelperDescriptor"/>s for the document.</param> /// <param name="parserErrors"><see cref="RazorError"/>s encountered when parsing the document.</param> /// <param name="codeBuilderResult">The results of generating code for the document.</param> /// <param name="codeTree">A <see cref="CodeTree"/> for the document.</param> public GeneratorResults([NotNull] Block document, [NotNull] IEnumerable <TagHelperDescriptor> tagHelperDescriptors, [NotNull] IList <RazorError> parserErrors, [NotNull] CodeBuilderResult codeBuilderResult, [NotNull] CodeTree codeTree) : this(parserErrors.Count == 0, document, tagHelperDescriptors, parserErrors, codeBuilderResult, codeTree) { }
/// <summary> /// Instantiates a new <see cref="GeneratorResults"/> instance. /// </summary> /// <param name="parserResults">The results of parsing a document.</param> /// <param name="codeBuilderResult">The results of generating code for the document.</param> /// <param name="codeTree">A <see cref="CodeTree"/> for the document.</param> public GeneratorResults([NotNull] ParserResults parserResults, [NotNull] CodeBuilderResult codeBuilderResult, [NotNull] CodeTree codeTree) : this(parserResults.Document, parserResults.TagHelperDescriptors, parserResults.ParserErrors, codeBuilderResult, codeTree) { }
/// <inheritdoc /> public void Merge([NotNull] CodeTree codeTree, [NotNull] Chunk chunk) { var injectChunk = ChunkHelper.EnsureChunk <InjectChunk>(chunk); if (!_addedMemberNames.Contains(injectChunk.MemberName)) { _addedMemberNames.Add(injectChunk.MemberName); codeTree.Chunks.Add(TransformChunk(injectChunk)); } }
/// <inheritdoc /> public void Merge([NotNull] CodeTree codeTree, [NotNull] Chunk chunk) { var namespaceChunk = ChunkHelper.EnsureChunk <UsingChunk>(chunk); if (!_currentUsings.Contains(namespaceChunk.Namespace)) { _currentUsings.Add(namespaceChunk.Namespace); codeTree.Chunks.Add(namespaceChunk); } }
public virtual bool FillRandom(CodeTree toAdd, Random rng) { if (rng.Next() % 2 == 0) { if (child1 != null) { if (child1.FillRandom(toAdd, rng)) { return(true); } else { if (child2.FillRandom(toAdd, rng)) { return(true); } else { return(false); } } } else { child1 = toAdd; return(true); } } else { if (child2 != null) { if (child2.FillRandom(toAdd, rng)) { return(true); } else { if (child1.FillRandom(toAdd, rng)) { return(true); } else { return(false); } } } else { child2 = toAdd; return(true); } } }
public virtual bool FillRandom(CodeTree toAdd) { if (rng.Range(0, 2) == 0) { if (child1 != null) { if (child1.FillRandom(toAdd)) { return(true); } else { if (child2.FillRandom(toAdd)) { return(true); } else { return(false); } } } else { child1 = toAdd; return(true); } } else { if (child2 != null) { if (child2.FillRandom(toAdd)) { return(true); } else { if (child1.FillRandom(toAdd)) { return(true); } else { return(false); } } } else { child2 = toAdd; return(true); } } }
public void MergeInheritedChunks_MergesDefaultInheritedChunks() { // Arrange var fileProvider = new TestFileProvider(); fileProvider.AddFile(@"Views\_GlobalImport.cshtml", "@inject DifferentHelper<TModel> Html"); var cache = new DefaultCodeTreeCache(fileProvider); var host = new MvcRazorHost(cache); var defaultChunks = new Chunk[] { new InjectChunk("MyTestHtmlHelper", "Html"), new UsingChunk { Namespace = "AppNamespace.Model" }, }; var inheritedCodeTrees = new CodeTree[] { new CodeTree { Chunks = new Chunk[] { new UsingChunk { Namespace = "InheritedNamespace" }, new LiteralChunk { Text = "some text" } } }, new CodeTree { Chunks = new Chunk[] { new UsingChunk { Namespace = "AppNamespace.Model" }, } } }; var utility = new ChunkInheritanceUtility(host, cache, defaultChunks); var codeTree = new CodeTree(); // Act utility.MergeInheritedCodeTrees(codeTree, inheritedCodeTrees, "dynamic"); // Assert Assert.Equal(3, codeTree.Chunks.Count); Assert.Same(inheritedCodeTrees[0].Chunks[0], codeTree.Chunks[0]); Assert.Same(inheritedCodeTrees[1].Chunks[0], codeTree.Chunks[1]); Assert.Same(defaultChunks[0], codeTree.Chunks[2]); }
protected GeneratorResults(bool success, Block document, IList <RazorError> parserErrors, CodeBuilderResult codeBuilderResult, CodeTree codeTree) : base(success, document, parserErrors) { GeneratedCode = codeBuilderResult.Code; DesignTimeLineMappings = codeBuilderResult.DesignTimeLineMappings; CodeTree = codeTree; }
private static Dictionary <Type, IChunkMerger> GetMergerMappings(CodeTree codeTree, string defaultModel) { var modelType = ChunkHelper.GetModelTypeName(codeTree, defaultModel); return(new Dictionary <Type, IChunkMerger> { { typeof(UsingChunk), new UsingChunkMerger() }, { typeof(InjectChunk), new InjectChunkMerger(modelType) }, { typeof(SetBaseTypeChunk), new SetBaseTypeChunkMerger(modelType) } }); }
/// <summary> /// Instantiates a new <see cref="GeneratorResults"/> instance. /// </summary> /// <param name="document">The <see cref="Block"/> for the syntax tree.</param> /// <param name="tagHelperDescriptors"> /// The <see cref="TagHelperDescriptor"/>s that apply to the current Razor document. /// </param> /// <param name="errorSink"> /// The <see cref="ParserErrorSink"/> used to collect <see cref="RazorError"/>s encountered when parsing the /// current Razor document. /// </param> /// <param name="codeBuilderResult">The results of generating code for the document.</param> /// <param name="codeTree">A <see cref="CodeTree"/> for the document.</param> public GeneratorResults([NotNull] Block document, [NotNull] IEnumerable <TagHelperDescriptor> tagHelperDescriptors, [NotNull] ParserErrorSink errorSink, [NotNull] CodeBuilderResult codeBuilderResult, [NotNull] CodeTree codeTree) : base(document, tagHelperDescriptors, errorSink) { GeneratedCode = codeBuilderResult.Code; DesignTimeLineMappings = codeBuilderResult.DesignTimeLineMappings; CodeTree = codeTree; }
public virtual string GenerateSnippet(CodeTree tree) { var result = ""; foreach (var codeTree in tree.Codes) { result = string.Concat(result, _actions[codeTree.GetType()](tree)); } return(result); }
/// <summary> /// Instantiates a new <see cref="GeneratorResults"/> instance. /// </summary> /// <param name="success"><c>true</c> if parsing was successful, <c>false</c> otherwise.</param> /// <param name="document">The <see cref="Block"/> for the syntax tree.</param> /// <param name="tagHelperDescriptors"><see cref="TagHelperDescriptor"/>s for the document.</param> /// <param name="parserErrors"><see cref="RazorError"/>s encountered when parsing the document.</param> /// <param name="codeBuilderResult">The results of generating code for the document.</param> /// <param name="codeTree">A <see cref="CodeTree"/> for the document.</param> protected GeneratorResults(bool success, [NotNull] Block document, [NotNull] IEnumerable <TagHelperDescriptor> tagHelperDescriptors, [NotNull] IList <RazorError> parserErrors, [NotNull] CodeBuilderResult codeBuilderResult, [NotNull] CodeTree codeTree) : base(success, document, tagHelperDescriptors, parserErrors) { GeneratedCode = codeBuilderResult.Code; DesignTimeLineMappings = codeBuilderResult.DesignTimeLineMappings; CodeTree = codeTree; }
/// <inheritdoc /> public void Merge([NotNull] CodeTree codeTree, [NotNull] Chunk chunk) { if (!_isBaseTypeSet) { var baseTypeChunk = ChunkHelper.EnsureChunk <SetBaseTypeChunk>(chunk); // The base type can set exactly once and the first one we encounter wins. _isBaseTypeSet = true; codeTree.Chunks.Add(TransformChunk(baseTypeChunk)); } }
public object DoConvert(string path, CodeTree codeTree, object value, Type targetType, object parameter, CultureInfo culture) { var parameters = new NameDictionary { { "@Value", value }, { "@TargetType", targetType }, { "@Parameter", parameter }, { "@Culture", culture }, }; return new Engine().FrameFunc(this, parameters, engine => engine.GetPath(path, codeTree)); }
public void AcceptTree(CodeTree tree) { if (Context.Host.DesignTimeMode) { using (Writer.BuildMethodDeclaration("private", "void", "@" + DesignTimeHelperMethodName)) { using (Writer.BuildDisableWarningScope(DisableVariableNamingWarnings)) { Accept(tree.Chunks); } } } }
public void Merge_IgnoresChunkIfChunkWithMatchingPropertyNameWasVisitedInCodeTree() { // Arrange var merger = new InjectChunkMerger("dynamic"); var codeTree = new CodeTree(); // Act merger.VisitChunk(new InjectChunk("MyTypeA", "MyProperty")); merger.Merge(codeTree, new InjectChunk("MyTypeB", "MyProperty")); // Assert Assert.Empty(codeTree.Chunks); }
public static object Call(string path, CodeTree codeTree, string staticMethodName, string methodName, string functionName, BuiltinFunction builtinFunction, Type type, ExpressionCollection typeArguments, IEnumerable<object> args, Engine engine) { if (path != null) return engine.CallPath(path, codeTree, args); if (functionName != null) return engine.CallFunction(functionName, args); if (builtinFunction != 0) return engine.CallBuiltinFunction(builtinFunction, args); var typeArgs = typeArguments.Count != 0 ? typeArguments.Get(engine).Cast<Type>().ToArray() : null; if (staticMethodName != null) return CallHelper.CallMethod(staticMethodName, true, type, null, args, typeArgs, engine); if (methodName != null) return CallHelper.CallMethod(methodName, false, type ?? engine.Context.GetType(), engine.Context, args, typeArgs, engine); return engine.Throw("nothing to call"); }
public void Process(CodeTree tree) { foreach (CodeTree node in tree.Codes) { var actors = _actors.Where(x => x.CanAct(node)); if (!actors.Any()) { throw new InvalidOperationException("Got no actor for " + node.GetType()); } foreach (var actor in actors) { actor.Invoke(node); } } }
public void Merge_ReplacesTModelTokensWithModel() { // Arrange var merger = new InjectChunkMerger("MyTestModel2"); var codeTree = new CodeTree(); // Act merger.Merge(codeTree, new InjectChunk("MyHelper<TModel>", "MyProperty")); // Assert var chunk = Assert.Single(codeTree.Chunks); var injectChunk = Assert.IsType <InjectChunk>(chunk); Assert.Equal("MyHelper<MyTestModel2>", injectChunk.TypeName); Assert.Equal("MyProperty", injectChunk.MemberName); }
public void Merge_ResolvesModelNameInTypesWithTModelToken() { // Arrange var merger = new InjectChunkMerger("dynamic"); var codeTree = new CodeTree(); // Act merger.Merge(codeTree, new InjectChunk("MyHelper<TModel>", "MyProperty")); // Assert var chunk = Assert.Single(codeTree.Chunks); var injectChunk = Assert.IsType <InjectChunk>(chunk); Assert.Equal("MyHelper<dynamic>", injectChunk.TypeName); Assert.Equal("MyProperty", injectChunk.MemberName); }
public void Merge_IgnoresSetBaseTypeChunksIfCodeTreeContainsOne() { // Arrange var merger = new SetBaseTypeChunkMerger("dynamic"); var codeTree = new CodeTree(); // Act merger.VisitChunk(new SetBaseTypeChunk { TypeName = "MyBaseType1" }); merger.Merge(codeTree, new SetBaseTypeChunk { TypeName = "MyBaseType2" }); // Assert Assert.Empty(codeTree.Chunks); }
private void AddImports(CodeTree codeTree, CSharpCodeWriter writer, IEnumerable<string> defaultImports) { // Write out using directives var usingVisitor = new CSharpUsingVisitor(writer, Context); foreach (Chunk chunk in Tree.Chunks) { usingVisitor.Accept(chunk); } defaultImports = defaultImports.Except(usingVisitor.ImportedUsings); foreach (string import in defaultImports) { writer.WriteUsing(import); } string taskNamespace = typeof(Task).Namespace; // We need to add the task namespace but ONLY if it hasn't been added by the default imports or using imports yet. if(!defaultImports.Contains(taskNamespace) && !usingVisitor.ImportedUsings.Contains(taskNamespace)) { writer.WriteUsing(taskNamespace); } }
public static void Print(CodeTree codeTree) { PrintNode(codeTree.Root, 0); Print(";\n"); }