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 74d55134e..674834571 100644 --- a/packages/liquid-html-parser/src/stage-1-cst.spec.ts +++ b/packages/liquid-html-parser/src/stage-1-cst.spec.ts @@ -980,16 +980,16 @@ describe('Unit: Stage 1 (CST)', () => { it('should parse doc tags', () => { for (const { toCST, expectPath } of testCases) { - const testStr = `{% doc -%} - @param asdf - @unsupported - {%- enddoc %}`; + const testStr = + '{% doc -%} @param asdf\n@unsupported this tag should fall back {%- enddoc %}'; cst = toCST(testStr); expectPath(cst, '0.type').to.equal('LiquidRawTag'); expectPath(cst, '0.name').to.equal('doc'); - expectPath(cst, '0.body').to.include('@param asdf'); + expectPath(cst, '0.body').to.equal( + ' @param asdf\n@unsupported this tag should fall back ', + ); expectPath(cst, '0.whitespaceStart').to.equal(''); expectPath(cst, '0.whitespaceEnd').to.equal('-'); expectPath(cst, '0.delimiterWhitespaceStart').to.equal('-'); @@ -1006,7 +1006,7 @@ describe('Unit: Stage 1 (CST)', () => { expectPath(cst, '0.children.1.type').to.equal('TextNode'); expectPath(cst, '0.children.1.locStart').to.equal(testStr.indexOf('@unsupported')); expectPath(cst, '0.children.1.locEnd').to.equal( - testStr.indexOf('@unsupported') + '@unsupported'.length, + testStr.indexOf('@unsupported') + '@unsupported this tag should fall back '.length, ); } }); diff --git a/packages/liquid-html-parser/src/stage-1-cst.ts b/packages/liquid-html-parser/src/stage-1-cst.ts index 4cbf7f3b2..9debfb798 100644 --- a/packages/liquid-html-parser/src/stage-1-cst.ts +++ b/packages/liquid-html-parser/src/stage-1-cst.ts @@ -1306,14 +1306,27 @@ function toLiquidDocAST(source: string, matchingSource: string, offset: number) const LiquidDocMappings: Mapping = { Node: 0, + textNode: { + type: ConcreteNodeTypes.TextNode, + value: function () { + return (this as any).sourceString; + }, + locStart, + locEnd, + source, + }, paramNode: { type: ConcreteNodeTypes.LiquidDocParamNode, + name: 0, locStart, locEnd, source, }, fallbackNode: { type: ConcreteNodeTypes.TextNode, + value: function () { + return (this as any).sourceString; + }, locStart, locEnd, source, 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 84848ccb2..ed1c2467f 100644 --- a/packages/liquid-html-parser/src/stage-2-ast.spec.ts +++ b/packages/liquid-html-parser/src/stage-2-ast.spec.ts @@ -1229,22 +1229,21 @@ describe('Unit: Stage 2 (AST)', () => { expectPath(ast, 'children.0.body.type').toEqual('RawMarkup'); expectPath(ast, 'children.0.body.nodes').toEqual([]); - ast = toLiquidAST(`{% doc -%} single line doc {%- enddoc %}`); + ast = toLiquidAST(` + {% doc -%} + @param asdf + @unsupported this node falls back to a text node + {%- 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'); + expectPath(ast, 'children.0.body.nodes.0.type').to.eql('LiquidDocParamNode'); + expectPath(ast, 'children.0.body.nodes.0.name').to.eql('@param'); - ast = toLiquidAST(`{% doc -%} - multi line doc - multi line doc - {%- enddoc %}`); - expectPath(ast, 'children.0.type').to.eql('LiquidRawTag'); - expectPath(ast, 'children.0.name').to.eql('doc'); - expectPath(ast, 'children.0.body.nodes.0.value').to.eql( - `multi line doc\n multi line doc`, + expectPath(ast, 'children.0.body.nodes.1.type').to.eql('TextNode'); + expectPath(ast, 'children.0.body.nodes.1.value').to.eql( + '@unsupported this node falls back to a text node', ); - expectPath(ast, 'children.0.body.nodes.0.type').toEqual('TextNode'); }); it('should parse unclosed tables with assignments', () => { diff --git a/packages/liquid-html-parser/src/stage-2-ast.ts b/packages/liquid-html-parser/src/stage-2-ast.ts index 15c7e61cb..370f08790 100644 --- a/packages/liquid-html-parser/src/stage-2-ast.ts +++ b/packages/liquid-html-parser/src/stage-2-ast.ts @@ -73,6 +73,7 @@ import { LiquidHtmlConcreteNode, ConcreteLiquidTagBaseCase, ConcreteLiquidTagContentForMarkup, + LiquidDocCST, } from './stage-1-cst'; import { Comparators, NamedTags, NodeTypes, nonTraversableProperties, Position } from './types'; import { assertNever, deepGet, dropLast } from './utils'; @@ -107,7 +108,8 @@ export type LiquidHtmlNode = | RenderVariableExpression | LiquidLogicalExpression | LiquidComparison - | TextNode; + | TextNode + | LiquidDocParamNode; /** The root node of all LiquidHTML ASTs. */ export interface DocumentNode extends ASTNode { @@ -754,6 +756,10 @@ export interface TextNode extends ASTNode { value: string; } +export interface LiquidDocParamNode extends ASTNode { + name: string; +} + export interface ASTNode { /** * The type of the node, as a string. @@ -1103,7 +1109,7 @@ export function cstToAst( } function buildAst( - cst: LiquidHtmlCST | LiquidCST | ConcreteAttributeNode[], + cst: LiquidHtmlCST | LiquidCST | LiquidDocCST | ConcreteAttributeNode[], options: ASTBuildOptions, ) { const builder = new ASTBuilder(cst[0].source); @@ -1268,6 +1274,16 @@ function buildAst( break; } + case ConcreteNodeTypes.LiquidDocParamNode: { + builder.push({ + type: NodeTypes.LiquidDocParamNode, + name: node.name, + position: position(node), + source: node.source, + }); + break; + } + default: { assertNever(node); } diff --git a/packages/liquid-html-parser/src/types.ts b/packages/liquid-html-parser/src/types.ts index 29648aebb..49efa1bf3 100644 --- a/packages/liquid-html-parser/src/types.ts +++ b/packages/liquid-html-parser/src/types.ts @@ -44,6 +44,7 @@ export enum NodeTypes { RawMarkup = 'RawMarkup', RenderMarkup = 'RenderMarkup', RenderVariableExpression = 'RenderVariableExpression', + LiquidDocParamNode = 'LiquidDocParamNode', } // These are officially supported with special node types