From c2f9760d0802d6bfe5b641d8fd59f219a8883f75 Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Wed, 21 May 2025 08:18:09 -0700 Subject: [PATCH] Fix template parsing --- .../components/core/Editor/twig/highlight.ts | 13 +--- .../core/Editor/twig/templateTags.ts | 4 ++ .../components/core/Editor/twig/twig.grammar | 71 +++---------------- .../components/core/Editor/twig/twig.terms.ts | 15 ++-- src-web/components/core/Editor/twig/twig.ts | 24 +++---- 5 files changed, 31 insertions(+), 96 deletions(-) diff --git a/src-web/components/core/Editor/twig/highlight.ts b/src-web/components/core/Editor/twig/highlight.ts index e33381ea..b91d6ed9 100644 --- a/src-web/components/core/Editor/twig/highlight.ts +++ b/src-web/components/core/Editor/twig/highlight.ts @@ -1,14 +1,7 @@ import { styleTags, tags as t } from '@lezer/highlight'; export const highlight = styleTags({ - "${[": t.bracket, - "]}": t.bracket, - "(": t.bracket, - ")": t.bracket, - "=": t.bracket, - ",": t.bracket, - Tag: t.keyword, - Identifier: t.variableName, - ChainedIdentifier: t.variableName, - Boolean: t.bool, + TagOpen: t.bracket, + TagClose: t.bracket, + TagContent: t.keyword, }); diff --git a/src-web/components/core/Editor/twig/templateTags.ts b/src-web/components/core/Editor/twig/templateTags.ts index e34fe5bd..79d37dcf 100644 --- a/src-web/components/core/Editor/twig/templateTags.ts +++ b/src-web/components/core/Editor/twig/templateTags.ts @@ -80,6 +80,10 @@ function templateTags( const inner = rawTag.replace(/^\$\{\[\s*/, '').replace(/\s*]}$/, ''); let name = inner.match(/([\w.]+)[(]/)?.[1] ?? inner; + if (inner.includes('\n')) { + return; + } + // The beta named the function `Response` but was changed in stable. // Keep this here for a while because there's no easy way to migrate if (name === 'Response') { diff --git a/src-web/components/core/Editor/twig/twig.grammar b/src-web/components/core/Editor/twig/twig.grammar index 6d31100d..5706e200 100644 --- a/src-web/components/core/Editor/twig/twig.grammar +++ b/src-web/components/core/Editor/twig/twig.grammar @@ -1,70 +1,17 @@ -@precedence { - top, - mid, - lesser +@top Template { (Tag | Text)* } + +@local tokens { + TagClose { "]}" } + @else TagContent } -@top Template { (Tag | PlainText)* } - -@skip { space } - -Tag { "${[" expression* "]}" } - -commaSep { "" | content ("," content?)* } - -expression { - Function | - Assignment | - Identifier | - ChainedIdentifier | - basicType | - hashStructure +@skip { } { + TagOpen { "${[" } + Tag { TagOpen (TagContent)+ TagClose } } -basicType { - String | - Boolean | - Number -} - -functionParam { - Identifier | - Assignment | - basicType -} - -FunctionParamList { - "(" commaSep ")" -} - -Assignment { Identifier "=" expression } - -Function { (Identifier | ChainedIdentifier) !top FunctionParamList} - @tokens { - PlainText { ![$] PlainText? | "$" (@eof | ![{[] PlainText?) } - - Identifier { $[a-zA-Z_\-0-9]+ } - ChainedIdentifier { Identifier ("." Identifier)+ } - - hashStructure { "{" | "}" | ":" | ","} - - Boolean { "true" | "false" } - String { ("'" (![\\'] | "\\" _)* "'"?) | ("\"" (![\\"] | "\\" _)* "\""?) } - Number { '-'? int frac? } - int { '0' | $[1-9] @digit* } - frac { '.' @digit+ } - - @precedence { PlainText, Boolean, Number, ChainedIdentifier, Identifier, space, String } - - space { $[ \t\n\r]+ } - - "${[" "]}" - "(" ")" - "=" - "," + Text { ![$] Text? | "$" (@eof | ![{] Text?) } } @external propSource highlight from "./highlight" - -@detectDelim diff --git a/src-web/components/core/Editor/twig/twig.terms.ts b/src-web/components/core/Editor/twig/twig.terms.ts index 5011c081..d6bda1a3 100644 --- a/src-web/components/core/Editor/twig/twig.terms.ts +++ b/src-web/components/core/Editor/twig/twig.terms.ts @@ -1,13 +1,8 @@ // This file was generated by lezer-generator. You probably shouldn't edit it. export const Template = 1, - Tag = 4, - Function = 5, - Identifier = 6, - ChainedIdentifier = 7, - FunctionParamList = 10, - Assignment = 11, - String = 13, - Boolean = 14, - Number = 15, - PlainText = 17 + Tag = 2, + TagOpen = 3, + TagContent = 4, + TagClose = 5, + Text = 6 diff --git a/src-web/components/core/Editor/twig/twig.ts b/src-web/components/core/Editor/twig/twig.ts index 2d16ccf1..04452432 100644 --- a/src-web/components/core/Editor/twig/twig.ts +++ b/src-web/components/core/Editor/twig/twig.ts @@ -1,22 +1,18 @@ // This file was generated by lezer-generator. You probably shouldn't edit it. -import {LRParser} from "@lezer/lr" +import {LRParser, LocalTokenGroup} from "@lezer/lr" import {highlight} from "./highlight" export const parser = LRParser.deserialize({ version: 14, - states: "$zQVQPOOOsQQO'#C`OOQO'#Cn'#CnQVQPOOO!fQQO'#CtOOQO'#Cw'#CwOzQQO'#CtOOQO'#Ct'#CtOOQO'#Co'#CoO!mQQO,58zOOQO,58z,58zOOQO-E6l-E6lO_QQO,59RO!tQQO'#CfOOQO,58{,58{OOQO-E6m-E6mOOQO1G.f1G.fOOQO1G.m1G.mO#VQSO'#CvOOQO'#Cv'#CvO#bQSO'#CuO#jQQO,59QO#oQSO'#CpO$TQSO,59aOOQO1G.l1G.lO$]QSO'#CtO$kQSO'#CtOOQO,59[,59[OOQO-E6n-E6nO$vQQO,59R", - stateData: "%e~OgOS~ORPOaQO~OUSOVUO]TO^TO_TOlVO~OQYO~P_OX]OQhXUhXVhX]hX^hX_hXlhX~O[[O~PzOQ`O~P_OUbO]TO^TO_TOWiP~O[mOWjX`jX~O`fOWiX~OWhO~OUbO]TO^TO_TOWdX`dX~O`fOWia~OX]O[mOWhX`hX~OX]OWhX`hX~OUiOVjO]TO^TO_TOlVO~Oa^_VUg]V~", - goto: "!|lPPPPmqPPPPw}PPPPPP!X!_!ePPP!k!s!v}TQORXVPX[mX^SUijWVPX[mTc]fQRORZRQXPR_XQgdRlgSWPXTa[mRe]Qd]Rkf", - nodeNames: "⚠ Template ]} ${[ Tag Function Identifier ChainedIdentifier ) ( FunctionParamList Assignment = String Boolean Number , PlainText", - maxTerm: 28, - nodeProps: [ - ["openedBy", 2,"${[",8,"("], - ["closedBy", 3,"]}",9,")"] - ], + states: "!^QQOPOOOOOO'#C_'#C_OYOQO'#C^OOOO'#Cc'#CcQQOPOOOOOO'#Cd'#CdO_OQO,58xOOOO-E6a-E6aOOOO-E6b-E6bOOOO1G.d1G.d", + stateData: "g~OUROYPO~OSTO~OSTOTXO~O", + goto: "nXPPY^PPPbhTROSTQOSQSORVSQUQRWU", + nodeNames: "⚠ Template Tag TagOpen TagContent TagClose Text", + maxTerm: 10, propSources: [highlight], skippedNodes: [0], - repeatNodeCount: 3, - tokenData: "Fe~RzOX#uXY%OYZ%OZ]#u]^%O^p#upq%Oqr#urs%{st#utu+Ouw#uwx+vxy0^yz0tz|#u|}1[}!O1t!O!Q#u!Q!R6h!R![:S![!];_!]!_#u!_!`;u!`!c#u!c!}3Q!}#P#u#P#Q<]#Q#R#u#R#S3Q#S#T#u#T#Y3Q#Y#Z=_#Z#h3Q#h#iCu#i#o3Q#o#p;_#p#q#u#q#r;_#r;'S#u;'S;=`$s<%lO#uP#zTaPOt#utu$Zu;'S#u;'S;=`$s<%lO#uP$^VO!}#u#O#o#u#p;'S#u;'S;=`$s<%l~#u~O#u~~$yP$vP;=`<%l#uP%OOaP~%V[aPg~OX#uXY%OYZ%OZ]#u]^%O^p#upq%Oqt#utu$Zu;'S#u;'S;=`$s<%lO#u~&SXaP]~Or%{rs&ost%{tu'Vu#O%{#O#P)r#P;'S%{;'S;=`*x<%lO%{~&vTaP]~Ot#utu$Zu;'S#u;'S;=`$s<%lO#u~'[[]~Or%{rs&os!}%{!}#O(Q#O#P)r#P#o%{#o#p(Q#p;'S%{;'S;=`*x<%l~%{~O%{~~$y~(VV]~Or(Qrs(ls#O(Q#O#P(q#P;'S(Q;'S;=`)l<%lO(Q~(qO]~~(tRO;'S(Q;'S;=`(};=`O(Q~)SW]~Or(Qrs(ls#O(Q#O#P(q#P;'S(Q;'S;=`)l;=`<%l(Q<%lO(Q~)oP;=`<%l(Q~)wUaPOt%{tu'Vu;'S%{;'S;=`*Z;=`<%l(Q<%lO%{~*`W]~Or(Qrs(ls#O(Q#O#P(q#P;'S(Q;'S;=`)l;=`<%l%{<%lO(Q~*{P;=`<%l%{~+RWO!}#u#O#o#u#o#p+k#p;'S#u;'S;=`$s<%l~#u~O#u~~$y~+nP!}#O+q~+vOR~~+}XaP]~Ot+vtu,juw+vwx&ox#O+v#O#P/Q#P;'S+v;'S;=`0W<%lO+v~,o[]~Ow+vwx&ox!}+v!}#O-e#O#P/Q#P#o+v#o#p-e#p;'S+v;'S;=`0W<%l~+v~O+v~~$y~-jV]~Ow-ewx(lx#O-e#O#P.P#P;'S-e;'S;=`.z<%lO-e~.SRO;'S-e;'S;=`.];=`O-e~.bW]~Ow-ewx(lx#O-e#O#P.P#P;'S-e;'S;=`.z;=`<%l-e<%lO-e~.}P;=`<%l-e~/VUaPOt+vtu,ju;'S+v;'S;=`/i;=`<%l-e<%lO+v~/nW]~Ow-ewx(lx#O-e#O#P.P#P;'S-e;'S;=`.z;=`<%l+v<%lO-e~0ZP;=`<%l+vV0eTXUaPOt#utu$Zu;'S#u;'S;=`$s<%lO#uV0{TWUaPOt#utu$Zu;'S#u;'S;=`$s<%lO#uV1eT`SlQaPOt#utu$Zu;'S#u;'S;=`$s<%lO#u~1{aaPU~Ot#utu$Zu}#u}!O3Q!O!P4Z!P!Q#u!Q!R6h!R![:S![!c#u!c!}3Q!}#R#u#R#S3Q#S#T#u#T#o3Q#o;'S#u;'S;=`$s<%lO#u~3X`aPU~Ot#utu$Zu}#u}!O3Q!O!P4Z!P!Q#u!Q![3Q![!c#u!c!}3Q!}#R#u#R#S3Q#S#T#u#T#o3Q#o;'S#u;'S;=`$s<%lO#u~4`_aPOt#utu$Zu}#u}!O5_!O!Q#u!Q![5_![!c#u!c!}5_!}#R#u#R#S5_#S#T#u#T#o5_#o;'S#u;'S;=`$s<%lO#u~5f`aPV~Ot#utu$Zu}#u}!O5_!O!P4Z!P!Q#u!Q![5_![!c#u!c!}5_!}#R#u#R#S5_#S#T#u#T#o5_#o;'S#u;'S;=`$s<%lO#u~6q`aP_~U~Ot#utu$Zu}#u}!O3Q!O!P7s!P!Q#u!Q![3Q![!c#u!c!}3Q!}#R#u#R#S3Q#S#T#u#T#o3Q#o;'S#u;'S;=`$s<%lO#u~7x_aPOt#utu$Zu}#u}!O5_!O!Q#u!Q![8w![!c#u!c!}5_!}#R#u#R#S5_#S#T#u#T#o5_#o;'S#u;'S;=`$s<%lO#u~9Q`aP_~V~Ot#utu$Zu}#u}!O5_!O!P4Z!P!Q#u!Q![8w![!c#u!c!}5_!}#R#u#R#S5_#S#T#u#T#o5_#o;'S#u;'S;=`$s<%lO#u~:]`aP_~U~Ot#utu$Zu}#u}!O3Q!O!P7s!P!Q#u!Q![:S![!c#u!c!}3Q!}#R#u#R#S3Q#S#T#u#T#o3Q#o;'S#u;'S;=`$s<%lO#uR;fTlQaPOt#utu$Zu;'S#u;'S;=`$s<%lO#uV;|T[UaPOt#utu$Zu;'S#u;'S;=`$s<%lO#uRk#U#o3Q#o;'S#u;'S;=`$s<%lO#u~>rbaPU~Ot#utu$Zu}#u}!O3Q!O!P4Z!P!Q#u!Q![3Q![!c#u!c!}3Q!}#R#u#R#S3Q#S#T#u#T#`3Q#`#a?z#a#o3Q#o;'S#u;'S;=`$s<%lO#u~@RbaPU~Ot#utu$Zu}#u}!O3Q!O!P4Z!P!Q#u!Q![3Q![!c#u!c!}3Q!}#R#u#R#S3Q#S#T#u#T#g3Q#g#hAZ#h#o3Q#o;'S#u;'S;=`$s<%lO#u~AbbaPU~Ot#utu$Zu}#u}!O3Q!O!P4Z!P!Q#u!Q![3Q![!c#u!c!}3Q!}#R#u#R#S3Q#S#T#u#T#X3Q#X#YBj#Y#o3Q#o;'S#u;'S;=`$s<%lO#u~Bs`aP^~U~Ot#utu$Zu}#u}!O3Q!O!P4Z!P!Q#u!Q![3Q![!c#u!c!}3Q!}#R#u#R#S3Q#S#T#u#T#o3Q#o;'S#u;'S;=`$s<%lO#u~C|baPU~Ot#utu$Zu}#u}!O3Q!O!P4Z!P!Q#u!Q![3Q![!c#u!c!}3Q!}#R#u#R#S3Q#S#T#u#T#f3Q#f#gEU#g#o3Q#o;'S#u;'S;=`$s<%lO#u~E]baPU~Ot#utu$Zu}#u}!O3Q!O!P4Z!P!Q#u!Q![3Q![!c#u!c!}3Q!}#R#u#R#S3Q#S#T#u#T#i3Q#i#jAZ#j#o3Q#o;'S#u;'S;=`$s<%lO#u", - tokenizers: [0, 1, 2], + repeatNodeCount: 2, + tokenData: "#]~RTOtbtu!hu;'Sb;'S;=`!]<%lOb~gTU~Otbtuvu;'Sb;'S;=`!]<%lOb~yUO#ob#p;'Sb;'S;=`!]<%l~b~Ob~~!c~!`P;=`<%lb~!hOU~~!kVO#ob#o#p#Q#p;'Sb;'S;=`!]<%l~b~Ob~~!c~#TP!}#O#W~#]OY~", + tokenizers: [1, new LocalTokenGroup("b~RP#P#QU~XP#q#r[~aOT~~", 17, 4)], topRules: {"Template":[0,1]}, - tokenPrec: 196 + tokenPrec: 0 })