public BindingContext(object value, EncodedTextWriter writer, BindingContext parent, string templatePath) { TemplatePath = parent != null ? (parent.TemplatePath ?? templatePath) : templatePath; TextWriter = writer; _value = value; _parent = parent; }
public BindingContext(object value, EncodedTextWriter writer, BindingContext parent, string templatePath ) { TemplatePath = parent != null ? (parent.TemplatePath ?? templatePath) : templatePath; TextWriter = writer; _value = value; _parent = parent; }
public void Write(object value) { var stringWriter = new StringWriter(); var formatterProvider = Substitute.For <IFormatterProvider>(); formatterProvider.TryCreateFormatter(Arg.Any <Type>(), out Arg.Any <IFormatter>()) .Returns(o => { new DefaultFormatterProvider().TryCreateFormatter(o[0] as Type, out var formatter); o[1] = formatter; return(true); }); formatterProvider.TryCreateFormatter(typeof(UndefinedBindingResult), out Arg.Any <IFormatter>()) .Returns(o => { o[1] = new UndefinedFormatter("{0}"); return(true); }); using var writer = new EncodedTextWriter(stringWriter, null, formatterProvider); writer.Write(value); Assert.Equal(value.ToString(), stringWriter.ToString()); }
public BindingContext(object value, EncodedTextWriter writer, BindingContext parent, string templatePath, BindingContext current) { TemplatePath = parent != null ? (parent.TemplatePath ?? templatePath) : templatePath; TextWriter = writer; _value = value; _parent = parent; //Inline partials cannot use the Handlebars.RegisteredTemplate method //because it pollutes the static dictionary and creates collisions //where the same partial name might exist in multiple templates. //To avoid collisions, pass around a dictionary of compiled partials //in the context if (parent != null) { InlinePartialTemplates = parent.InlinePartialTemplates; } else if (current != null) { InlinePartialTemplates = current.InlinePartialTemplates; } else { InlinePartialTemplates = new Dictionary <string, Action <TextWriter, object> >(StringComparer.OrdinalIgnoreCase); } }
public static BindingContext Create(InternalHandlebarsConfiguration configuration, object value, EncodedTextWriter writer, BindingContext parent, string templatePath, Action <TextWriter, object> partialBlockTemplate, IDictionary <string, Action <TextWriter, object> > inlinePartialTemplates) { return(Pool.CreateContext(configuration, value, writer, parent, templatePath, partialBlockTemplate, inlinePartialTemplates)); }
void isType(EncodedTextWriter writer, BlockHelperOptions options, Context context, Arguments arguments) { Type[] expectedType; var strType = (string)arguments[1]; switch (strType) { case "IEnumerable<string>": expectedType = new[] { typeof(IEnumerable <string>) }; break; case "IEnumerable<KeyValuePair<string, string>>": expectedType = new[] { typeof(IEnumerable <KeyValuePair <string, string> >) }; break; default: throw new ArgumentException("Invalid type: " + strType); } var t = arguments[0]?.GetType(); if (expectedType.Any(x => x.IsAssignableFrom(t))) { options.Template(writer, context); } else { options.Inverse(writer, context); } }
public BindingContext(object value, EncodedTextWriter writer, BindingContext parent, string templateName) { TextWriter = writer; Value = value; ParentContext = parent; TemplateName = templateName; }
public static void Iterate( BindingContext context, EncodedTextWriter writer, ChainSegment[] blockParamsVariables, object target, TemplateDelegate template, TemplateDelegate ifEmpty) { if (!HandlebarsUtils.IsTruthy(target)) { using var frame = context.CreateFrame(context.Value); ifEmpty(writer, frame); return; } if (!ObjectDescriptor.TryCreate(target, out var descriptor)) { throw new HandlebarsRuntimeException($"Cannot create ObjectDescriptor for type {descriptor.DescribedType}"); } if (descriptor.Iterator == null) { throw new HandlebarsRuntimeException($"Type {descriptor.DescribedType} does not support iteration"); } descriptor.Iterator.Iterate(writer, context, blockParamsVariables, target, template, ifEmpty); }
internal static TemplateDelegate CompileView(ViewReaderFactory readerFactoryFactory, string templatePath, CompilationContext compilationContext) { var configuration = compilationContext.Configuration; IEnumerable <object> tokens; using (var sr = readerFactoryFactory(configuration, templatePath)) { using (var reader = new ExtendedStringReader(sr)) { tokens = Tokenizer.Tokenize(reader).ToArray(); } } var layoutToken = tokens.OfType <LayoutToken>().SingleOrDefault(); var expressions = ExpressionBuilder.ConvertTokensToExpressions(tokens, configuration); var compiledView = FunctionBuilder.Compile(expressions, compilationContext); if (layoutToken == null) { return(compiledView); } var fs = configuration.FileSystem; var layoutPath = fs.Closest(templatePath, layoutToken.Value + ".hbs"); if (layoutPath == null) { throw new InvalidOperationException($"Cannot find layout '{layoutToken.Value}' for template '{templatePath}'"); } var compiledLayout = CompileView(readerFactoryFactory, layoutPath, new CompilationContext(compilationContext)); return((in EncodedTextWriter writer, BindingContext context) => { var config = context.Configuration; using var bindingContext = BindingContext.Create(config, null); foreach (var pair in context.ContextDataObject) { switch (pair.Key.WellKnownVariable) { case WellKnownVariable.Parent: case WellKnownVariable.Root: continue; } bindingContext.ContextDataObject[pair.Key] = pair.Value; } using var innerWriter = ReusableStringWriter.Get(config.FormatProvider); using var textWriter = new EncodedTextWriter(innerWriter, config.TextEncoder, FormatterProvider.Current, true); compiledView(textWriter, context); var inner = innerWriter.ToString(); var viewModel = new LayoutViewModel(inner, context.Value); bindingContext.Value = viewModel; compiledLayout(writer, bindingContext); });
private static void IterateObjectWithStaticProperties( BindingContext context, EncodedTextWriter writer, ChainSegment[] blockParamsVariables, ObjectDescriptor descriptor, object target, IList <ChainSegment> properties, Type targetType, TemplateDelegate template, TemplateDelegate ifEmpty) { using var innerContext = context.CreateFrame(); var iterator = new ObjectIteratorValues(innerContext); var blockParams = new BlockParamsValues(innerContext, blockParamsVariables); blockParams.CreateProperty(0, out var _0); blockParams.CreateProperty(1, out var _1); var count = properties.Count; var accessor = new MemberAccessor(target, descriptor); var iterationIndex = 0; var lastIndex = count - 1; object iteratorValue; ChainSegment iteratorKey; for (; iterationIndex < count; iterationIndex++) { iteratorKey = properties[iterationIndex]; iterator.Index = iterationIndex; iterator.Key = iteratorKey; if (iterationIndex == 1) { iterator.First = BoxedValues.False; } if (iterationIndex == lastIndex) { iterator.Last = BoxedValues.True; } iteratorValue = accessor[iteratorKey]; iterator.Value = iteratorValue; innerContext.Value = iteratorValue; blockParams[_0] = iteratorValue; blockParams[_1] = iteratorKey; template(writer, innerContext); } if (iterationIndex == 0) { innerContext.Value = context.Value; ifEmpty(writer, innerContext); } }
public static Expression <Action <BindingContext, TextWriter, object> > Bind(CompilationContext context, Expression body, string templatePath) { var configuration = Arg(context.Configuration); var writerParameter = Parameter <TextWriter>("buffer"); var objectParameter = Parameter <object>("data"); var bindingContext = Arg <BindingContext>(context.BindingContext); var textEncoder = configuration.Property(o => o.TextEncoder); var writer = Var <EncodedTextWriter>("writer"); var encodedWriterExpression = Call(() => EncodedTextWriter.From(writerParameter, (ITextEncoder)textEncoder)); var parentContextArg = Var <BindingContext>("parentContext"); var newBindingContext = Call( () => BindingContext.Create((ICompiledHandlebarsConfiguration)configuration, objectParameter, writer, parentContextArg, templatePath) ); Expression blockBuilder = Block() .Parameter(bindingContext) .Parameter(writer) .Parameter <bool>(out var shouldDispose) .Parameter <bool>(out var shouldDisposeWriter) .Line(bindingContext.Assign(objectParameter.As <BindingContext>())) .Line(Condition() .If(Expression.Equal(bindingContext, Null <BindingContext>())) .Then(block => { block.Line(shouldDispose.Assign(true)) .Line(writer.Assign(writerParameter.As <EncodedTextWriter>())) .Line(Condition() .If(Expression.Equal(writer, Null <EncodedTextWriter>())) .Then(b => { b.Line(shouldDisposeWriter.Assign(true)) .Line(writer.Assign(encodedWriterExpression)); }) ); block.Line(bindingContext.Assign(newBindingContext)); }) ) .Line(Try() .Body(block => block.Lines(((BlockExpression)body).Expressions)) .Finally(block => { block.Lines( Condition() .If(shouldDispose) .Then(bindingContext.Call(o => o.Dispose())), Condition() .If(shouldDisposeWriter) .Then(writer.Call(o => o.Dispose())) ); }) ); return(Expression.Lambda <Action <BindingContext, TextWriter, object> >(blockBuilder, (ParameterExpression)parentContextArg.Expression, (ParameterExpression)writerParameter.Expression, (ParameterExpression)objectParameter.Expression)); }
private static void IterateObject( BindingContext context, EncodedTextWriter writer, ObjectDescriptor descriptor, ChainSegment[] blockParamsVariables, object target, IEnumerable properties, Type targetType, TemplateDelegate template, TemplateDelegate ifEmpty) { using var innerContext = context.CreateFrame(); var iterator = new ObjectIteratorValues(innerContext); var blockParams = new BlockParamsValues(innerContext, blockParamsVariables); blockParams.CreateProperty(0, out var _0); blockParams.CreateProperty(1, out var _1); var accessor = new MemberAccessor(target, descriptor); var enumerable = new ExtendedEnumerator <object>(properties.GetEnumerator()); var enumerated = false; object iteratorValue; ChainSegment iteratorKey; while (enumerable.MoveNext()) { enumerated = true; var enumerableValue = enumerable.Current; iteratorKey = ChainSegment.Create(enumerableValue.Value); iterator.Key = iteratorKey; iterator.Index = enumerableValue.Index; if (enumerableValue.Index == 1) { iterator.First = BoxedValues.False; } if (enumerableValue.IsLast) { iterator.Last = BoxedValues.True; } iteratorValue = accessor[iteratorKey]; iterator.Value = iteratorValue; innerContext.Value = iteratorValue; blockParams[_0] = iteratorValue; blockParams[_1] = iteratorKey; template(writer, innerContext); } if (!enumerated) { innerContext.Value = context.Value; ifEmpty(writer, innerContext); } }
void ToBase64(EncodedTextWriter output, Context context, Arguments arguments) { var bytes = (byte[])arguments[0]; if (bytes != null) { output.Write(Convert.ToBase64String(bytes)); } }
void footer(EncodedTextWriter writer, BlockHelperOptions options, Context context, Arguments arguments) { IDictionary <string, object> viewBag = context["ViewBag"] as IDictionary <string, object>; if (viewBag.TryGetValue("ShowFooter", out var show) && (bool)show == true) { options.Template(writer, (object)context); } }
private BindingContext(InternalHandlebarsConfiguration configuration, object value, EncodedTextWriter writer, BindingContext parent) { Configuration = configuration; TextWriter = writer; Value = value; ParentContext = parent; RegisterValueProvider(new BindingContextValueProvider(this)); }
void ViewBag(EncodedTextWriter output, Context context, Arguments arguments) { var dict = (IDictionary <string, object>)arguments[0]; var viewBag = (IDictionary <string, object>)context["ViewBag"]; foreach (var pair in dict) { viewBag[pair.Key] = pair.Value; } }
public static void PlainHelper( BindingContext context, EncodedTextWriter writer, object value, TemplateDelegate body, TemplateDelegate inverse ) { RenderSection(value, context, writer, body, inverse); }
public void Write(object value) { var stringWriter = new StringWriter(); using var writer = new EncodedTextWriter(stringWriter, null, new Formatter <UndefinedBindingResult>(undefined => undefined.ToString())); writer.Write(value); Assert.Equal(value.ToString(), stringWriter.ToString()); }
private static void IterateList( BindingContext context, EncodedTextWriter writer, ChainSegment[] blockParamsVariables, IList target, TemplateDelegate template, TemplateDelegate ifEmpty) { using var innerContext = context.CreateFrame(); var iterator = new IteratorValues(innerContext); var blockParams = new BlockParamsValues(innerContext, blockParamsVariables); blockParams.CreateProperty(0, out var _0); blockParams.CreateProperty(1, out var _1); var count = target.Count; object boxedIndex; object iteratorValue; var iterationIndex = 0; var lastIndex = count - 1; for (; iterationIndex < count; iterationIndex++) { iteratorValue = target[iterationIndex]; iterator.Value = iteratorValue; if (iterationIndex == 1) { iterator.First = BoxedValues.False; } if (iterationIndex == lastIndex) { iterator.Last = BoxedValues.True; } boxedIndex = iterationIndex; iterator.Index = boxedIndex; blockParams[_0] = iteratorValue; blockParams[_1] = boxedIndex; innerContext.Value = iteratorValue; template(writer, innerContext); } if (iterationIndex == 0) { innerContext.Value = context.Value; ifEmpty(writer, innerContext); } }
public BindingContext(object value, EncodedTextWriter writer, BindingContext parent, string templatePath, Action <TextWriter, object> partialBlockTemplate, BindingContext current, IDictionary <string, Action <TextWriter, object> > inlinePartialTemplates) { TemplatePath = parent != null ? (parent.TemplatePath ?? templatePath) : templatePath; TextWriter = writer; _value = value; _parent = parent; _Root = new Lazy <object>(() => { var currentContext = this; while (currentContext.ParentContext != null) { currentContext = currentContext.ParentContext; } return(currentContext.Value); } ); //Inline partials cannot use the Handlebars.RegisteredTemplate method //because it pollutes the static dictionary and creates collisions //where the same partial name might exist in multiple templates. //To avoid collisions, pass around a dictionary of compiled partials //in the context if (parent != null) { InlinePartialTemplates = parent.InlinePartialTemplates; if (value is HashParameterDictionary dictionary) { // Populate value with parent context foreach (var item in GetContextDictionary(parent.Value)) { if (!dictionary.ContainsKey(item.Key)) { dictionary[item.Key] = item.Value; } } } } else if (current != null) { InlinePartialTemplates = current.InlinePartialTemplates; } else if (inlinePartialTemplates != null) { InlinePartialTemplates = inlinePartialTemplates; } else { InlinePartialTemplates = new Dictionary <string, Action <TextWriter, object> >(StringComparer.OrdinalIgnoreCase); } PartialBlockTemplate = partialBlockTemplate; }
private static void IterateEnumerable( BindingContext context, EncodedTextWriter writer, ChainSegment[] blockParamsVariables, IEnumerable target, TemplateDelegate template, TemplateDelegate ifEmpty) { using var innerContext = context.CreateFrame(); var iterator = new IteratorValues(innerContext); var blockParams = new BlockParamsValues(innerContext, blockParamsVariables); blockParams.CreateProperty(0, out var _0); blockParams.CreateProperty(1, out var _1); var enumerator = new ExtendedEnumerator <object>(target.GetEnumerator()); var enumerated = false; object boxedIndex; object iteratorValue; while (enumerator.MoveNext()) { enumerated = true; var enumerableValue = enumerator.Current; if (enumerableValue.Index == 1) { iterator.First = BoxedValues.False; } if (enumerableValue.IsLast) { iterator.Last = BoxedValues.True; } boxedIndex = enumerableValue.Index; iteratorValue = enumerableValue.Value; iterator.Value = iteratorValue; iterator.Index = boxedIndex; blockParams[_0] = iteratorValue; blockParams[_1] = boxedIndex; innerContext.Value = iteratorValue; template(writer, innerContext); } if (!enumerated) { innerContext.Value = context.Value; ifEmpty(writer, innerContext); } }
void ActionUrl(EncodedTextWriter output, Context context, Arguments arguments) { if (arguments.Length < 1 || arguments.Length > 3) { throw new ArgumentOutOfRangeException(nameof(arguments)); } IDictionary <string, object> routeValues = null; string controller = null; string action = (arguments[0] as Page)?.ActionName ?? (string)arguments[0]; if (arguments.Length >= 2) // [actionName, controllerName/routeValues ] { if (arguments[1] is IDictionary <string, object> r) { routeValues = r; } else if (arguments[1] is string s) { controller = s; } else if (arguments[1] is Page v) { controller = v.ControllerName; } else { throw new Exception("ActionUrl: Invalid parameter 1"); } } if (arguments.Length == 3) // [actionName, controllerName, routeValues] { routeValues = (IDictionary <string, object>)arguments[2]; } if (controller == null) { controller = context["ControllerName"] as string; } string url = BaseUrl + controller; if (!string.IsNullOrEmpty(action)) { url += "/" + action; } output.WriteSafeString(AddQueryString(url, routeValues)); }
void eachPair(EncodedTextWriter writer, BlockHelperOptions options, Context context, Arguments arguments) { void OutputElements <T>() { if (arguments[0] is IEnumerable <T> pairs) { foreach (var item in pairs) { options.Template(writer, item); } } } OutputElements <KeyValuePair <string, string> >(); OutputElements <KeyValuePair <string, object> >(); }
private static bool InvokePartial( string partialName, BindingContext context, EncodedTextWriter writer, ICompiledHandlebarsConfiguration configuration) { if (partialName.Equals(SpecialPartialBlockName)) { if (context.PartialBlockTemplate == null) { return false; } context.PartialBlockTemplate(writer, context.ParentContext); return true; } //if we have an inline partial, skip the file system and RegisteredTemplates collection if (context.InlinePartialTemplates.TryGetValue(partialName, out var partial)) { partial(writer, context); return true; } // Partial is not found, so call the resolver and attempt to load it. if (!configuration.RegisteredTemplates.ContainsKey(partialName)) { var handlebars = Handlebars.Create(configuration); if (configuration.PartialTemplateResolver == null || !configuration.PartialTemplateResolver.TryRegisterPartial(handlebars, partialName, (string) context.Extensions.Optional("templatePath"))) { // Template not found. return false; } } try { using var textWriter = writer.CreateWrapper(); configuration.RegisteredTemplates[partialName](textWriter, context); return true; } catch (Exception exception) { throw new HandlebarsRuntimeException($"Runtime error while rendering partial '{partialName}', see inner exception for more information", exception); } }
internal static TemplateDelegate CompileView(ViewReaderFactory readerFactoryFactory, string templatePath, CompilationContext compilationContext) { var configuration = compilationContext.Configuration; IEnumerable <object> tokens; using (var sr = readerFactoryFactory(configuration, templatePath)) { using (var reader = new ExtendedStringReader(sr)) { tokens = Tokenizer.Tokenize(reader).ToArray(); } } var layoutToken = tokens.OfType <LayoutToken>().SingleOrDefault(); var expressions = ExpressionBuilder.ConvertTokensToExpressions(tokens, configuration); var compiledView = FunctionBuilder.Compile(expressions, compilationContext); if (layoutToken == null) { return(compiledView); } var fs = configuration.FileSystem; var layoutPath = fs.Closest(templatePath, layoutToken.Value + ".hbs"); if (layoutPath == null) { throw new InvalidOperationException($"Cannot find layout '{layoutToken.Value}' for template '{templatePath}'"); } var compiledLayout = CompileView(readerFactoryFactory, layoutPath, new CompilationContext(compilationContext)); return((in EncodedTextWriter writer, BindingContext context) => { var config = context.Configuration; using var innerWriter = ReusableStringWriter.Get(config.FormatProvider); using var textWriter = new EncodedTextWriter(innerWriter, config.TextEncoder, config.UnresolvedBindingFormatter, true); compiledView(textWriter, context); var inner = innerWriter.ToString(); var vmContext = new [] { new { body = inner }, context.Value }; var viewModel = new DynamicViewModel(vmContext); using var bindingContext = BindingContext.Create(config, viewModel); compiledLayout(writer, bindingContext); });
public static void Iterate( BindingContext context, EncodedTextWriter writer, ChainSegment[] blockParamsVariables, object target, TemplateDelegate template, TemplateDelegate ifEmpty) { if (!HandlebarsUtils.IsTruthy(target)) { using var frame = context.CreateFrame(context.Value); ifEmpty(writer, frame); return; } var targetType = target.GetType(); if (!context.Configuration.ObjectDescriptorProvider.TryGetDescriptor(targetType, out var descriptor)) { using var frame = context.CreateFrame(context.Value); ifEmpty(writer, frame); return; } if (!descriptor.ShouldEnumerate) { var properties = descriptor.GetProperties(descriptor, target); if (properties is IList <ChainSegment> propertiesList) { IterateObjectWithStaticProperties(context, writer, blockParamsVariables, descriptor, target, propertiesList, targetType, template, ifEmpty); return; } IterateObject(context, writer, descriptor, blockParamsVariables, target, properties, targetType, template, ifEmpty); return; } if (target is IList list) { IterateList(context, writer, blockParamsVariables, list, template, ifEmpty); return; } IterateEnumerable(context, writer, blockParamsVariables, (IEnumerable)target, template, ifEmpty); }
private static void InvokePartialWithFallback( string partialName, BindingContext context, EncodedTextWriter writer, ICompiledHandlebarsConfiguration configuration) { if (InvokePartial(partialName, context, writer, configuration)) return; if (context.PartialBlockTemplate == null) { if (configuration.MissingPartialTemplateHandler == null) throw new HandlebarsRuntimeException($"Referenced partial name {partialName} could not be resolved"); configuration.MissingPartialTemplateHandler.Handle(configuration, partialName, writer); return; } context.PartialBlockTemplate(writer, context); }
void Selected(EncodedTextWriter output, Context context, Arguments arguments) { string selected; if (arguments.Length >= 2) { selected = arguments[1]?.ToString(); } else { selected = context["selected"].ToString(); } if (((string)arguments[0]).Equals(selected, StringComparison.InvariantCultureIgnoreCase)) { output.Write("selected"); } }
public static Expression <Action <BindingContext, TextWriter, object> > Bind(CompilationContext context, Expression body, string templatePath) { var configuration = ExpressionShortcuts.Arg(context.Configuration); var writerParameter = ExpressionShortcuts.Parameter <TextWriter>("buffer"); var objectParameter = ExpressionShortcuts.Parameter <object>("data"); var bindingContext = ExpressionShortcuts.Arg <BindingContext>(context.BindingContext); var inlinePartialsParameter = ExpressionShortcuts.Null <IDictionary <string, Action <TextWriter, object> > >(); var textEncoder = configuration.Property(o => o.TextEncoder); var encodedWriterExpression = ExpressionShortcuts.Call(() => EncodedTextWriter.From(writerParameter, (ITextEncoder)textEncoder)); var parentContextArg = ExpressionShortcuts.Var <BindingContext>("parentContext"); var newBindingContext = ExpressionShortcuts.Call( () => BindingContext.Create(configuration, objectParameter, encodedWriterExpression, parentContextArg, templatePath, (IDictionary <string, Action <TextWriter, object> >)inlinePartialsParameter) ); var shouldDispose = ExpressionShortcuts.Var <bool>("shouldDispose"); Expression blockBuilder = ExpressionShortcuts.Block() .Parameter(bindingContext) .Parameter(shouldDispose) .Line(ExpressionShortcuts.Condition() .If(objectParameter.Is <BindingContext>(), bindingContext.Assign(objectParameter.As <BindingContext>()) ) .Else(block => { block.Line(shouldDispose.Assign(true)); block.Line(bindingContext.Assign(newBindingContext)); }) ) .Line(ExpressionShortcuts.Try() .Body(block => block.Lines(((BlockExpression)body).Expressions)) .Finally(ExpressionShortcuts.Condition() .If(shouldDispose, bindingContext.Call(o => o.Dispose())) ) ); return(Expression.Lambda <Action <BindingContext, TextWriter, object> >(blockBuilder, (ParameterExpression)parentContextArg.Expression, (ParameterExpression)writerParameter.Expression, (ParameterExpression)objectParameter.Expression)); }
void MenuItemActionLink(EncodedTextWriter output, Context context, Arguments arguments) { var dict = arguments[0] as IDictionary <string, object> ?? new Dictionary <string, object>() { ["controller"] = arguments[0] }; string classes = "item"; if (dict["controller"].Equals(context["ControllerName"])) { classes += " active"; } string url = BaseUrl + dict["controller"]; string title = dict.GetValue("title", dict["controller"]) as string; //string title = HtmlEncode(value); output.WriteSafeString($@"<a href=""{url}"" class=""{classes}"">{title}</a>"); }
private static void RenderSection(object value, BindingContext context, EncodedTextWriter writer, TemplateDelegate body, TemplateDelegate inversion) { switch (value) { case bool boolValue when boolValue: body(writer, context); return; case null: case object _ when HandlebarsUtils.IsFalsyOrEmpty(value): inversion(writer, context); return; case string _: { using var frame = context.CreateFrame(value); body(writer, frame); return; } case IEnumerable enumerable: Iterator.Iterate(context, writer, BlockParamsVariables, enumerable, body, inversion); break; default: { using var frame = context.CreateFrame(value); body(writer, frame); break; } } }