From 469b4bc23fa5412bae6f2b3a701c180b1f77b812 Mon Sep 17 00:00:00 2001 From: Dylan Piercey Date: Sat, 7 May 2022 20:14:01 -0700 Subject: [PATCH] fix: multi line expression parsing --- .changeset/strange-zoos-tell.md | 5 + .../attr-operators-newline-after.expected.txt | 914 ++++++++++++++++++ .../attr-operators-newline-after/input.marko | 232 +++++ ...attr-operators-newline-before.expected.txt | 427 ++++++++ .../attr-operators-newline-before/input.marko | 118 +++ src/states/EXPRESSION.ts | 45 +- src/states/OPEN_TAG.ts | 2 +- 7 files changed, 1726 insertions(+), 17 deletions(-) create mode 100644 .changeset/strange-zoos-tell.md create mode 100644 src/__tests__/fixtures/attr-operators-newline-after/__snapshots__/attr-operators-newline-after.expected.txt create mode 100644 src/__tests__/fixtures/attr-operators-newline-after/input.marko create mode 100644 src/__tests__/fixtures/attr-operators-newline-before/__snapshots__/attr-operators-newline-before.expected.txt create mode 100644 src/__tests__/fixtures/attr-operators-newline-before/input.marko diff --git a/.changeset/strange-zoos-tell.md b/.changeset/strange-zoos-tell.md new file mode 100644 index 00000000..480f50fd --- /dev/null +++ b/.changeset/strange-zoos-tell.md @@ -0,0 +1,5 @@ +--- +"htmljs-parser": patch +--- + +Improves consistency with v2 of the parser by allowing expressions to span multiple lines if the line is ended with the continuation. This change also allows html attributes and grouped concise attributes to span multiple lines with a new line before _or after_ the continuation. diff --git a/src/__tests__/fixtures/attr-operators-newline-after/__snapshots__/attr-operators-newline-after.expected.txt b/src/__tests__/fixtures/attr-operators-newline-after/__snapshots__/attr-operators-newline-after.expected.txt new file mode 100644 index 00000000..eedcad00 --- /dev/null +++ b/src/__tests__/fixtures/attr-operators-newline-after/__snapshots__/attr-operators-newline-after.expected.txt @@ -0,0 +1,914 @@ +1╭─ a= await + │ ││ ╰─ attrValue.value "await\ny" + │ │├─ attrValue "= await\ny" + │ │╰─ attrName + ╰─ ╰─ tagName +2╭─ y a + ╰─ ╰─ attrName +3╭─ a= new + │ ││ ╰─ attrValue.value "new\ny" + │ │├─ attrValue "= new\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +4╭─ y a + ╰─ ╰─ attrName +5╭─ a= void + │ ││ ╰─ attrValue.value "void\ny" + │ │├─ attrValue "= void\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +6╭─ y a + ╰─ ╰─ attrName +7╭─ a= typeof + │ ││ ╰─ attrValue.value "typeof\ny" + │ │├─ attrValue "= typeof\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +8╭─ y a + ╰─ ╰─ attrName +9╭─ a= class + │ ││ ╰─ attrValue.value "class\nY {}" + │ │├─ attrValue "= class\nY {}" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +10╭─ Y {} a + ╰─ ╰─ attrName +11╭─ a=x . + │ ││╰─ attrValue.value "x .\ny" + │ │├─ attrValue "=x .\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +12╭─ y a + ╰─ ╰─ attrName +13╭─ a=x ! + │ ││╰─ attrValue.value "x !\ny" + │ │├─ attrValue "=x !\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +14╭─ y a + ╰─ ╰─ attrName +15╭─ a=x * + │ ││╰─ attrValue.value "x *\ny" + │ │├─ attrValue "=x *\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +16╭─ y a + ╰─ ╰─ attrName +17╭─ a=x / + │ ││╰─ attrValue.value "x /\ny" + │ │├─ attrValue "=x /\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +18╭─ y a + ╰─ ╰─ attrName +19╭─ a=x ** + │ ││╰─ attrValue.value "x **\ny" + │ │├─ attrValue "=x **\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +20╭─ y a + ╰─ ╰─ attrName +21╭─ a=x % + │ ││╰─ attrValue.value "x %\ny" + │ │├─ attrValue "=x %\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +22╭─ y a + ╰─ ╰─ attrName +23╭─ a=x & + │ ││╰─ attrValue.value "x &\ny" + │ │├─ attrValue "=x &\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +24╭─ y a + ╰─ ╰─ attrName +25╭─ a=x && + │ ││╰─ attrValue.value "x &&\ny" + │ │├─ attrValue "=x &&\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +26╭─ y a + ╰─ ╰─ attrName +27╭─ a=x ^ + │ ││╰─ attrValue.value "x ^\ny" + │ │├─ attrValue "=x ^\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +28╭─ y a + ╰─ ╰─ attrName +29╭─ a=x ~ + │ ││╰─ attrValue.value "x ~\ny" + │ │├─ attrValue "=x ~\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +30╭─ y a + ╰─ ╰─ attrName +31╭─ a=x | + │ ││╰─ attrValue.value "x |\ny" + │ │├─ attrValue "=x |\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +32╭─ y a + ╰─ ╰─ attrName +33╭─ a=x || + │ ││╰─ attrValue.value "x ||\ny" + │ │├─ attrValue "=x ||\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +34╭─ y a + ╰─ ╰─ attrName +35╭─ a=x ?? + │ ││╰─ attrValue.value "x ??\ny" + │ │├─ attrValue "=x ??\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +36╭─ y a + ╰─ ╰─ attrName +37╭─ a=x ? + │ ││╰─ attrValue.value "x ?\ny :\nz" + │ │├─ attrValue "=x ?\ny :\nz" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +38├─ y : +39╭─ z a + ╰─ ╰─ attrName +40╭─ a=x == + │ ││╰─ attrValue.value "x ==\ny" + │ │├─ attrValue "=x ==\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +41╭─ y a + ╰─ ╰─ attrName +42╭─ a=x === + │ ││╰─ attrValue.value "x ===\ny" + │ │├─ attrValue "=x ===\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +43╭─ y a + ╰─ ╰─ attrName +44╭─ a=x != + │ ││╰─ attrValue.value "x !=\ny" + │ │├─ attrValue "=x !=\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +45╭─ y a + ╰─ ╰─ attrName +46╭─ a=x !== + │ ││╰─ attrValue.value "x !==\ny" + │ │├─ attrValue "=x !==\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +47╭─ y a + ╰─ ╰─ attrName +48╭─ a=x <= + │ ││╰─ attrValue.value "x <=\ny" + │ │├─ attrValue "=x <=\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +49╭─ y a + ╰─ ╰─ attrName +50╭─ a=x >= + │ ││╰─ attrValue.value "x >=\ny" + │ │├─ attrValue "=x >=\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +51╭─ y a + ╰─ ╰─ attrName +52╭─ a=x &= + │ ││╰─ attrValue.value "x &=\ny" + │ │├─ attrValue "=x &=\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +53╭─ y a + ╰─ ╰─ attrName +54╭─ a=x &&= + │ ││╰─ attrValue.value "x &&=\ny" + │ │├─ attrValue "=x &&=\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +55╭─ y a + ╰─ ╰─ attrName +56╭─ a=x |= + │ ││╰─ attrValue.value "x |=\ny" + │ │├─ attrValue "=x |=\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +57╭─ y a + ╰─ ╰─ attrName +58╭─ a=x ||= + │ ││╰─ attrValue.value "x ||=\ny" + │ │├─ attrValue "=x ||=\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +59╭─ y a + ╰─ ╰─ attrName +60╭─ a=x ^= + │ ││╰─ attrValue.value "x ^=\ny" + │ │├─ attrValue "=x ^=\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +61╭─ y a + ╰─ ╰─ attrName +62╭─ a=x ~= + │ ││╰─ attrValue.value "x ~=\ny" + │ │├─ attrValue "=x ~=\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +63╭─ y a + ╰─ ╰─ attrName +64╭─ a=x >>= + │ ││╰─ attrValue.value "x >>=\ny" + │ │├─ attrValue "=x >>=\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +65╭─ y a + ╰─ ╰─ attrName +66╭─ a=x >>>= + │ ││╰─ attrValue.value "x >>>=\ny" + │ │├─ attrValue "=x >>>=\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +67╭─ y a + ╰─ ╰─ attrName +68╭─ a=x -= + │ ││╰─ attrValue.value "x -=\ny" + │ │├─ attrValue "=x -=\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +69╭─ y a + ╰─ ╰─ attrName +70╭─ a=x /= + │ ││╰─ attrValue.value "x /=\ny" + │ │├─ attrValue "=x /=\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +71╭─ y a + ╰─ ╰─ attrName +72╭─ a=x *= + │ ││╰─ attrValue.value "x *=\ny" + │ │├─ attrValue "=x *=\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +73╭─ y a + ╰─ ╰─ attrName +74╭─ a=x **= + │ ││╰─ attrValue.value "x **=\ny" + │ │├─ attrValue "=x **=\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +75╭─ y a + ╰─ ╰─ attrName +76╭─ a=x %= + │ ││╰─ attrValue.value "x %=\ny" + │ │├─ attrValue "=x %=\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +77╭─ y a + ╰─ ╰─ attrName +78╭─ a=x += + │ ││╰─ attrValue.value "x +=\ny" + │ │├─ attrValue "=x +=\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +79╭─ y a + ╰─ ╰─ attrName +80╭─ a=x ++ + + │ ││╰─ attrValue.value "x ++ +\ny" + │ │├─ attrValue "=x ++ +\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +81╭─ y a + ╰─ ╰─ attrName +82╭─ a=x + + │ ││╰─ attrValue.value "x +\n++ y" + │ │├─ attrValue "=x +\n++ y" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +83╭─ ++ y a + ╰─ ╰─ attrName +84╭─ a=x >> + │ ││╰─ attrValue.value "x >>\ny" + │ │├─ attrValue "=x >>\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +85╭─ y a + ╰─ ╰─ attrName +86╭─ a=x >>> + │ ││╰─ attrValue.value "x >>>\ny" + │ │├─ attrValue "=x >>>\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +87╭─ y a + ╰─ ╰─ attrName +88╭─ a=x => + │ ││╰─ attrValue.value "x =>\ny" + │ │├─ attrValue "=x =>\ny" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +89╭─ y a + ╰─ ╰─ attrName +90╭─ a=x => + │ ││╰─ attrValue.value "x =>\n( y )" + │ │├─ attrValue "=x =>\n( y )" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +91╭─ ( y ) a + ╰─ ╰─ attrName +92╭─ a= (x) => + │ ││ ╰─ attrValue.value "(x) =>\n{ console.log(\"y\") }" + │ │├─ attrValue "= (x) =>\n{ console.log(\"y\") }" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +93╭─ { console.log("y") } a + ╰─ ╰─ attrName +94╭─ a= async + │ ││ ╰─ attrValue.value "async\nx =>\n{ console.log(\"y\") }" + │ │├─ attrValue "= async\nx =>\n{ console.log(\"y\") }" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +95├─ x => +96├─ { console.log("y") } +97╭─ a + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +98╭─ a= function + │ ││ ╰─ attrValue.value "function\n(x) { console.log(\"y\") }" + │ │├─ attrValue "= function\n(x) { console.log(\"y\") }" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +99├─ (x) { console.log("y") } +100╭─ a + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +101╭─ a= x => + │ ││ ╰─ attrValue.value "x =>\n{ console.log(\"y\") }" + │ │├─ attrValue "= x =>\n{ console.log(\"y\") }" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +102├─ { console.log("y") } +103╭─ a + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +104╭─ a= async + │ ││ ╰─ attrValue.value "async\nfunction\n(x) { console.log(\"y\") }" + │ │├─ attrValue "= async\nfunction\n(x) { console.log(\"y\") }" + │ │╰─ attrName + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +105├─ function +106├─ (x) { console.log("y") } +107╭─ a + │ ├─ closeTag(a) + │ ├─ openTagEnd + ╰─ ╰─ tagName +108╭─ + ╰─ ╰─ openTagEnd +109╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +111╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +113╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +115╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +117╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +120╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +122╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +124╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +126╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +128╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +130╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +132╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +134╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +136╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +138╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +140╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +142╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +144╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +146╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +149╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +151╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +153╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +155╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +157╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +159╭─ = + │ ││╰─ attrValue.value "x >=\ny" + │ │├─ attrValue "=x >=\ny" + │ │╰─ attrName + ╰─ ╰─ tagName +160╭─ y a/> + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +161╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +163╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +165╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +167╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +169╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +171╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +173╭─ >= + │ ││╰─ attrValue.value "x >>=\ny" + │ │├─ attrValue "=x >>=\ny" + │ │╰─ attrName + ╰─ ╰─ tagName +174╭─ y a/> + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +175╭─ >>= + │ ││╰─ attrValue.value "x >>>=\ny" + │ │├─ attrValue "=x >>>=\ny" + │ │╰─ attrName + ╰─ ╰─ tagName +176╭─ y a/> + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +177╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +179╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +181╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +183╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +185╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +187╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +189╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +191╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +193╭─ > + │ ││╰─ attrValue.value "x >>\ny" + │ │├─ attrValue "=x >>\ny" + │ │╰─ attrName + ╰─ ╰─ tagName +194╭─ y a/> + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +195╭─ >> + │ ││╰─ attrValue.value "x >>>\ny" + │ │├─ attrValue "=x >>>\ny" + │ │╰─ attrName + ╰─ ╰─ tagName +196╭─ y a/> + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +197╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +199╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +201╭─ \ny" + │ │├─ attrValue "=x\n=>\ny" + │ │╰─ attrName + ╰─ ╰─ tagName +202├─ => +203╭─ y a/> + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +204╭─ \n( y )" + │ │├─ attrValue "=x\n=>\n( y )" + │ │╰─ attrName + ╰─ ╰─ tagName +205├─ => +206╭─ ( y ) a/> + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +207╭─ \n{ y }" + │ │├─ attrValue "=x\n=>\n{ y }" + │ │╰─ attrName + ╰─ ╰─ tagName +208├─ => +209╭─ { y } a/> + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +210╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +212╭─ \n{ console.log(\"y\") }" + │ │├─ attrValue "= (x)\n=>\n{ console.log(\"y\") }" + │ │╰─ attrName + ╰─ ╰─ tagName +213├─ => +214╭─ { console.log("y") } a/> + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +215╭─ \n{ console.log(\"y\") }" + │ │├─ attrValue "= async\nx\n=>\n{ console.log(\"y\") }" + │ │╰─ attrName + ╰─ ╰─ tagName +216├─ x +217├─ => +218├─ { console.log("y") } +219╭─ a/> + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +220╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +224╭─ \n{ console.log(\"y\") }" + │ │├─ attrValue "= x\n=>\n{ console.log(\"y\") }" + │ │╰─ attrName + ╰─ ╰─ tagName +225├─ => +226├─ { console.log("y") } +227╭─ a/> + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +228╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName \ No newline at end of file diff --git a/src/__tests__/fixtures/attr-operators-newline-after/input.marko b/src/__tests__/fixtures/attr-operators-newline-after/input.marko new file mode 100644 index 00000000..3813fe7a --- /dev/null +++ b/src/__tests__/fixtures/attr-operators-newline-after/input.marko @@ -0,0 +1,232 @@ +a= await +y a +a= new +y a +a= void +y a +a= typeof +y a +a= class +Y {} a +a=x . +y a +a=x ! +y a +a=x * +y a +a=x / +y a +a=x ** +y a +a=x % +y a +a=x & +y a +a=x && +y a +a=x ^ +y a +a=x ~ +y a +a=x | +y a +a=x || +y a +a=x ?? +y a +a=x ? +y : +z a +a=x == +y a +a=x === +y a +a=x != +y a +a=x !== +y a +a=x <= +y a +a=x >= +y a +a=x &= +y a +a=x &&= +y a +a=x |= +y a +a=x ||= +y a +a=x ^= +y a +a=x ~= +y a +a=x >>= +y a +a=x >>>= +y a +a=x -= +y a +a=x /= +y a +a=x *= +y a +a=x **= +y a +a=x %= +y a +a=x += +y a +a=x ++ + +y a +a=x + +++ y a +a=x >> +y a +a=x >>> +y a +a=x => +y a +a=x => +( y ) a +a= (x) => +{ console.log("y") } a +a= async +x => +{ console.log("y") } +a +a= function +(x) { console.log("y") } +a +a= x => +{ console.log("y") } +a +a= async +function +(x) { console.log("y") } +a + + + + + + + + + + + + + + + + + + + + + + + + + += +y a/> + + + + + + +>= +y a/> +>>= +y a/> + + + + + + + + +> +y a/> +>> +y a/> + + + +y a/> + +( y ) a/> + +{ y } a/> + + +{ console.log("y") } a/> + +{ console.log("y") } +a/> + + +{ console.log("y") } +a/> + \ No newline at end of file diff --git a/src/__tests__/fixtures/attr-operators-newline-before/__snapshots__/attr-operators-newline-before.expected.txt b/src/__tests__/fixtures/attr-operators-newline-before/__snapshots__/attr-operators-newline-before.expected.txt new file mode 100644 index 00000000..bfa278ad --- /dev/null +++ b/src/__tests__/fixtures/attr-operators-newline-before/__snapshots__/attr-operators-newline-before.expected.txt @@ -0,0 +1,427 @@ +1╭─ // newline continuations only work for html mode or enclosed concice attr groups. + │ │ ╰─ comment.value " newline continuations only work for html mode or enclosed concice attr groups." + ╰─ ╰─ comment "// newline continuations only work for html mode or enclosed concice attr groups." +2╭─ // here we sanity check that is the case. + │ │ ╰─ comment.value " here we sanity check that is the case." + ╰─ ╰─ comment "// here we sanity check that is the case." +3╭─ a=x + │ ││╰─ attrValue.value + │ │├─ attrValue "=x" + │ │╰─ attrName + ╰─ ╰─ tagName +4╭─ .b + │ │╰─ tagShorthandClass.quasis[0] + │ ├─ closeTag(a) + │ ├─ openTagEnd + │ ├─ tagShorthandClass ".b" + ╰─ ╰─ tagName +5╭─ + ╰─ ╰─ openTagEnd +6╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +8╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +10╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +12╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +14╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +16╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +18╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +20╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +22╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +24╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +26╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +28╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +30╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +32╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +35╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +37╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +39╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +41╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +43╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +45╭─ = y" + │ │├─ attrValue "=x\n>= y" + │ │╰─ attrName + ╰─ ╰─ tagName +46╭─ >= y a/> + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +47╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +49╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +51╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +53╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +55╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +57╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +59╭─ >= y" + │ │├─ attrValue "=x\n>>= y" + │ │╰─ attrName + ╰─ ╰─ tagName +60╭─ >>= y a/> + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +61╭─ >>= y" + │ │├─ attrValue "=x\n>>>= y" + │ │╰─ attrName + ╰─ ╰─ tagName +62╭─ >>>= y a/> + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +63╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +65╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +67╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +69╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +71╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +73╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +75╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +77╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +79╭─ >y" + │ │├─ attrValue "=x\n>>y" + │ │╰─ attrName + ╰─ ╰─ tagName +80╭─ >>y a/> + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +81╭─ >> y" + │ │├─ attrValue "=x\n>>> y" + │ │╰─ attrName + ╰─ ╰─ tagName +82╭─ >>> y a/> + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +83╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +85╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +87╭─ \ny" + │ │├─ attrValue "=x\n=>\ny" + │ │╰─ attrName + ╰─ ╰─ tagName +88├─ => +89╭─ y a/> + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +90╭─ \n( y )" + │ │├─ attrValue "=x\n=>\n( y )" + │ │╰─ attrName + ╰─ ╰─ tagName +91├─ => +92╭─ ( y ) a/> + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +93╭─ \n{ y }" + │ │├─ attrValue "=x\n=>\n{ y }" + │ │╰─ attrName + ╰─ ╰─ tagName +94├─ => +95╭─ { y } a/> + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +96╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +98╭─ \n{ console.log(\"y\") }" + │ │├─ attrValue "= (x)\n=>\n{ console.log(\"y\") }" + │ │╰─ attrName + ╰─ ╰─ tagName +99├─ => +100╭─ { console.log("y") } a/> + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +101╭─ \n{ console.log(\"y\") }" + │ │├─ attrValue "= async\nx\n=>\n{ console.log(\"y\") }" + │ │╰─ attrName + ╰─ ╰─ tagName +102├─ x +103├─ => +104├─ { console.log("y") } +105╭─ a/> + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +106╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +110╭─ \n{ console.log(\"y\") }" + │ │├─ attrValue "= x\n=>\n{ console.log(\"y\") }" + │ │╰─ attrName + ╰─ ╰─ tagName +111├─ => +112├─ { console.log("y") } +113╭─ a/> + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName +114╭─ + │ │╰─ openTagEnd:selfClosed "/>" + ╰─ ╰─ attrName \ No newline at end of file diff --git a/src/__tests__/fixtures/attr-operators-newline-before/input.marko b/src/__tests__/fixtures/attr-operators-newline-before/input.marko new file mode 100644 index 00000000..a854587b --- /dev/null +++ b/src/__tests__/fixtures/attr-operators-newline-before/input.marko @@ -0,0 +1,118 @@ +// newline continuations only work for html mode or enclosed concice attr groups. +// here we sanity check that is the case. +a=x +.b + + + + + + + + + + + + + + + + + + + + += y a/> + + + + + + +>= y a/> +>>= y a/> + + + + + + + + +>y a/> +>> y a/> + + + +y a/> + +( y ) a/> + +{ y } a/> + + +{ console.log("y") } a/> + +{ console.log("y") } +a/> + + +{ console.log("y") } +a/> + \ No newline at end of file diff --git a/src/states/EXPRESSION.ts b/src/states/EXPRESSION.ts index a9ddb9b9..a6273f2e 100644 --- a/src/states/EXPRESSION.ts +++ b/src/states/EXPRESSION.ts @@ -8,6 +8,12 @@ import { ErrorCode, } from "../internal"; +const enum PatternType { + HTML_ATTRS, + CONCISE_ATTRS, + CONCISE_ATTRS_GROUP, +} + export interface ExpressionMeta extends Meta { groupStack: number[]; terminator: number | (number | number[])[]; @@ -16,8 +22,9 @@ export interface ExpressionMeta extends Meta { terminatedByWhitespace: boolean; } -const conciseOperatorPattern = buildOperatorPattern(true); -const htmlOperatorPattern = buildOperatorPattern(false); +const htmlAttrsPattern = buildPattern(PatternType.HTML_ATTRS); +const conciseAttrsPattern = buildPattern(PatternType.CONCISE_ATTRS); +const conciseAttrsGroupPattern = buildPattern(PatternType.CONCISE_ATTRS_GROUP); export const EXPRESSION: StateDefinition = { name: "EXPRESSION", @@ -134,7 +141,8 @@ export const EXPRESSION: StateDefinition = { eol(_, expression) { if ( !expression.groupStack.length && - (expression.terminatedByWhitespace || expression.terminatedByEOL) + (expression.terminatedByEOL || expression.terminatedByWhitespace) && + !checkForOperators(this, expression) ) { this.exitState(); } @@ -201,17 +209,20 @@ export const EXPRESSION: StateDefinition = { return() {}, }; -function buildOperatorPattern(isConcise: boolean) { +function buildPattern(type: PatternType) { + const space = type === PatternType.CONCISE_ATTRS ? "[ \\t]" : "\\s"; const binary = "(?:[!~*%&^|?<]+=*)+" + // Any of these characters can always continue an expression "|:+(?!=)" + // Match a colon without matching a bound attribute "|[>/+=-]+=|=>" + // Match equality and multi char assignment operators w/o matching equals by itself - "|(?"}])` + // We only continue after a forward slash if it isn't //, /* (or /> in html mode) - `|(?${isConcise ? "+" : "{2,}"}` + // in html mode only consume closing angle brackets if it is >> - "|\\b(?:in(?:stanceof)?|as|extends)(?=[ \\t]+[^=/,;:>])"; // We only continue after word operators (instanceof/in) when they are not followed by a terminator + `|(?" : ""}])` + // We only continue after a forward slash if it isn't //, /* (or /> in html mode) + `|(?${type === PatternType.HTML_ATTRS ? "{2,}" : "+"}` + // in html mode only consume closing angle brackets if it is >> + "|[ \\t]+(?:in(?:stanceof)?|as|extends)(?=[ \\t]+[^=/,;:>])"; // We only continue after word operators (instanceof/in) when they are not followed by a terminator const unary = "\\b(?