public async Task <string> RenderAsync(string template, TemplateVars variables) { Guard.NotNull(variables, nameof(variables)); if (SquidexTemplate.TryParse(template, out var parsed, out var errors)) { var context = new TemplateContext(); foreach (var extension in extensions) { extension.BeforeRun(context); } foreach (var(key, value) in variables) { context.MemberAccessStrategy.Register(value.GetType()); context.SetValue(key, value); } var result = await parsed.RenderAsync(context); return(result); } throw new TemplateParseException(template, errors); }
public async Task Should_resolve_text_from_event(string encoding) { var @event = new EnrichedAssetEvent { Id = DomainId.NewGuid(), FileVersion = 0, FileSize = 100, AppId = appId }; SetupText(@event.ToRef(), Encode(encoding, "hello+assets")); var vars = new TemplateVars { ["event"] = @event }; var template = $@" Text: {{{{ event | assetText: '{encoding}' }}}} "; var expected = $@" Text: hello+assets "; var result = await sut.RenderAsync(template, vars); Assert.Equal(Cleanup(expected), Cleanup(result)); }
public async Task Should_resolve_asset_text_from_event() { var @event = new EnrichedAssetEvent { Id = DomainId.NewGuid(), FileVersion = 0, FileSize = 100, AppId = appId }; SetupText(@event.Id, Encoding.UTF8.GetBytes("Hello Asset")); var vars = new TemplateVars { ["event"] = @event }; var template = @" Text: {{ event | assetText }} "; var expected = $@" Text: Hello Asset "; var result = await sut.RenderAsync(template, vars); Assert.Equal(Cleanup(expected), Cleanup(result)); }
public async Task Should_resolve_blur_hash_from_event() { var @event = new EnrichedAssetEvent { Id = DomainId.NewGuid(), AssetType = AssetType.Image, FileVersion = 0, FileSize = 100, AppId = appId }; SetupBlurHash(@event.ToRef(), "Hash"); var vars = new TemplateVars { ["event"] = @event }; var template = @" Text: {{ event | assetBlurHash }} "; var expected = $@" Text: Hash "; var result = await sut.RenderAsync(template, vars); Assert.Equal(Cleanup(expected), Cleanup(result)); }
public async Task Should_not_resolve_asset_text_from_event_if_too_big() { var @event = new EnrichedAssetEvent { Id = DomainId.NewGuid(), FileVersion = 0, FileSize = 1_000_000, AppId = appId }; var vars = new TemplateVars { ["event"] = @event }; var template = @" Text: {{ event | assetText }} "; var expected = $@" Text: ErrorTooBig "; var result = await sut.RenderAsync(template, vars); Assert.Equal(Cleanup(expected), Cleanup(result)); A.CallTo(() => assetFileStore.DownloadAsync(A <DomainId> ._, A <DomainId> ._, A <long> ._, null, A <Stream> ._, A <BytesRange> ._, A <CancellationToken> ._)) .MustNotHaveHappened(); }
private (TemplateVars, IAssetEntity) SetupAssetVars(int fileSize = 100) { var assetId = DomainId.NewGuid(); var asset = CreateAsset(assetId, 1, fileSize); var @event = new EnrichedContentEvent { Data = new ContentData() .AddField("assets", new ContentFieldData() .AddInvariant(JsonValue.Array(assetId))), AppId = appId }; A.CallTo(() => assetQuery.FindAsync(A <Context> ._, assetId, EtagVersion.Any, A <CancellationToken> ._)) .Returns(asset); SetupText(@event.Id, Encoding.UTF8.GetBytes("Hello Asset")); var vars = new TemplateVars { ["event"] = @event }; return(vars, asset); }
private (TemplateVars, IAssetEntity[]) SetupAssetsVars(int fileSize = 100) { var assetId1 = DomainId.NewGuid(); var asset1 = CreateAsset(assetId1, 1, fileSize); var assetId2 = DomainId.NewGuid(); var asset2 = CreateAsset(assetId2, 2, fileSize); var @event = new EnrichedContentEvent { Data = new ContentData() .AddField("assets", new ContentFieldData() .AddInvariant(JsonValue.Array(assetId1, assetId2))), AppId = appId }; A.CallTo(() => assetQuery.FindAsync(A <Context> ._, assetId1, EtagVersion.Any, A <CancellationToken> ._)) .Returns(asset1); A.CallTo(() => assetQuery.FindAsync(A <Context> ._, assetId2, EtagVersion.Any, A <CancellationToken> ._)) .Returns(asset2); var vars = new TemplateVars { ["event"] = @event }; return(vars, new[] { asset1, asset2 }); }
public void AddTemplateVar(string name, object data) { if (TemplateVars == null) { TemplateVars = new List <TemplateVar>(); } TemplateVars.Add(new TemplateVar() { Name = name, Data = data }); }
public TableScaffolder( TemplateVars templateVars, ITemplateProvider templateProvider, IFilePersister filePersister, ProjectItem projectItem, ILogger logger) { this.templateVars = templateVars; this.templateProvider = templateProvider; this.filePersister = filePersister; this.projectItem = projectItem; this.logger = logger; }
public async ValueTask <string?> FormatAsync(string text, EnrichedEvent @event) { if (string.IsNullOrWhiteSpace(text)) { return(text); } if (TryGetTemplate(text.Trim(), out var template)) { var vars = new TemplateVars { ["event"] = @event }; return(await templateEngine.RenderAsync(template, vars)); } if (TryGetScript(text.Trim(), out var script)) { // Script vars are just wrappers over dictionaries for better performance. var vars = new EventScriptVars { Event = @event, AppId = @event.AppId.Id, AppName = @event.AppId.Name, User = Admin() }; var result = (await scriptEngine.ExecuteAsync(vars, script)).ToString(); if (result == "undefined") { return(GlobalFallback); } return(result); } var parts = BuildParts(text, @event); if (parts.Any(x => !x.Var.IsCompleted)) { await ValueTaskEx.WhenAll(parts.Select(x => x.Var)); } return(CombineParts(text, parts)); }
public override void AcceptContent(RCToken token) { TemplateVars template = _templates.Peek(); int firstNewline = token.Text.IndexOfAny(CRLF); if (firstNewline > -1) { template._multilineTemplate = true; } // I want it to be AS IF we saw something like {:"foo bar with newlines"} // AcceptEvaluator (new RCToken (":", RCTokenType.Evaluator, token.Start, // token.Index)); // soo... _variable = ""; _evaluator = RCEvaluator.Let; _result = new RCString(token.Text); }
public async ValueTask <string?> FormatAsync(string text, EnrichedEvent @event) { if (string.IsNullOrWhiteSpace(text)) { return(text); } if (TryGetTemplate(text.Trim(), out var template)) { var vars = new TemplateVars { ["event"] = @event }; return(await templateEngine.RenderAsync(template, vars)); } if (TryGetScript(text.Trim(), out var script)) { var vars = new ScriptVars { ["event"] = @event }; #pragma warning disable MA0042 // Do not use blocking calls in an async method var result = scriptEngine.Execute(vars, script).ToString(); #pragma warning restore MA0042 // Do not use blocking calls in an async method if (result == "undefined") { return(GlobalFallback); } return(result); } var parts = BuildParts(text, @event); if (parts.Any(x => !x.Var.IsCompleted)) { await ValueTaskEx.WhenAll(parts.Select(x => x.Var)); } return(CombineParts(text, parts)); }
public async Task Should_resolve_references_in_loop() { var referenceId1 = DomainId.NewGuid(); var reference1 = CreateReference(referenceId1, 1); var referenceId2 = DomainId.NewGuid(); var reference2 = CreateReference(referenceId1, 2); var @event = new EnrichedContentEvent { Data = new NamedContentData() .AddField("references", new ContentFieldData() .AddJsonValue(JsonValue.Array(referenceId1, referenceId2))), AppId = appId }; A.CallTo(() => contentQuery.QueryAsync(A <Context> ._, A <IReadOnlyList <DomainId> > .That.Contains(referenceId1))) .Returns(ResultList.CreateFrom(1, reference1)); A.CallTo(() => contentQuery.QueryAsync(A <Context> ._, A <IReadOnlyList <DomainId> > .That.Contains(referenceId2))) .Returns(ResultList.CreateFrom(1, reference2)); var vars = new TemplateVars { ["event"] = @event }; var template = @" {% for id in event.data.references.iv %} {% reference 'ref', id %} Text: {{ ref.data.field1.iv }} {{ ref.data.field2.iv }} {% endfor %} "; var expected = @" Text: Hello 1 World 1 Text: Hello 2 World 2 "; var result = await sut.RenderAsync(template, vars); Assert.Equal(expected, result); }
public async Task Should_resolve_assets_in_loop() { var assetId1 = DomainId.NewGuid(); var asset1 = CreateAsset(assetId1, 1); var assetId2 = DomainId.NewGuid(); var asset2 = CreateAsset(assetId2, 2); var @event = new EnrichedContentEvent { Data = new ContentData() .AddField("assets", new ContentFieldData() .AddInvariant(JsonValue.Array(assetId1, assetId2))), AppId = appId }; A.CallTo(() => assetQuery.FindAsync(A <Context> ._, assetId1, EtagVersion.Any, A <CancellationToken> ._)) .Returns(asset1); A.CallTo(() => assetQuery.FindAsync(A <Context> ._, assetId2, EtagVersion.Any, A <CancellationToken> ._)) .Returns(asset2); var vars = new TemplateVars { ["event"] = @event }; var template = @" {% for id in event.data.assets.iv %} {% asset 'ref', id %} Text: {{ ref.fileName }} {{ ref.id }} {% endfor %} "; var expected = $@" Text: file1.jpg {assetId1} Text: file2.jpg {assetId2} "; var result = await sut.RenderAsync(template, vars); Assert.Equal(Cleanup(expected), Cleanup(result)); }
public async Task Should_resolve_references_in_loop_with_filter() { var referenceId1 = DomainId.NewGuid(); var reference1 = CreateReference(referenceId1, 1); var referenceId2 = DomainId.NewGuid(); var reference2 = CreateReference(referenceId2, 2); var @event = new EnrichedContentEvent { Data = new ContentData() .AddField("references", new ContentFieldData() .AddInvariant(JsonValue.Array(referenceId1, referenceId2))), AppId = appId }; A.CallTo(() => contentQuery.QueryAsync(A <Context> ._, A <Q> .That.HasIds(referenceId1), A <CancellationToken> ._)) .Returns(ResultList.CreateFrom(1, reference1)); A.CallTo(() => contentQuery.QueryAsync(A <Context> ._, A <Q> .That.HasIds(referenceId2), A <CancellationToken> ._)) .Returns(ResultList.CreateFrom(1, reference2)); var vars = new TemplateVars { ["event"] = @event }; var template = @" {% for id in event.data.references.iv %} {% assign ref = id | reference %} Text: {{ ref.data.field1.iv }} {{ ref.data.field2.iv }} {{ ref.id }} {% endfor %} "; var expected = $@" Text: Hello 1 World 1 {referenceId1} Text: Hello 2 World 2 {referenceId2} "; var result = await sut.RenderAsync(template, vars); Assert.Equal(Cleanup(expected), Cleanup(result)); }
private void StartScaffoldingAsync(Object sender, EventArgs e) { var logger = new RichTextBoxLogger(log, sender as BackgroundWorker); var templateVars = new TemplateVars(TableName, TableColumns, ProjectItem.Name); var templateProvider = GetTemplateProvider(); var codeCommentator = new CodeCommentator(); var vsProjectPersister = new VsProjectFilePersister(ProjectItem, codeCommentator, logger); TableDesignerVisible = false; ScaffoldingLogVisible = true; var scaffolder = new TableScaffolder( templateVars, templateProvider, vsProjectPersister, ProjectItem, logger); scaffolder.Scaffold(); }
public Template Compile(TemplateVars templateVars, ILogger logger) { try { // Override default delimiters, these will not require as // much escaping in C# code as default delimiters var template = new Template(Template, '$', '$'); foreach (var templateVar in templateVars) { template.Add(templateVar.Key, templateVar.Value); } // Register string renderer so that we can user "Upper" modifier in templates template.Group.RegisterRenderer(typeof(string), new StringRenderer()); return template; } catch (Exception e) { // Ups, something is worng with the template logger.Error(string.Format("Invalid template {0}. {1}", FileName, e.Message)); return null; } }
public async ValueTask <string?> FormatAsync(string text, EnrichedEvent @event) { if (string.IsNullOrWhiteSpace(text)) { return(text); } if (TryGetTemplate(text.Trim(), out var template)) { var vars = new TemplateVars { ["event"] = @event }; return(await templateEngine.RenderAsync(template, vars)); } if (TryGetScript(text.Trim(), out var script)) { var vars = new ScriptVars { ["event"] = @event }; return(scriptEngine.Interpolate(vars, script)); } var parts = BuildParts(text, @event); if (parts.Any(x => !x.Var.IsCompleted)) { await ValueTaskEx.WhenAll(parts.Select(x => x.Var)); } return(CombineParts(text, parts)); }
/// <summary> /// Generates full path to the destination file and replaces all /// placeholders with a corresponding template variable /// </summary> public string CompileFullPath(TemplateVars templateVars, string basePath) { var fullPath = Path.Combine(basePath, RelativePath, FileName); foreach (var templateVar in templateVars) { var key = string.Format("_{0}_", templateVar.Key); fullPath = fullPath.Replace(key, templateVar.Value.ToString()); } return fullPath; }
public SharpTLDefaultTemplate(TemplateVars templateVars) { _templateVars = templateVars; }
public SchemaMethodsImplTemplate(TemplateVars templateVars) { _templateVars = templateVars; }
protected void FinishTemplate(int escapeCount) { RCString section; TemplateVars template = _templates.Peek(); if (template._multilineTemplate) { for (int i = 0; i < _block.Count; ++i) { RCBlock current = _block.GetName(i); section = current.Value as RCString; if (section != null && i % 2 == 0) { string content = section[0]; int spaces = 0; bool broken = false; bool hasLine = false; int firstNewline = content.IndexOf('\n'); if (firstNewline > -1) { hasLine = true; } for (int j = firstNewline + 1; j < content.Length; ++j) { if (content[j] == ' ') { if (!broken) { ++spaces; } } else if (content[j] == '\n') { if (j > 0) { template._minSpaces = Math.Min(template._minSpaces, spaces); } spaces = 0; broken = false; hasLine = true; } else { broken = true; } } if (content.Length > 0 && content[content.Length - 1] != '\n' && hasLine && i < _block.Count - 1) { template._minSpaces = Math.Min(template._minSpaces, spaces); } if (template._minSpaces == int.MaxValue) { template._minSpaces = 0; } } } RCBlock final = RCBlock.Empty; // strip indentation (spaces only) from the lines in the content. // Ignore the first and last sections. for (int i = 0; i < _block.Count; ++i) { RCBlock current = _block.GetName(i); section = current.Value as RCString; if (section != null && i % 2 == 0) { string content = section[0]; StringBuilder builder = new StringBuilder(); int start = 0, end = 0; // Skip past the initial newline in the first section. if (i == 0) { while (content[start] != '\n') { ++start; } ++start; } else { while (end < content.Length) { if (content[end] == '\n') { ++end; break; } ++end; } if (end < content.Length && end > 1 && content[end - 2] == '\r') { builder.Append(content.Substring(start, (end - 2) - start)); builder.Append("\n"); } else { builder.Append(content.Substring(start, end - start)); } start = end; } end = start; GETLINE: start = end + template._minSpaces; while (end < content.Length) { if (content[end] == '\n') { ++end; break; } ++end; } // The problem is when the first character is a newline this gets f****d up. if (start < content.Length && end <= content.Length) { // string trimmed; if (end < start) { builder.Append(content.Substring(0, end)); } else { if (content.Length > 1 && content[end - 2] == '\r') { builder.Append(content.Substring(start, (end - 2) - start)); builder.Append("\n"); } else { builder.Append(content.Substring(start, end - start)); } } // builder.Append (trimmed); goto GETLINE; } else { final = new RCBlock(final, current.Name, current.Evaluator, new RCString(builder.ToString())); } } else { final = new RCBlock(final, current.Name, current.Evaluator, current.Value); } } _result = new RCTemplate(final, escapeCount, true); } else { _result = new RCTemplate(_block, escapeCount, false); } // The template must either be all on one line, // or the first and last lines with the [? and ?] tokens // must be free of any other content. // So this loop needs to find out whether there are any newlines. // If there are then we also need to find out where the // first non-white character is. // Reset state for the possible next template. // _multilineTemplate = false; // _parsingContent = false; // _minSpaces = 0; }