Skip to content

How To Add New Features

zackad edited this page Aug 6, 2024 · 1 revision

Originally posted by @jannisborgers in https://github.com/zackad/prettier-plugin-twig/issues/19#issuecomment-2272283914

Step 1: Let lexer tokenize arrow functions

  • Add new token type:

https://github.com/zackad/prettier-plugin-twig/blob/c38344121732798ea32c4388989514bb8acdfb1d/src/melody/melody-parser/TokenTypes.js#L47

  • Identify and tokenize arrow function correctly instead of making it an assignment (=) and an operator (>) (this is the error we all see right now):

https://github.com/zackad/prettier-plugin-twig/blob/c38344121732798ea32c4388989514bb8acdfb1d/src/melody/melody-parser/Lexer.js#L47 https://github.com/zackad/prettier-plugin-twig/blob/c38344121732798ea32c4388989514bb8acdfb1d/src/melody/melody-parser/Lexer.js#L349-L357

Step 2: Let parser identify arrow function in addition to other filter arguments

matchFilterExpression() and matchArguments() are called to collect the arguments of the filter that is applied to a variable.

  • Already supported scenarios:
    • no arguments: someString|raw
    • some arguments, comma-separated: someArray|batch(3, 'No item')
    • named arguments via assignments: someDate|data_uri(mime="text/html", parameters={charset: "ascii"})
  • Newly supported scenarios:
    • arrow function with one argument: someArray|filter(item => item.amount > 4)
    • arrow function with multiple arguments: someArray|map((value, key) => item.firstName ~ " " ~ item.lastName)
    • arrow function, plus other filter arguments, e.g. numbers|reduce((carry, v, k) => carry + v * k, 10), where 10 is the second filter argument and the arrow function is the callback. This works because comma-checks are in place for multiple filter arguments already and matchArguments() is called recursively for each filter argument.

https://github.com/zackad/prettier-plugin-twig/blob/c38344121732798ea32c4388989514bb8acdfb1d/src/melody/melody-parser/Parser.js#L923-L961

Step 3: Add node type:

Used to identify the arrow function as a whole

https://github.com/zackad/prettier-plugin-twig/blob/c38344121732798ea32c4388989514bb8acdfb1d/src/melody/melody-types/index.js#L326-L339

Step 4: Parse arrow function itself

Arguments is everything between the filter’s opening parenthesis ( and arrow =>

  • Possible scenarios:
  • option 1: single argument, e.g. item =>
  • option 2: multiple arguments inside their own parenthesis, e.g.(value, key) =>

Body is everything after the arrow => up until the closing filter parenthesis )

  • A million scenarios, but each is an expression, which is already covered by the plugin

https://github.com/zackad/prettier-plugin-twig/blob/c38344121732798ea32c4388989514bb8acdfb1d/src/melody/melody-parser/Parser.js#L963-L1004

Step 5: Add ArrowFunction printer

After the arrow function as a whole is added as a node, it has props for params and body, which can be used inside the printer for formatting.

This is where proper formatting can be achieved by defining the output of the printer.

I’m working on another PR which allows more fine-grained control over line-breaks for filters (and objects), because I think needless indentation of single arguments or properties, or multiple short ones, is not helping code legibility.

https://github.com/zackad/prettier-plugin-twig/blob/c38344121732798ea32c4388989514bb8acdfb1d/src/print/ArrowFunction.js#L1-L28

Additional scenarios:

I have only tested arrow functions in tags {% %} as opposed to expressions {{ }} briefly, but they seem to work as well now (?)

Scope

As far as I know, arrow functions are only available in map, filter and reduce filters in Twig 3. While there is a Craft plugin to make it work everywhere else, and that plugin got a lot of thumbs up for being native Twig 4 functionality, I think making it work with the three above will improve this plugin a lot.