Fluid icon indicating copy to clipboard operation
Fluid copied to clipboard

Allow trailing comma in arrays

Open mbrodala opened this issue 6 years ago • 13 comments

A very common error in Fluid templates is a trailing comma after the last array item:

<f:render partial="MyPartial" arguments="{
  first: 1,
  second: 2,
}"/>

This leads to the whole array being interpreted as string instead and is hard to track.

For this reason we really should allow trailing commas in arrays. Even IE9 agrees.

mbrodala avatar May 21 '19 08:05 mbrodala

The sequencer (symbol-and-capture yielding, context-switching tokenisation) strategy I am writing as a replacement for the current regular expression based parsing will support this. The reason for the current lack of support is that the separator isn't optional in the regular expression, causing any expression with a tailing comma to not be recognised as array at all.

https://github.com/NamelessCoder/Fluid/commits/feature/sequencer

The following will also be supported:

{{foo: bar} | v:h()} // pass ['foo' => 'bar'] as child node.
{{foo, bar} | v:h()} // pass ['foo' => $foo, 'bar' => $bar] as child node
{[foo, bar] | v:h()} // pass [0 => $foo, 1 => $bar] as child node

With the same array syntax supported in arguments. Inline pass used in example because that ability is also new :)

NamelessCoder avatar May 21 '19 09:05 NamelessCoder

@NamelessCoder Sounds really useful. Just to be clear, the following would be valid as well then?

{{foo: bar,} | v:h()}
{{foo, bar,} | v:h()}
{[foo, bar,] | v:h()}
// Plain argument syntax
{v:h({foo: bar,})}
{v:h({foo, bar,})}
{v:h([foo, bar,])}

mbrodala avatar May 21 '19 10:05 mbrodala

Not exactly - here's a more complete version:

{{foo: bar,} | v:h()} // supported, last comma ignored
{{foo, bar,} | v:h()} // supported, last comma ignored (ECMA literal)
{[foo, bar,] | v:h()} // supported, last comma ignored (numeric index)
{v:h(foo)} // call v:h with foo=$foo
{v:h(foo, bar)} // call v:h with foo=$foo and bar=$bar
                // VH arguments support ECMA literal property shorthand only
{v:h(array: {foo, bar,})} // supported, last comma ignored (ECMA literal)
{v:h(array: [foo, bar,])} // supported, last comma ignored (numeric index)
{v:h(array: {foo: x, bar: y,})} // supported, last comma ignored
{v:h(array: ["{dynamic}": "y"])} // supported
{v:h(array: ["{v:h()}": "value"])} // supported
{v:h(array: ["x"="y", "z"="m"])} // supported, but whitespace has separator meaning (X)
{v:h(array: ["x"="y" "z"="m"])} // supported, no separators works only with equals sign (X)
{v:h(array: ["{dynamic}"="y"])} // supported (X)

Including all variations of the above, only discerning about [] vs. {} in terms of what happens if you do not provide a key. Leaning heavily on ECMA. Not completely decided about the X marked ones but theoretically it should be possible to switch to tag attribute mode if detecting an equals sign in the array...

NamelessCoder avatar May 21 '19 10:05 NamelessCoder

I'm not sure I get everything of this. For example why is {v:h(foo: foo, bar: bar)} not allowed anymore? I can imagine this will lead to quite a few additional f:alias or f:var calls to rename incoming variables to viewhelper arguments.

mbrodala avatar May 21 '19 11:05 mbrodala

All the old syntax is still supported! I just didn't mention those because they're so well known already ;)

{v:h(arg: x, arg2: y, )} // also supported despite tailing comma
{v:h(arg: x, arg2: y)} // still supported just like always

Everything you know from tag mode remains the same with one addition; the sequencer is actually also aware of standard tags (in preparation for extracting xmlns, but currently just rendering normal, not-VH tags as text).

Another thing that's also going to be added are ViewHelper aliases so you can alias f:format.raw to a shorter name and do for example {variable | raw} which becomes identical to {variable | f:format.raw()}.

NamelessCoder avatar May 21 '19 11:05 NamelessCoder

Dude, I'm not sure if Fluid is on steroids or you are. ;-)

(BTW, I expect the latter to be {variable | raw()} instead, for clarity.)

mbrodala avatar May 21 '19 12:05 mbrodala

{variable | raw()} would work the same (didn't test but the sequencer should see the same situation except this variant is slightly more expensive). Avoid the 'roid! ^^

NamelessCoder avatar May 21 '19 12:05 NamelessCoder

Syntax like <f:render partial="Test" arguments="{foo: 'foo', bar: 'bar',}" /> appears to be supported in 2.x - would you mind confirming, @mbrodala? If you can confirm I say we close this issue - and lean back and relax, knowing that at least 2.x array syntax is ECMA-compliant just like 3.0 will be :)

NamelessCoder avatar Jan 08 '20 13:01 NamelessCoder

Yes, I'm happily using this. :-)

mbrodala avatar Jan 08 '20 14:01 mbrodala

Perfect - happy to hear that :)

NamelessCoder avatar Jan 08 '20 14:01 NamelessCoder

Actually I was wrong, this still doesn't work:

The argument "arguments" was registered with type "array", but is of type "string" in view helper "TYPO3\CMS\Fluid\ViewHelpers\RenderViewHelper".

mbrodala avatar Jan 08 '20 15:01 mbrodala

Do you have Fluid 2.6.8 on the system that reports this? (I did a test earlier today and it works on 2.6.8 at least on my system).

Does it fail the same way in both tag mode and inline mode? IIRC those are two different regular expressions.

Fails:
	<f:render partial="Test" arguments="{
	foo: 'foo',
	bar: 'bar',
	}" />
Works:
        <f:render partial="Test" arguments="{foo: 'foo', bar: 'bar',}" />

Looks like the whitespace has an effect.

NamelessCoder avatar Jan 08 '20 15:01 NamelessCoder

Yes, using 2.6.8 and I can confirm that the linebreaks break (heh) the code. Everything inline works just fine, even with trailing comma ...

mbrodala avatar Jan 08 '20 16:01 mbrodala

This has been fixed with https://github.com/TYPO3/Fluid/pull/696

lolli42 avatar May 04 '23 14:05 lolli42