Skip to content

Commit be6edd1

Browse files
committed
added snippet tags in stage 1 and stage 2
1 parent 1cbd8ad commit be6edd1

File tree

7 files changed

+74
-0
lines changed

7 files changed

+74
-0
lines changed

.changeset/dull-jobs-tap.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@shopify/prettier-plugin-liquid': minor
3+
'@shopify/liquid-html-parser': minor
4+
---
5+
6+
Added parsing support for the `snippet` tag by updating the ohm rules

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,17 @@ describe('Unit: Stage 1 (CST)', () => {
794794
});
795795
});
796796

797+
it('should parse snippet arguments as a singular liquid variable lookup', () => {
798+
const expression = `var`;
799+
const type = 'VariableLookup';
800+
for (const { toCST, expectPath } of testCases) {
801+
cst = toCST(`{% snippet ${expression} -%}`);
802+
expectPath(cst, '0.type').to.equal('LiquidTagOpen');
803+
expectPath(cst, '0.name').to.equal('snippet');
804+
expectPath(cst, '0.markup.type').to.equal(type);
805+
}
806+
});
807+
797808
it('should parse when arguments as an array of liquid expressions', () => {
798809
[
799810
{ expression: `"string"`, args: [{ type: 'String' }] },

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ export type ConcreteLiquidTagOpen = ConcreteLiquidTagOpenBaseCase | ConcreteLiqu
237237
export type ConcreteLiquidTagOpenNamed =
238238
| ConcreteLiquidTagOpenCase
239239
| ConcreteLiquidTagOpenCapture
240+
| ConcreteLiquidTagOpenSnippet
240241
| ConcreteLiquidTagOpenIf
241242
| ConcreteLiquidTagOpenUnless
242243
| ConcreteLiquidTagOpenForm
@@ -254,6 +255,8 @@ export interface ConcreteLiquidTagOpenBaseCase extends ConcreteLiquidTagOpenNode
254255

255256
export interface ConcreteLiquidTagOpenCapture
256257
extends ConcreteLiquidTagOpenNode<NamedTags.capture, ConcreteLiquidVariableLookup> {}
258+
export interface ConcreteLiquidTagOpenSnippet
259+
extends ConcreteLiquidTagOpenNode<NamedTags.snippet, ConcreteLiquidVariableLookup> {}
257260

258261
export interface ConcreteLiquidTagOpenCase
259262
extends ConcreteLiquidTagOpenNode<NamedTags.case, ConcreteLiquidExpression> {}
@@ -746,6 +749,7 @@ function toCST<T>(
746749
},
747750

748751
liquidTagOpenCapture: 0,
752+
liquidTagOpenSnippet: 0,
749753
liquidTagOpenForm: 0,
750754
liquidTagOpenFormMarkup: 0,
751755
liquidTagOpenFor: 0,

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,25 @@ describe('Unit: Stage 2 (AST)', () => {
637637
});
638638
});
639639

640+
it('should parse snippet blocks', () => {
641+
for (const { toAST, expectPath, expectPosition } of testCases) {
642+
ast = toAST(`{% snippet hello_snippet %}{% echo "Hello content" %}{% endsnippet %}`);
643+
expectPath(ast, 'children.0').to.exist;
644+
expectPath(ast, 'children.0.type').to.eql('LiquidTag');
645+
expectPath(ast, 'children.0.name').to.eql('snippet');
646+
expectPath(ast, 'children.0.markup.type').to.eql('VariableLookup');
647+
expectPath(ast, 'children.0.markup.name').to.eql('hello_snippet');
648+
649+
expectPath(ast, 'children.0.children.0.type').to.eql('LiquidTag');
650+
expectPath(ast, 'children.0.children.0.name').to.eql('echo');
651+
expectPath(ast, 'children.0.children.0.markup.type').to.eql('LiquidVariable');
652+
expectPath(ast, 'children.0.children.0.markup.expression.value').to.eql('Hello content');
653+
654+
expectPosition(ast, 'children.0');
655+
expectPosition(ast, 'children.0.markup');
656+
}
657+
});
658+
640659
describe('Case: content_for', () => {
641660
it('should parse content_for tags with no arguments', () => {
642661
for (const { toAST, expectPath, expectPosition } of testCases) {
@@ -1230,6 +1249,25 @@ describe('Unit: Stage 2 (AST)', () => {
12301249
expectPosition(ast, 'children.0.body.nodes.2').toEqual('}');
12311250
expectPosition(ast, 'children.0');
12321251
});
1252+
1253+
it('should parse snippet blocks with HTML content', () => {
1254+
ast = toLiquidHtmlAST(
1255+
`{% snippet hello_snippet %}<div class="component"><p>Hello</p></div>{% endsnippet %}`,
1256+
);
1257+
expectPath(ast, 'children.0.type').to.eql('LiquidTag');
1258+
expectPath(ast, 'children.0.name').to.eql('snippet');
1259+
expectPath(ast, 'children.0.markup.type').to.eql('VariableLookup');
1260+
expectPath(ast, 'children.0.markup.name').to.eql('hello_snippet');
1261+
expectPath(ast, 'children.0.children.0.type').to.eql('HtmlElement');
1262+
expectPath(ast, 'children.0.children.0.name.0.value').to.eql('div');
1263+
expectPath(ast, 'children.0.children.0.attributes.0.name.0.value').to.eql('class');
1264+
expectPath(ast, 'children.0.children.0.attributes.0.value.0.value').to.eql('component');
1265+
expectPath(ast, 'children.0.children.0.children.0.type').to.eql('HtmlElement');
1266+
expectPath(ast, 'children.0.children.0.children.0.name.0.value').to.eql('p');
1267+
expectPath(ast, 'children.0.children.0.children.0.children.0.type').to.eql('TextNode');
1268+
expectPath(ast, 'children.0.children.0.children.0.children.0.value').to.eql('Hello');
1269+
expectPosition(ast, 'children.0');
1270+
});
12331271
});
12341272

12351273
describe('Unit: toLiquidAST(text)', () => {

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ export type LiquidTagNamed =
212212
| LiquidTagRender
213213
| LiquidTagSection
214214
| LiquidTagSections
215+
| LiquidTagSnippet
215216
| LiquidTagTablerow
216217
| LiquidTagUnless;
217218

@@ -278,6 +279,9 @@ export interface LiquidTagDecrement
278279
/** https://shopify.dev/docs/api/liquid/tags#capture */
279280
export interface LiquidTagCapture extends LiquidTagNode<NamedTags.capture, LiquidVariableLookup> {}
280281

282+
/** https://shopify.dev/docs/api/liquid/tags#snippet */
283+
export interface LiquidTagSnippet extends LiquidTagNode<NamedTags.snippet, LiquidVariableLookup> {}
284+
281285
/** https://shopify.dev/docs/api/liquid/tags#cycle */
282286
export interface LiquidTagCycle extends LiquidTagNode<NamedTags.cycle, CycleMarkup> {}
283287

@@ -1544,6 +1548,15 @@ function toNamedLiquidTag(
15441548
};
15451549
}
15461550

1551+
case NamedTags.snippet: {
1552+
return {
1553+
...liquidTagBaseAttributes(node),
1554+
name: node.name,
1555+
markup: toExpression(node.markup) as LiquidVariableLookup,
1556+
children: [],
1557+
};
1558+
}
1559+
15471560
case NamedTags.content_for: {
15481561
return {
15491562
...liquidTagBaseAttributes(node),

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export enum NamedTags {
7070
layout = 'layout',
7171
liquid = 'liquid',
7272
paginate = 'paginate',
73+
snippet = 'snippet',
7374
render = 'render',
7475
section = 'section',
7576
sections = 'sections',

packages/prettier-plugin-liquid/src/printer/print/liquid.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ function printNamedLiquidBlockStart(
189189
}
190190

191191
case NamedTags.capture:
192+
case NamedTags.snippet:
192193
case NamedTags.increment:
193194
case NamedTags.decrement:
194195
case NamedTags.layout:

0 commit comments

Comments
 (0)