Skip to content

Commit a6b207d

Browse files
committed
Refactor: create new grammar for doc tags
LiquidDoc is essentially a new language that we are adding. Creating a new grammar allows us to directly parse and test the contents of the doc tag. This also allows us to avoid the complexity of including liquid support from within the doc tag grammar.
1 parent 84b7136 commit a6b207d

File tree

5 files changed

+40
-30
lines changed

5 files changed

+40
-30
lines changed

packages/liquid-html-parser/grammar/liquid-html.ohm

+5-1
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,11 @@ LiquidStatement <: Liquid {
376376

377377
liquidStatementEnd = newline | end
378378
delimTag := liquidStatementEnd
379-
}
379+
}
380+
381+
LiquidDoc <: Helpers {
382+
Node := (TextNode)*
383+
}
380384

381385
LiquidHTML <: Liquid {
382386
Node := yamlFrontmatter? (HtmlNode | liquidNode | TextNode)*

packages/liquid-html-parser/src/grammar.ts

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import ohm from 'ohm-js';
33
export const liquidHtmlGrammars = ohm.grammars(require('../grammar/liquid-html.ohm.js'));
44

55
export const TextNodeGrammar = liquidHtmlGrammars['Helpers'];
6+
export const LiquidDocGrammar = liquidHtmlGrammars['LiquidDoc'];
67

78
export interface LiquidGrammars {
89
Liquid: ohm.Grammar;

packages/liquid-html-parser/src/stage-1-cst.spec.ts

+9-7
Original file line numberDiff line numberDiff line change
@@ -994,13 +994,15 @@ describe('Unit: Stage 1 (CST)', () => {
994994
expectPath(cst, '0.blockStartLocEnd').to.equal(0 + '{% doc -%}'.length);
995995
expectPath(cst, '0.blockEndLocStart').to.equal(testStr.length - '{%- enddoc %}'.length);
996996
expectPath(cst, '0.blockEndLocEnd').to.equal(testStr.length);
997-
expectPath(cst, '0.children').to.deep.equal({
998-
locEnd: 35,
999-
locStart: 11,
1000-
source: '{% doc -%} Renders loading-spinner. {%- enddoc %}',
1001-
type: 'LiquidDocBody',
1002-
description: 'Renders loading-spinner.',
1003-
});
997+
expectPath(cst, '0.children').to.deep.equal([
998+
{
999+
locEnd: 25,
1000+
locStart: 1,
1001+
source: '{% doc -%} Renders loading-spinner. {%- enddoc %}',
1002+
type: 'TextNode',
1003+
value: 'Renders loading-spinner.',
1004+
},
1005+
]);
10041006
}
10051007
});
10061008

packages/liquid-html-parser/src/stage-1-cst.ts

+19-20
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import { Parser } from 'prettier';
3434
import ohm, { Node } from 'ohm-js';
3535
import { toAST } from 'ohm-js/extras';
3636
import {
37+
LiquidDocGrammar,
3738
LiquidGrammars,
3839
TextNodeGrammar,
3940
placeholderGrammars,
@@ -81,7 +82,6 @@ export enum ConcreteNodeTypes {
8182
RenderMarkup = 'RenderMarkup',
8283
PaginateMarkup = 'PaginateMarkup',
8384
RenderVariableExpression = 'RenderVariableExpression',
84-
LiquidDocBody = 'LiquidDocBody',
8585
}
8686

8787
export const LiquidLiteralValues = {
@@ -504,13 +504,7 @@ function toCST<T>(
504504
source: string /* the original file */,
505505
grammars: LiquidGrammars,
506506
grammar: ohm.Grammar,
507-
cstMappings: (
508-
| 'HelperMappings'
509-
| 'LiquidMappings'
510-
| 'LiquidHTMLMappings'
511-
| 'LiquidStatement'
512-
| 'LiquidDocMappings'
513-
)[],
507+
cstMappings: ('HelperMappings' | 'LiquidMappings' | 'LiquidHTMLMappings' | 'LiquidStatement')[],
514508
matchingSource: string = source /* for subtree parsing */,
515509
offset: number = 0 /* for subtree parsing location offsets */,
516510
): T {
@@ -638,11 +632,8 @@ function toCST<T>(
638632
body: (tokens: Node[]) => tokens[1].sourceString,
639633
children: (tokens: Node[]) => {
640634
const contentNode = tokens[1];
641-
return toCST(
635+
return toLiquidDocAST(
642636
source,
643-
grammars,
644-
grammars.Liquid,
645-
['LiquidDocMappings'],
646637
contentNode.sourceString,
647638
offset + contentNode.source.startIdx,
648639
);
@@ -1108,15 +1099,24 @@ function toCST<T>(
11081099
};
11091100

11101101
const LiquidDocMappings: Mapping = {
1111-
Node: {
1112-
type: ConcreteNodeTypes.LiquidDocBody,
1113-
locStart,
1114-
locEnd,
1115-
source,
1116-
description: (tokens: Node[]) => tokens[0].sourceString,
1117-
},
1102+
Node: 0,
1103+
TextNode: textNode,
11181104
};
11191105

1106+
function toLiquidDocAST(source: string, matchingSource: string, offset: number) {
1107+
const res = LiquidDocGrammar.match(matchingSource, 'Node');
1108+
if (res.failed()) {
1109+
throw new LiquidHTMLCSTParsingError(res);
1110+
}
1111+
1112+
const LiquidDocMappings: Mapping = {
1113+
Node: 0,
1114+
TextNode: textNode,
1115+
};
1116+
1117+
return toAST(res, LiquidDocMappings);
1118+
}
1119+
11201120
const LiquidHTMLMappings: Mapping = {
11211121
Node(frontmatter: Node, nodes: Node) {
11221122
const self = this as any;
@@ -1272,7 +1272,6 @@ function toCST<T>(
12721272
LiquidMappings,
12731273
LiquidHTMLMappings,
12741274
LiquidStatement,
1275-
LiquidDocMappings,
12761275
};
12771276

12781277
const selectedMappings = cstMappings.reduce(

packages/liquid-html-parser/src/stage-2-ast.spec.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -1225,21 +1225,25 @@ describe('Unit: Stage 2 (AST)', () => {
12251225
expectPath(ast, 'children.0.type').to.eql('LiquidRawTag');
12261226
expectPath(ast, 'children.0.name').to.eql('doc');
12271227
expectPath(ast, 'children.0.body.value').to.eql('');
1228+
expectPath(ast, 'children.0.body.type').toEqual('RawMarkup');
1229+
expectPath(ast, 'children.0.body.nodes').toEqual([]);
12281230

12291231
ast = toLiquidAST(`{% doc -%} single line doc {%- enddoc %}`);
12301232
expectPath(ast, 'children.0.type').to.eql('LiquidRawTag');
12311233
expectPath(ast, 'children.0.name').to.eql('doc');
12321234
expectPath(ast, 'children.0.body.value').to.eql(' single line doc ');
1235+
expectPath(ast, 'children.0.body.nodes.0.type').toEqual('TextNode');
12331236

12341237
ast = toLiquidAST(`{% doc -%}
12351238
multi line doc
12361239
multi line doc
12371240
{%- enddoc %}`);
12381241
expectPath(ast, 'children.0.type').to.eql('LiquidRawTag');
12391242
expectPath(ast, 'children.0.name').to.eql('doc');
1240-
expectPath(ast, 'children.0.body.source').to.eql(
1241-
'{% doc -%}\n multi line doc\n multi line doc\n {%- enddoc %}',
1243+
expectPath(ast, 'children.0.body.nodes.0.value').to.eql(
1244+
`multi line doc\n multi line doc`,
12421245
);
1246+
expectPath(ast, 'children.0.body.nodes.0.type').toEqual('TextNode');
12431247
});
12441248

12451249
it('should parse unclosed tables with assignments', () => {

0 commit comments

Comments
 (0)