fluid icon indicating copy to clipboard operation
fluid copied to clipboard

How to convert ArgumentsTag

Open SebastianStehle opened this issue 1 year ago • 5 comments

Hi,

I am trying to convert the following arguments tag to v2:

https://github.com/Squidex/squidex/blob/master/backend/src/Squidex.Domain.Apps.Entities/Contents/ReferencesFluidExtension.cs#L27

I have had a look to Orchard (https://github.com/OrchardCMS/OrchardCore/blob/339d74b251b53393dd510f8ad3027aa17d78500d/src/OrchardCore/OrchardCore.DisplayManagement.Liquid/LiquidViewParser.cs) and after that I came up with something like:

parser.RegisterParserTag("reference", primary.And(primary),
            async (ValueTuple<Expression, Expression> arguments, TextWriter writer, TextEncoder encoder, TemplateContext context) =>
            {
                if (context.GetValue("event")?.ToObjectValue() is EnrichedEvent enrichedEvent)
                {
                    var contentId = await arguments.Item2.EvaluateAsync(context);
                    var content = await ResolveContentAsync(serviceProvider, enrichedEvent.AppId.Id, contentId);

                    if (content != null)
                    {
                        var name = (await arguments.Item1.EvaluateAsync(context)).ToStringValue();

                        context.SetValue(name, content);
                    }
                }

                return Fluid.Ast.Completion.Normal;
            });

The tag works like assign:

{% for id in event.data.references.iv %}
    {% reference 'ref' id %}
    Text: {{ ref.data.field1.iv }} {{ ref.data.field2.iv }} {{ ref.id }}
{% endfor %}

there is also a filter

{% for id in event.data.references.iv %}
    {% assign ref = id | reference %}
    Text: {{ ref.data.field1.iv }} {{ ref.data.field2.iv }} {{ ref.id }}
{% endfor %}

But in my tests I always get the following error from the parse method:

Object reference not set to an instance of an object.

SebastianStehle avatar Dec 07 '22 14:12 SebastianStehle

Okay, got it. It is basically the same problem like this: https://github.com/sebastienros/fluid/issues/307#issuecomment-818001822

I derived from FluidParser and exposed the parsers I needed:

public sealed class CustomFluidParser : FluidParser
{
    public Deferred<Expression> PrimaryParser => Primary;

    public Parser<char> CommaParser => Comma;
}

I guess I could just have used ArgumentsList, but I decided to use this syntax:

parser.PrimaryParser.And(ZeroOrOne(parser.CommaParser)).And(parser.PrimaryParser);

It makes the comma optional and allows these statements:

{% asset 'ref' id %}
{% asset 'ref', id %}

SebastianStehle avatar Dec 07 '22 14:12 SebastianStehle

You can even use AndSkip on the comma so it doesn't show up as a consumable token.

sebastienros avatar Dec 07 '22 14:12 sebastienros

Good to know. I tried that first, but without the ZeroOrOne, so:

Primary.AndSkip(comma).And(Primary).

SebastianStehle avatar Dec 07 '22 15:12 SebastianStehle

Can the parsers not be made public? It is "weird" that you can add custom tags from outside but not access the parsers that you need to register them.

SebastianStehle avatar Dec 07 '22 15:12 SebastianStehle

I agree most of them should be public. But maybe through a custom property such that the public API is not drowning in these. A solution could be to introduce a class that will return the protected instances. This way it's not a breaking change, and there is a public property that exposes all of them.

sebastienros avatar Dec 07 '22 18:12 sebastienros