diff --git a/packages/liquid-html-parser/grammar/liquid-html.ohm b/packages/liquid-html-parser/grammar/liquid-html.ohm index 3d806237..6b1c4045 100644 --- a/packages/liquid-html-parser/grammar/liquid-html.ohm +++ b/packages/liquid-html-parser/grammar/liquid-html.ohm @@ -376,7 +376,11 @@ LiquidStatement <: Liquid { liquidStatementEnd = newline | end delimTag := liquidStatementEnd -} +} + +LiquidDoc <: Helpers { + Node := (TextNode)* +} LiquidHTML <: Liquid { Node := yamlFrontmatter? (HtmlNode | liquidNode | TextNode)* diff --git a/packages/liquid-html-parser/src/grammar.ts b/packages/liquid-html-parser/src/grammar.ts index ab673506..79675ad7 100644 --- a/packages/liquid-html-parser/src/grammar.ts +++ b/packages/liquid-html-parser/src/grammar.ts @@ -3,6 +3,7 @@ import ohm from 'ohm-js'; export const liquidHtmlGrammars = ohm.grammars(require('../grammar/liquid-html.ohm.js')); export const TextNodeGrammar = liquidHtmlGrammars['Helpers']; +export const LiquidDocGrammar = liquidHtmlGrammars['LiquidDoc']; export interface LiquidGrammars { Liquid: ohm.Grammar; diff --git a/packages/liquid-html-parser/src/stage-1-cst.spec.ts b/packages/liquid-html-parser/src/stage-1-cst.spec.ts index 3d366609..71ae05a6 100644 --- a/packages/liquid-html-parser/src/stage-1-cst.spec.ts +++ b/packages/liquid-html-parser/src/stage-1-cst.spec.ts @@ -994,13 +994,15 @@ describe('Unit: Stage 1 (CST)', () => { expectPath(cst, '0.blockStartLocEnd').to.equal(0 + '{% doc -%}'.length); expectPath(cst, '0.blockEndLocStart').to.equal(testStr.length - '{%- enddoc %}'.length); expectPath(cst, '0.blockEndLocEnd').to.equal(testStr.length); - expectPath(cst, '0.children').to.deep.equal({ - locEnd: 35, - locStart: 11, - source: '{% doc -%} Renders loading-spinner. {%- enddoc %}', - type: 'LiquidDocBody', - description: 'Renders loading-spinner.', - }); + expectPath(cst, '0.children').to.deep.equal([ + { + locEnd: 25, + locStart: 1, + source: '{% doc -%} Renders loading-spinner. {%- enddoc %}', + type: 'TextNode', + value: 'Renders loading-spinner.', + }, + ]); } }); diff --git a/packages/liquid-html-parser/src/stage-1-cst.ts b/packages/liquid-html-parser/src/stage-1-cst.ts index b158fb66..2bb9bfa8 100644 --- a/packages/liquid-html-parser/src/stage-1-cst.ts +++ b/packages/liquid-html-parser/src/stage-1-cst.ts @@ -34,6 +34,7 @@ import { Parser } from 'prettier'; import ohm, { Node } from 'ohm-js'; import { toAST } from 'ohm-js/extras'; import { + LiquidDocGrammar, LiquidGrammars, TextNodeGrammar, placeholderGrammars, @@ -81,7 +82,6 @@ export enum ConcreteNodeTypes { RenderMarkup = 'RenderMarkup', PaginateMarkup = 'PaginateMarkup', RenderVariableExpression = 'RenderVariableExpression', - LiquidDocBody = 'LiquidDocBody', } export const LiquidLiteralValues = { @@ -504,13 +504,7 @@ function toCST( source: string /* the original file */, grammars: LiquidGrammars, grammar: ohm.Grammar, - cstMappings: ( - | 'HelperMappings' - | 'LiquidMappings' - | 'LiquidHTMLMappings' - | 'LiquidStatement' - | 'LiquidDocMappings' - )[], + cstMappings: ('HelperMappings' | 'LiquidMappings' | 'LiquidHTMLMappings' | 'LiquidStatement')[], matchingSource: string = source /* for subtree parsing */, offset: number = 0 /* for subtree parsing location offsets */, ): T { @@ -638,11 +632,8 @@ function toCST( body: (tokens: Node[]) => tokens[1].sourceString, children: (tokens: Node[]) => { const contentNode = tokens[1]; - return toCST( + return toLiquidDocAST( source, - grammars, - grammars.Liquid, - ['LiquidDocMappings'], contentNode.sourceString, offset + contentNode.source.startIdx, ); @@ -1108,15 +1099,24 @@ function toCST( }; const LiquidDocMappings: Mapping = { - Node: { - type: ConcreteNodeTypes.LiquidDocBody, - locStart, - locEnd, - source, - description: (tokens: Node[]) => tokens[0].sourceString, - }, + Node: 0, + TextNode: textNode, }; + function toLiquidDocAST(source: string, matchingSource: string, offset: number) { + const res = LiquidDocGrammar.match(matchingSource, 'Node'); + if (res.failed()) { + throw new LiquidHTMLCSTParsingError(res); + } + + const LiquidDocMappings: Mapping = { + Node: 0, + TextNode: textNode, + }; + + return toAST(res, LiquidDocMappings); + } + const LiquidHTMLMappings: Mapping = { Node(frontmatter: Node, nodes: Node) { const self = this as any; @@ -1272,7 +1272,6 @@ function toCST( LiquidMappings, LiquidHTMLMappings, LiquidStatement, - LiquidDocMappings, }; const selectedMappings = cstMappings.reduce( diff --git a/packages/liquid-html-parser/src/stage-2-ast.spec.ts b/packages/liquid-html-parser/src/stage-2-ast.spec.ts index a2310496..d88a557e 100644 --- a/packages/liquid-html-parser/src/stage-2-ast.spec.ts +++ b/packages/liquid-html-parser/src/stage-2-ast.spec.ts @@ -1225,11 +1225,14 @@ describe('Unit: Stage 2 (AST)', () => { expectPath(ast, 'children.0.type').to.eql('LiquidRawTag'); expectPath(ast, 'children.0.name').to.eql('doc'); expectPath(ast, 'children.0.body.value').to.eql(''); + expectPath(ast, 'children.0.body.type').toEqual('RawMarkup'); + expectPath(ast, 'children.0.body.nodes').toEqual([]); ast = toLiquidAST(`{% doc -%} single line doc {%- enddoc %}`); expectPath(ast, 'children.0.type').to.eql('LiquidRawTag'); expectPath(ast, 'children.0.name').to.eql('doc'); expectPath(ast, 'children.0.body.value').to.eql(' single line doc '); + expectPath(ast, 'children.0.body.nodes.0.type').toEqual('TextNode'); ast = toLiquidAST(`{% doc -%} multi line doc @@ -1237,9 +1240,10 @@ describe('Unit: Stage 2 (AST)', () => { {%- enddoc %}`); expectPath(ast, 'children.0.type').to.eql('LiquidRawTag'); expectPath(ast, 'children.0.name').to.eql('doc'); - expectPath(ast, 'children.0.body.source').to.eql( - '{% doc -%}\n multi line doc\n multi line doc\n {%- enddoc %}', + expectPath(ast, 'children.0.body.nodes.0.value').to.eql( + `multi line doc\n multi line doc`, ); + expectPath(ast, 'children.0.body.nodes.0.type').toEqual('TextNode'); }); it('should parse unclosed tables with assignments', () => {