public void ShouldParseFunctionCall() { var options = new FluidParserOptions { AllowFunctions = true }; #if COMPILED var _parser = new FluidParser(options).Compile(); #else var _parser = new FluidParser(options); #endif _parser.TryParse("{{ a() }}", out var template, out var errors); var statements = ((FluidTemplate)template).Statements; Assert.Single(statements); var outputStatement = statements[0] as OutputStatement; Assert.NotNull(outputStatement); var memberExpression = outputStatement.Expression as MemberExpression; Assert.Equal(2, memberExpression.Segments.Count); Assert.IsType <IdentifierSegment>(memberExpression.Segments[0]); Assert.IsType <FunctionCallSegment>(memberExpression.Segments[1]); }
public async Task ShouldNotBreakJObjectCustomizations() { var options = new TemplateOptions(); // When a property of a JObject value is accessed, try to look into its properties options.MemberAccessStrategy.Register <JObject, object>((source, name) => source[name]); // Convert JToken to FluidValue options.ValueConverters.Add(x => x is JObject o ? new ObjectValue(o) : null); options.ValueConverters.Add(x => x is JValue v ? v.Value : null); var model = JObject.Parse("{\"Name\": \"Bill\",\"Company\":{\"Name\":\"Microsoft\"}}"); _parser.TryParse("His name is {{ Name }}, Company : {{ Company.Name }}", out var template); var context = new TemplateContext(model, options); Assert.Equal("His name is Bill, Company : Microsoft", await template.RenderAsync(context)); }
private Dictionary <string, List <PatchSet> > RenderFilePatchTemplates(PatchRequest request, WingmanMod mod, Dictionary <string, string> modelVars) { var dict = mod.FilePatches.ToDictionary(k => k.Key, kvp => { var finalPatches = kvp.Value.Where(psList => { // REMEMBER: this is to keep the step, so have to return false to skip it if (mod.ModInfo.StepsEnabled.ContainsKey(psList.Name) && _parser.TryParse(mod.ModInfo.StepsEnabled[psList.Name], out var skipTemplate)) { var rendered = skipTemplate.Render(GetInputContext(request, modelVars)); var result = !bool.TryParse(rendered, out var skip) || skip; // var result = bool.TryParse(rendered, out var skip) || skip; // do NOT invert result: result *is* inverted return(result); } return(true); }).Select(psList => { psList.Patches = psList.Patches.Select(p => { if (_parser.TryParse(p.Substitution, out var subTemplate)) { p.Substitution = subTemplate.Render(GetInputContext(request, modelVars)); } if (_parser.TryParse(p.Template, out var template)) { p.Template = template.Render(GetInputContext(request, modelVars)); } if (p.Window != null) { p.Window.After = SafeRender(request, p.Window.After, modelVars); p.Window.Before = SafeRender(request, p.Window.Before, modelVars); } return(p); }).ToList(); return(psList); }).ToList(); return(finalPatches); });
private static async Task <string> CreateIssueBody(IEnumerable <Regression> regressions, string template) { var report = new Report { Regressions = regressions.OrderBy(x => x.CurrentResult.Scenario).ThenBy(x => x.CurrentResult.DateTimeUtc).ToList() }; // The base64 encoded MessagePack-serialized model var regressionBlock = CreateRegressionsBlock(regressions); if (!_fluidParser.TryParse(template, out var fluidTemplate, out var errors)) { Console.WriteLine("Error parsing the template:"); foreach (var error in errors) { Console.WriteLine(error); } return(""); } var context = new TemplateContext(report, _templateOptions); try { var body = await fluidTemplate.RenderAsync(context); body = AddOwners(body, regressions); body += regressionBlock; return(body); } catch (Exception e) { Console.WriteLine($"An error occurred while rendering an issue: {e}"); Console.WriteLine("[DEBUG] Model used:"); Console.WriteLine(regressionBlock); throw; } }
private async Task CheckAsync(string source, string expected, Action <TemplateContext> init = null) { _parser.TryParse("{% if " + source + " %}true{% else %}false{% endif %}", out var template, out var messages); var context = new TemplateContext(); init?.Invoke(context); var result = await template.RenderAsync(context); Assert.Equal(expected, result); }
public void ShouldNotParseFunctionCall() { var options = new FluidParserOptions { AllowFunctions = false }; #if COMPILED var parser = new FluidParser(options).Compile(); #else var parser = new FluidParser(options); #endif Assert.False(parser.TryParse("{{ a() }}", out var template, out var errors)); Assert.Contains(ErrorMessages.FunctionsNotAllowed, errors); }
public override async ValueTask <Completion> WriteToAsync(TextWriter writer, TextEncoder encoder, TemplateContext context) { context.IncrementSteps(); var relativePath = (await Path.EvaluateAsync(context)).ToStringValue(); if (!relativePath.EndsWith(ViewExtension, StringComparison.OrdinalIgnoreCase)) { relativePath += ViewExtension; } var fileProvider = context.Options.FileProvider; var fileInfo = fileProvider.GetFileInfo(relativePath); if (fileInfo == null || !fileInfo.Exists) { throw new FileNotFoundException(relativePath); } using (var stream = fileInfo.CreateReadStream()) using (var streamReader = new StreamReader(stream)) { context.EnterChildScope(); string partialTemplate = await streamReader.ReadToEndAsync(); if (_parser.TryParse(partialTemplate, out var result, out var errors)) { if (With != null) { var identifier = System.IO.Path.GetFileNameWithoutExtension(relativePath); var with = await With.EvaluateAsync(context); context.SetValue(identifier, with); } if (AssignStatements != null) { foreach (var assignStatement in AssignStatements) { await assignStatement.WriteToAsync(writer, encoder, context); } } await result.RenderAsync(writer, encoder, context); }
public async Task FunctionCallsShouldDefaultToNil() { var source = @" {{- a() -}} "; _parser.TryParse(source, out var template, out var error); var context = new TemplateContext(); var result = await template.RenderAsync(context); Assert.Equal("", result); }
public static CachedTemplate Parse(string input, bool bypass = false) { Guard.NotNull(input); CachedTemplate result; if (!bypass) { LockObject.EnterWriteLock(); try { if (Cache.TryGetValue(input, out result)) { return(result); } } finally { LockObject.ExitWriteLock(); } } Parser.TryParse(input, out var template, out var errorMessage); var error = TemplateError.Parse(errorMessage); result = new CachedTemplate(template, error); if (!bypass) { LockObject.EnterWriteLock(); try { Cache.Set(input, result); } finally { LockObject.ExitWriteLock(); } } return(result); }
public void ScopeShouldFallbackToTemplateOptions() { var parser = new FluidParser(); parser.TryParse("{{ p.NaMe }}", out var template, out var error); var options = new TemplateOptions(); options.Scope.SetValue("o1", new StringValue("o1")); options.Scope.SetValue("o2", new StringValue("o2")); var context = new TemplateContext(options); context.SetValue("o2", "new o2"); context.SetValue("o3", "o3"); Assert.Equal("o1", context.GetValue("o1").ToStringValue()); Assert.Equal("new o2", context.GetValue("o2").ToStringValue()); Assert.Equal("o3", context.GetValue("o3").ToStringValue()); }
public async Task ShouldRenderReadmeSample() { var options = new TemplateOptions(); // When a property of a JObject value is accessed, try to look into its properties options.MemberAccessStrategy.Register <JObject, object>((source, name) => source[name]); // Convert JToken to FluidValue options.ValueConverters.Add(x => x is JObject o ? new ObjectValue(o) : null); options.ValueConverters.Add(x => x is JValue v ? v.Value : null); var model = JObject.Parse("{\"Name\": \"Bill\"}"); var parser = new FluidParser(); parser.TryParse("His name is {{ Name }}", out var template); var context = new TemplateContext(model, options); Assert.Equal("His name is Bill", await template.RenderAsync(context)); }
public FluidBenchmarks() { _options.MemberAccessStrategy.Register <Product>(); _options.MemberAccessStrategy.MemberNameStrategy = MemberNameStrategies.CamelCase; _parser.TryParse(ProductTemplate, out _fluidTemplate, out var _); }
public void WrongTemplateShouldRenderErrorMessage(string source, string expected) { Assert.False(_parser.TryParse(source, out var _, out var error)); Assert.StartsWith(expected, error); // e.g., message then 'at (1:15)' }
private static IReadOnlyList <Statement> Parse(string source) { _parser.TryParse(source, out var template, out var errors); return(template.Statements); }
private async Task CheckAsync(string source, string expected, Action <TemplateContext> init = null) { _parser.TryParse(source, out var template, out var error); var context = new TemplateContext(); context.Options.MemberAccessStrategy.Register(new { name = "product 1", price = 1 }.GetType()); init?.Invoke(context); var result = await template.RenderAsync(context); Assert.Equal(expected, result); }
public void IncludeTag_With() { var fileProvider = new MockFileProvider(); fileProvider.Add("product.liquid", "Product: {{ product.title }} "); var options = new TemplateOptions() { FileProvider = fileProvider, MemberAccessStrategy = UnsafeMemberAccessStrategy.Instance }; var context = new TemplateContext(options); context.SetValue("products", new[] { new { title = "Draft 151cm" }, new { title = "Element 155cm" } }); _parser.TryParse("{% include 'product' with products[0] %}", out var template); var result = template.Render(context); Assert.Equal("Product: Draft 151cm ", result); }
public async Task ShouldPreserveSpace() { var source = @"# With whitespace control {% assign name = 'John G. Chalmers-Smith' %} {% if name and name.size > 10 %} Wow, {{ name }}, you have a long name! {% else %} Hello there! {% endif %}"; var expected = @"# With whitespace control Wow, John G. Chalmers-Smith, you have a long name! "; _parser.TryParse(source, out var template); var result = await template.RenderAsync(); Assert.Equal(expected, result); }