diff --git a/grammar/liquid-html.ohm b/grammar/liquid-html.ohm index 5aa9b5d..32be192 100644 --- a/grammar/liquid-html.ohm +++ b/grammar/liquid-html.ohm @@ -45,11 +45,14 @@ Liquid <: Helpers { | liquidTag | liquidInlineComment - liquidTag = + liquidTagStrict = | liquidTagAssign + | liquidTagBreak + | liquidTagContinue | liquidTagCycle | liquidTagDecrement | liquidTagEcho + | liquidTagElse | liquidTagElsif | liquidTagInclude | liquidTagIncrement @@ -59,9 +62,12 @@ Liquid <: Helpers { | liquidTagSection | liquidTagSections | liquidTagWhen + + liquidTag = + | liquidTagStrict | liquidTagBaseCase - liquidTagOpen = + liquidTagOpenStrict = | liquidTagOpenCase | liquidTagOpenCapture | liquidTagOpenForm @@ -70,7 +76,11 @@ Liquid <: Helpers { | liquidTagOpenIf | liquidTagOpenPaginate | liquidTagOpenUnless + + liquidTagOpen = + | liquidTagOpenStrict | liquidTagOpenBaseCase + liquidTagClose = "{%" "-"? space* "end" blockName space* tagMarkup "-"? "%}" // These two are the same but transformed differently @@ -148,6 +158,10 @@ Liquid <: Helpers { liquidTagOpenUnless = liquidTagOpenRule<"unless", liquidTagOpenConditionalMarkup> liquidTagElsif = liquidTagRule<"elsif", liquidTagOpenConditionalMarkup> + liquidTagBreak = liquidTagRule<"break", empty> + liquidTagContinue = liquidTagRule<"continue", empty> + liquidTagElse = liquidTagRule<"else", empty> + liquidTagOpenConditionalMarkup = nonemptyListOf space* conditionSeparator = &logicalOperator condition = logicalOperator? space* (comparison | liquidExpression) space* @@ -455,3 +469,18 @@ LiquidHTML <: Liquid { | caseInsensitive<"wbr"> ) ~identifierCharacter } + +StrictLiquid <: Liquid { + liquidTag := liquidTagStrict + liquidTagOpen := liquidTagOpenStrict +} + +StrictLiquidStatement <: LiquidStatement { + liquidTag := liquidTagStrict + liquidTagOpen := liquidTagOpenStrict +} + +StrictLiquidHTML <: LiquidHTML { + liquidTag := liquidTagStrict + liquidTagOpen := liquidTagOpenStrict +} diff --git a/src/parser/grammar.spec.ts b/src/parser/grammar.spec.ts index 477b591..657d422 100644 --- a/src/parser/grammar.spec.ts +++ b/src/parser/grammar.spec.ts @@ -1,89 +1,125 @@ import { expect } from 'chai'; -import { liquidHtmlGrammar, liquidStatementsGrammar } from '~/parser/grammar'; +import { strictGrammars, tolerantGrammars } from '~/parser/grammar'; describe('Unit: liquidHtmlGrammar', () => { - it('should parse or not parse HTML+Liquid', () => { - expectMatchSucceeded('
').to.be.true; - expectMatchSucceeded('').to.be.true; - expectMatchSucceeded('').to.be.true; - expectMatchSucceeded(``).to.be.true; - expectMatchSucceeded(``).to.be.true; - expectMatchSucceeded(`<{{header_type}}-header>`).to.be.true; - expectMatchSucceeded(``).to.be.true; - expectMatchSucceeded(`<-nope>`).to.be.false; - expectMatchSucceeded(`<:nope>`).to.be.false; - expectMatchSucceeded(`<1nope>`).to.be.false; - expectMatchSucceeded(`{{ product.feature }}`).to.be.true; - expectMatchSucceeded(`{{product.feature}}`).to.be.true; - expectMatchSucceeded(`{%- if A -%}`).to.be.true; - expectMatchSucceeded(`{%-if A-%}`).to.be.true; - expectMatchSucceeded(`{%- else-%}`).to.be.true; - expectMatchSucceeded(`{%- liquid-%}`).to.be.true; - expectMatchSucceeded(`{%- schema-%}`).to.be.true; - expectMatchSucceeded(`{%- form-%}`).to.be.true; - expectMatchSucceeded(`{{ true-}}`).to.be.true; - expectMatchSucceeded(` - - - {{ 'foo' | script_tag }} - - - {% if true %} -
- hello world -
- {% else %} - nope - {% endif %} - - - `).to.be.true; - expectMatchSucceeded(` - - `).to.be.true; - expectMatchSucceeded(` - - - - - - `).to.be.true; - expectMatchSucceeded(`
`).to.be.true; - expectMatchSucceeded('').to.be.true; - expectMatchSucceeded('').to.be.true; - expectMatchSucceeded('<6h>').to.be.false; + grammars.forEach(({ mode, grammar }) => { + describe(`Case: ${mode}`, () => { + it('should parse or not parse HTML+Liquid', () => { + expectMatchSucceeded('
').to.be.true; + expectMatchSucceeded('').to.be.true; + expectMatchSucceeded('').to.be.true; + expectMatchSucceeded(``).to.be.true; + expectMatchSucceeded(``).to.be.true; + expectMatchSucceeded(`<{{header_type}}-header>`).to.be.true; + expectMatchSucceeded(``).to.be.true; + expectMatchSucceeded(`<-nope>`).to.be.false; + expectMatchSucceeded(`<:nope>`).to.be.false; + expectMatchSucceeded(`<1nope>`).to.be.false; + expectMatchSucceeded(`{{ product.feature }}`).to.be.true; + expectMatchSucceeded(`{{product.feature}}`).to.be.true; + expectMatchSucceeded(`{%- if A -%}`).to.be.true; + expectMatchSucceeded(`{%-if A-%}`).to.be.true; + expectMatchSucceeded(`{%- else-%}`).to.be.true; + expectMatchSucceeded(`{%- break-%}`).to.be.true; + expectMatchSucceeded(`{%- continue -%}`).to.be.true; + expectMatchSucceeded(`{%- liquid-%}`).to.be.true; + expectMatchSucceeded(`{%- schema-%}{% endschema %}`).to.be.true; + expectMatchSucceeded(`{%- form 'form-type'-%}`).to.be.true; + expectMatchSucceeded(`{%- # a comment -%}`).to.be.true; + expectMatchSucceeded(`{%- javascript -%}{% endjavascript %}`).to.be.true; + expectMatchSucceeded(`{%- include 'layout' -%}`).to.be.true; + expectMatchSucceeded(`{%- layout 'full-width' -%}`).to.be.true; + expectMatchSucceeded(`{%- layout none -%}`).to.be.true; + expectMatchSucceeded(`{% render 'filename' for array as item %}`).to.be.true; + expectMatchSucceeded(`{% section 'name' %}`).to.be.true; + expectMatchSucceeded(`{% sections 'name' %}`).to.be.true; + expectMatchSucceeded(`{% style %}{% endstyle %}`).to.be.true; + expectMatchSucceeded(`{% stylesheet %}{% endstylesheet %}`).to.be.true; + expectMatchSucceeded(`{% assign variable_name = value %}`).to.be.true; + expectMatchSucceeded(` + {% capture variable %} + value + {% endcapture %} + `).to.be.true; + expectMatchSucceeded(` + {% for variable in array limit: number %} + expression + {% endfor %} + `).to.be.true; - function expectMatchSucceeded(text: string) { - const match = liquidHtmlGrammar.match(text, 'Node'); - return expect(match.succeeded()); - } - }); + expectMatchSucceeded(`{% decrement variable_name %}`).to.be.true; + expectMatchSucceeded(`{% increment variable_name %}`).to.be.true; + expectMatchSucceeded(`{{ true-}}`).to.be.true; + expectMatchSucceeded(` + + + {{ 'foo' | script_tag }} + + + {% if true %} +
+ hello world +
+ {% else %} + nope + {% endif %} + + + `).to.be.true; + expectMatchSucceeded(` + + `).to.be.true; + expectMatchSucceeded(` + + + + + + `).to.be.true; + expectMatchSucceeded(`
`).to.be + .true; + expectMatchSucceeded('').to.be.true; + expectMatchSucceeded('').to.be.true; + expectMatchSucceeded('<6h>').to.be.false; + + function expectMatchSucceeded(text: string) { + const match = grammar.LiquidHTML.match(text, 'Node'); + return expect(match.succeeded(), text); + } + }); - it('should parse or not parse {% liquid %} lines', () => { - expectMatchSucceeded(` - layout none + it('should parse or not parse {% liquid %} lines', () => { + expectMatchSucceeded(` + layout none - paginate search.results by 28 - for item in search.results - if item.object_type != 'product' - continue - endif + paginate search.results by 28 + for item in search.results + if item.object_type != 'product' + continue + endif - render 'product-item', product: item - endfor - endpaginate - `).to.be.true; + render 'product-item', product: item + endfor + endpaginate + `).to.be.true; - function expectMatchSucceeded(text: string) { - const match = liquidStatementsGrammar.match(text.trimStart(), 'Node'); - return expect(match.succeeded()); - } + function expectMatchSucceeded(text: string) { + const match = grammar.LiquidStatement.match(text.trimStart(), 'Node'); + return expect(match.succeeded(), text); + } + }); + }); }); }); diff --git a/src/parser/grammar.ts b/src/parser/grammar.ts index 4027678..c61ddf4 100644 --- a/src/parser/grammar.ts +++ b/src/parser/grammar.ts @@ -4,18 +4,26 @@ export const liquidHtmlGrammars = ohm.grammars( require('../../grammar/liquid-html.ohm.js'), ); -export const liquidGrammar = liquidHtmlGrammars['Liquid']; -export const liquidHtmlGrammar = liquidHtmlGrammars['LiquidHTML']; -export const liquidStatementsGrammar = liquidHtmlGrammars['LiquidStatement']; +export const strictGrammars = { + Liquid: liquidHtmlGrammars['StrictLiquid'], + LiquidHTML: liquidHtmlGrammars['StrictLiquidHTML'], + LiquidStatement: liquidHtmlGrammars['StrictLiquidStatement'], +}; + +export const tolerantGrammars = { + Liquid: liquidHtmlGrammars['Liquid'], + LiquidHTML: liquidHtmlGrammars['LiquidHTML'], + LiquidStatement: liquidHtmlGrammars['LiquidStatement'], +}; // see ../../grammar/liquid-html.ohm for full list export const BLOCKS = ( - liquidHtmlGrammar.rules as any + strictGrammars.LiquidHTML.rules as any ).blockName.body.factors[0].terms.map((x: any) => x.obj) as string[]; // see ../../grammar/liquid-html.ohm for full list export const VOID_ELEMENTS = ( - liquidHtmlGrammar.rules as any + strictGrammars.LiquidHTML.rules as any ).voidElementName.body.factors[0].terms.map( (x: any) => x.args[0].obj, ) as string[]; diff --git a/src/parser/stage-1-cst.ts b/src/parser/stage-1-cst.ts index 1f9e56d..0303dce 100644 --- a/src/parser/stage-1-cst.ts +++ b/src/parser/stage-1-cst.ts @@ -33,11 +33,7 @@ import { Parser } from 'prettier'; import ohm, { Node } from 'ohm-js'; import { toAST } from 'ohm-js/extras'; -import { - liquidGrammar, - liquidHtmlGrammar, - liquidHtmlGrammars, -} from '~/parser/grammar'; +import { strictGrammars, tolerantGrammars } from '~/parser/grammar'; import { LiquidHTMLCSTParsingError } from '~/parser/errors'; import { Comparators, NamedTags } from '~/types'; @@ -505,21 +501,45 @@ const markup = (i: number) => (tokens: Node[]) => tokens[i].sourceString.trim(); const markupTrimEnd = (i: number) => (tokens: Node[]) => tokens[i].sourceString.trimEnd(); -export function toLiquidHtmlCST(source: string): LiquidHtmlCST { - return toCST(source, liquidHtmlGrammar, [ +export interface CSTBuildOptions { + /** + * 'strict' will disable the Liquid parsing base cases. Which means that we will + * throw an error if we can't parse the node `markup` properly. + * + * 'tolerant' is the default case so that prettier can pretty print nodes + * that it doesn't understand. + */ + mode: 'strict' | 'tolerant'; +} + +export function toLiquidHtmlCST( + source: string, + options: CSTBuildOptions = { mode: 'tolerant' }, +): LiquidHtmlCST { + const grammars = + options.mode === 'tolerant' ? tolerantGrammars : strictGrammars; + const grammar = grammars.LiquidHTML; + return toCST(source, grammars, grammar, [ 'HelperMappings', 'LiquidMappings', 'LiquidHTMLMappings', ]); } -export function toLiquidCST(source: string): LiquidCST { - return toCST(source, liquidGrammar, ['HelperMappings', 'LiquidMappings']); +export function toLiquidCST( + source: string, + options: CSTBuildOptions = { mode: 'tolerant' }, +): LiquidCST { + const grammars = + options.mode === 'tolerant' ? tolerantGrammars : strictGrammars; + const grammar = grammars.Liquid; + return toCST(source, grammars, grammar, ['HelperMappings', 'LiquidMappings']); } function toCST( source: string, - cstGrammar: ohm.Grammar, + grammars: typeof strictGrammars, + grammar: ohm.Grammar, cstMappings: ('HelperMappings' | 'LiquidMappings' | 'LiquidHTMLMappings')[], ): T { // When we switch parser, our locStart and locEnd functions must account @@ -542,7 +562,7 @@ function toCST( source, }; - const res = cstGrammar.match(source, 'Node'); + const res = grammar.match(source, 'Node'); if (res.failed()) { throw new LiquidHTMLCSTParsingError(res); } @@ -625,6 +645,7 @@ function toCST( }, liquidTagOpen: 0, + liquidTagOpenStrict: 0, liquidTagOpenBaseCase: 0, liquidTagOpenRule: { type: ConcreteNodeTypes.LiquidTagOpen, @@ -658,6 +679,8 @@ function toCST( locEnd, source, }, + liquidTagBreak: 0, + liquidTagContinue: 0, liquidTagOpenTablerow: 0, liquidTagOpenPaginate: 0, liquidTagOpenPaginateMarkup: { @@ -676,6 +699,7 @@ function toCST( liquidTagOpenIf: 0, liquidTagOpenUnless: 0, liquidTagElsif: 0, + liquidTagElse: 0, liquidTagOpenConditionalMarkup: 0, condition: { type: ConcreteNodeTypes.Condition, @@ -706,6 +730,7 @@ function toCST( }, liquidTag: 0, + liquidTagStrict: 0, liquidTagBaseCase: 0, liquidTagAssign: 0, liquidTagEcho: 0, @@ -737,7 +762,7 @@ function toCST( liquidTagLiquid: 0, liquidTagLiquidMarkup(tagMarkup: Node) { - const res = liquidHtmlGrammars['LiquidStatement'].match( + const res = grammars['LiquidStatement'].match( tagMarkup.sourceString, 'Node', ); diff --git a/src/parser/stage-2-ast.spec.ts b/src/parser/stage-2-ast.spec.ts index 9336e50..cfded1b 100644 --- a/src/parser/stage-2-ast.spec.ts +++ b/src/parser/stage-2-ast.spec.ts @@ -571,7 +571,7 @@ describe('Unit: Stage 2 (AST)', () => { }); it(`${title} - should parse liquid case as branches`, () => { - ast = toAST(`{% case A %}{% when A %}A{% when "B" %}B{% else %}C{% endcase %}`); + ast = toAST(`{% case A %}{% when A %}A{% when "B" %}B{% else %}C{% endcase %}`); expectPath(ast, 'children.0').to.exist; expectPath(ast, 'children.0.type').to.eql('LiquidTag'); expectPath(ast, 'children.0.name').to.eql('case'); @@ -599,6 +599,7 @@ describe('Unit: Stage 2 (AST)', () => { expectPath(ast, 'children.0.children.3.type').to.eql('LiquidBranch'); expectPath(ast, 'children.0.children.3.name').to.eql('else'); + expectPath(ast, 'children.0.children.3.markup').to.eql(''); expectPath(ast, 'children.0.children.3.children.0.type').to.eql('TextNode'); expectPath(ast, 'children.0.children.3.children.0.value').to.eql('C'); }); diff --git a/src/parser/stage-2-ast.ts b/src/parser/stage-2-ast.ts index 3582271..127c2b8 100644 --- a/src/parser/stage-2-ast.ts +++ b/src/parser/stage-2-ast.ts @@ -532,7 +532,19 @@ export interface ASTNode { source: string; } -interface AstBuildOptions { +interface ASTBuildOptions { + /** + * Whether the parser should throw if the document node isn't closed + */ + allowUnclosedDocumentNode: boolean; + + /** + * 'strict' will disable the Liquid parsing base cases. Which means that we will + * throw an error if we can't parse the node `markup` properly. + * + * 'tolerant' is the default case so that prettier can pretty print nodes + * that it doesn't understand. + */ mode: 'strict' | 'tolerant'; } @@ -562,12 +574,18 @@ function isConcreteLiquidBranchDisguisedAsTag( ); } -export function toLiquidAST(source: string) { - const cst = toLiquidCST(source); +export function toLiquidAST( + source: string, + options: ASTBuildOptions = { + allowUnclosedDocumentNode: true, + mode: 'tolerant', + }, +) { + const cst = toLiquidCST(source, { mode: options.mode }); const root: DocumentNode = { type: NodeTypes.Document, source: source, - children: cstToAst(cst, { mode: 'tolerant' }), + children: cstToAst(cst, options), name: '#document', position: { start: 0, @@ -577,12 +595,18 @@ export function toLiquidAST(source: string) { return root; } -export function toLiquidHtmlAST(source: string): DocumentNode { +export function toLiquidHtmlAST( + source: string, + options: ASTBuildOptions = { + allowUnclosedDocumentNode: false, + mode: 'tolerant', + }, +): DocumentNode { const cst = toLiquidHtmlCST(source); const root: DocumentNode = { type: NodeTypes.Document, source: source, - children: cstToAst(cst, { mode: 'strict' }), + children: cstToAst(cst, options), name: '#document', position: { start: 0, @@ -752,14 +776,13 @@ function getName( export function cstToAst( cst: LiquidHtmlCST | LiquidCST | ConcreteAttributeNode[], - options: AstBuildOptions, + options: ASTBuildOptions, ): LiquidHtmlNode[] { if (cst.length === 0) return []; const builder = buildAst(cst, options); - const isStrictParser = options.mode === 'strict'; - if (isStrictParser && builder.cursor.length !== 0) { + if (!options.allowUnclosedDocumentNode && builder.cursor.length !== 0) { throw new LiquidHTMLASTParsingError( `Attempting to end parsing before ${builder.parent?.type} '${getName( builder.parent, @@ -775,7 +798,7 @@ export function cstToAst( function buildAst( cst: LiquidHtmlCST | LiquidCST | ConcreteAttributeNode[], - options: AstBuildOptions, + options: ASTBuildOptions, ) { const builder = new ASTBuilder(cst[0].source); @@ -985,14 +1008,14 @@ function toAttributePosition( function toAttributeValue( value: (ConcreteLiquidNode | ConcreteTextNode)[], - options: AstBuildOptions, + options: ASTBuildOptions, ): (LiquidNode | TextNode)[] { return cstToAst(value, options) as (LiquidNode | TextNode)[]; } function toAttributes( attrList: ConcreteAttributeNode[], - options: AstBuildOptions, + options: ASTBuildOptions, ): AttributeNode[] { return cstToAst(attrList, options) as AttributeNode[]; } @@ -1026,7 +1049,7 @@ function liquidBranchBaseAttributes( function toLiquidTag( node: ConcreteLiquidTag | ConcreteLiquidTagOpen, - options: AstBuildOptions & { isBlockTag: boolean }, + options: ASTBuildOptions & { isBlockTag: boolean }, ): LiquidTag | LiquidBranch { if (typeof node.markup !== 'string') { return toNamedLiquidTag(node as ConcreteLiquidTagNamed, options); @@ -1047,7 +1070,7 @@ function toLiquidTag( function toNamedLiquidTag( node: ConcreteLiquidTagNamed | ConcreteLiquidTagOpenNamed, - options: AstBuildOptions, + options: ASTBuildOptions, ): LiquidTagNamed | LiquidBranchNamed { switch (node.name) { case NamedTags.echo: { @@ -1559,7 +1582,7 @@ function toNamedArgument( function toHtmlElement( node: ConcreteHtmlTagOpen, - options: AstBuildOptions, + options: ASTBuildOptions, ): HtmlElement { return { type: NodeTypes.HtmlElement, @@ -1575,7 +1598,7 @@ function toHtmlElement( function toHtmlDanglingMarkerOpen( node: ConcreteHtmlTagOpen, - options: AstBuildOptions, + options: ASTBuildOptions, ): HtmlDanglingMarkerOpen { return { type: NodeTypes.HtmlDanglingMarkerOpen, @@ -1589,7 +1612,7 @@ function toHtmlDanglingMarkerOpen( function toHtmlDanglingMarkerClose( node: ConcreteHtmlTagClose, - options: AstBuildOptions, + options: ASTBuildOptions, ): HtmlDanglingMarkerClose { return { type: NodeTypes.HtmlDanglingMarkerClose, @@ -1602,7 +1625,7 @@ function toHtmlDanglingMarkerClose( function toHtmlVoidElement( node: ConcreteHtmlVoidElement, - options: AstBuildOptions, + options: ASTBuildOptions, ): HtmlVoidElement { return { type: NodeTypes.HtmlVoidElement, @@ -1616,7 +1639,7 @@ function toHtmlVoidElement( function toHtmlSelfClosingElement( node: ConcreteHtmlSelfClosingElement, - options: AstBuildOptions, + options: ASTBuildOptions, ): HtmlSelfClosingElement { return { type: NodeTypes.HtmlSelfClosingElement, diff --git a/test/liquid-tag-break/fixed.liquid b/test/liquid-tag-break/fixed.liquid new file mode 100644 index 0000000..4a941e3 --- /dev/null +++ b/test/liquid-tag-break/fixed.liquid @@ -0,0 +1,17 @@ +It should strip extraneous whitespace +printWidth: 1 +{% for i in col %} + {% break %} +{% endfor %} + +It should support missing whitespace +printWidth: 1 +{% for i in col %} + {%- break -%} +{% endfor %} + +It should strip extraneous args +printWidth: 1 +{% for i in col %} + {% break %} +{% endfor %} diff --git a/test/liquid-tag-break/index.liquid b/test/liquid-tag-break/index.liquid new file mode 100644 index 0000000..1359a72 --- /dev/null +++ b/test/liquid-tag-break/index.liquid @@ -0,0 +1,11 @@ +It should strip extraneous whitespace +printWidth: 1 +{% for i in col %} {% break %} {% endfor %} + +It should support missing whitespace +printWidth: 1 +{% for i in col %} {%-break-%} {% endfor %} + +It should strip extraneous args +printWidth: 1 +{% for i in col %} {% break huh?? %} {% endfor %} diff --git a/test/liquid-tag-break/index.spec.ts b/test/liquid-tag-break/index.spec.ts new file mode 100644 index 0000000..4587999 --- /dev/null +++ b/test/liquid-tag-break/index.spec.ts @@ -0,0 +1,6 @@ +import { assertFormattedEqualsFixed } from '../test-helpers'; +import * as path from 'path'; + +describe(`Unit: ${path.basename(__dirname)}`, () => { + assertFormattedEqualsFixed(__dirname); +}); diff --git a/test/liquid-tag-continue/fixed.liquid b/test/liquid-tag-continue/fixed.liquid new file mode 100644 index 0000000..7898077 --- /dev/null +++ b/test/liquid-tag-continue/fixed.liquid @@ -0,0 +1,17 @@ +It should strip extraneous whitespace +printWidth: 1 +{% for i in col %} + {% continue %} +{% endfor %} + +It should support missing whitespace +printWidth: 1 +{% for i in col %} + {%- continue -%} +{% endfor %} + +It should strip extraneous args +printWidth: 1 +{% for i in col %} + {% continue %} +{% endfor %} diff --git a/test/liquid-tag-continue/index.liquid b/test/liquid-tag-continue/index.liquid new file mode 100644 index 0000000..46fc2f8 --- /dev/null +++ b/test/liquid-tag-continue/index.liquid @@ -0,0 +1,11 @@ +It should strip extraneous whitespace +printWidth: 1 +{% for i in col %} {% continue %} {% endfor %} + +It should support missing whitespace +printWidth: 1 +{% for i in col %} {%-continue-%} {% endfor %} + +It should strip extraneous args +printWidth: 1 +{% for i in col %} {% continue huh?? %} {% endfor %} diff --git a/test/liquid-tag-continue/index.spec.ts b/test/liquid-tag-continue/index.spec.ts new file mode 100644 index 0000000..4587999 --- /dev/null +++ b/test/liquid-tag-continue/index.spec.ts @@ -0,0 +1,6 @@ +import { assertFormattedEqualsFixed } from '../test-helpers'; +import * as path from 'path'; + +describe(`Unit: ${path.basename(__dirname)}`, () => { + assertFormattedEqualsFixed(__dirname); +}); diff --git a/test/liquid-tag-else/fixed.liquid b/test/liquid-tag-else/fixed.liquid new file mode 100644 index 0000000..d873094 --- /dev/null +++ b/test/liquid-tag-else/fixed.liquid @@ -0,0 +1,20 @@ +It should strip extraneous whitespace +printWidth: 1 +{% if false %} +{% else %} + hello +{% endif %} + +It should support missing whitespace +printWidth: 1 +{% if false %} +{%- else -%} + hello +{% endif %} + +It should strip extraneous args +printWidth: 1 +{% if false %} +{% else %} + hello +{% endif %} diff --git a/test/liquid-tag-else/index.liquid b/test/liquid-tag-else/index.liquid new file mode 100644 index 0000000..eb2e6cf --- /dev/null +++ b/test/liquid-tag-else/index.liquid @@ -0,0 +1,11 @@ +It should strip extraneous whitespace +printWidth: 1 +{% if false %} {% else %} hello {% endif %} + +It should support missing whitespace +printWidth: 1 +{% if false %} {%-else-%} hello {% endif %} + +It should strip extraneous args +printWidth: 1 +{% if false %} {% else huh?? %} hello {% endif %} diff --git a/test/liquid-tag-else/index.spec.ts b/test/liquid-tag-else/index.spec.ts new file mode 100644 index 0000000..4587999 --- /dev/null +++ b/test/liquid-tag-else/index.spec.ts @@ -0,0 +1,6 @@ +import { assertFormattedEqualsFixed } from '../test-helpers'; +import * as path from 'path'; + +describe(`Unit: ${path.basename(__dirname)}`, () => { + assertFormattedEqualsFixed(__dirname); +});