Skip to content

Commit e57979e

Browse files
committedFeb 4, 2025··
stage 1/2 & prettier refactor along with extra test additions

File tree

7 files changed

+128
-45
lines changed

7 files changed

+128
-45
lines changed
 

‎.changeset/many-seahorses-smoke.md

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
'@shopify/prettier-plugin-liquid': minor
3+
'@shopify/liquid-html-parser': minor
4+
---
5+
6+
Add parsing and prettier support for example node in liquiddoc
7+
Example:
8+
9+
```liquid
10+
{% doc %}
11+
@example
12+
Here is my content
13+
{% enddoc %}
14+
```

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

+18
Original file line numberDiff line numberDiff line change
@@ -1126,6 +1126,12 @@ describe('Unit: Stage 1 (CST)', () => {
11261126
expectPath(cst, '0.children.0.type').to.equal('LiquidDocExampleNode');
11271127
expectPath(cst, '0.children.0.name').to.equal('example');
11281128
expectPath(cst, '0.children.0.exampleContent.value').to.equal('hello there');
1129+
expectPath(cst, '0.children.0.exampleContent.locStart').to.equal(
1130+
testStr.indexOf('hello there'),
1131+
);
1132+
expectPath(cst, '0.children.0.exampleContent.locEnd').to.equal(
1133+
testStr.indexOf('hello there') + 'hello there'.length,
1134+
);
11291135
});
11301136

11311137
it('should parse an example tag with a value', () => {
@@ -1176,6 +1182,18 @@ describe('Unit: Stage 1 (CST)', () => {
11761182
'hello there my friend\n This is an example\n It supports multiple lines\n',
11771183
);
11781184
});
1185+
1186+
it('should parse multiple example nodes', () => {
1187+
const testStr = `{% doc %}
1188+
@example hello there
1189+
@example second example
1190+
{% enddoc %}`;
1191+
cst = toCST(testStr);
1192+
expectPath(cst, '0.children.0.type').to.equal('LiquidDocExampleNode');
1193+
expectPath(cst, '0.children.0.exampleContent.value').to.equal('hello there\n');
1194+
expectPath(cst, '0.children.1.type').to.equal('LiquidDocExampleNode');
1195+
expectPath(cst, '0.children.1.exampleContent.value').to.equal('second example\n');
1196+
});
11791197
}
11801198
});
11811199
});

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

+21
Original file line numberDiff line numberDiff line change
@@ -1298,6 +1298,27 @@ describe('Unit: Stage 2 (AST)', () => {
12981298
'including inline code\n This is a valid example\n It can have multiple lines\n',
12991299
);
13001300

1301+
ast = toLiquidAST(`
1302+
{% doc -%}
1303+
@example
1304+
First Example
1305+
@example
1306+
Second Example
1307+
{% enddoc %}
1308+
`);
1309+
expectPath(ast, 'children.0.type').to.eql('LiquidRawTag');
1310+
expectPath(ast, 'children.0.name').to.eql('doc');
1311+
expectPath(ast, 'children.0.body.nodes.0.type').to.eql('LiquidDocExampleNode');
1312+
expectPath(ast, 'children.0.body.nodes.0.name').to.eql('example');
1313+
expectPath(ast, 'children.0.body.nodes.0.exampleContent.value').to.eql(
1314+
'\n First Example\n',
1315+
);
1316+
expectPath(ast, 'children.0.body.nodes.1.type').to.eql('LiquidDocExampleNode');
1317+
expectPath(ast, 'children.0.body.nodes.1.name').to.eql('example');
1318+
expectPath(ast, 'children.0.body.nodes.1.exampleContent.value').to.eql(
1319+
'\n Second Example\n',
1320+
);
1321+
13011322
ast = toLiquidAST(`
13021323
{% doc -%}
13031324
@example

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

+2-7
Original file line numberDiff line numberDiff line change
@@ -767,7 +767,7 @@ export interface LiquidDocParamNode extends ASTNode<NodeTypes.LiquidDocParamNode
767767
paramType: TextNode | null;
768768
}
769769

770-
/** Represents a `@example` node in a LiquidDoc comment - `@example @exampleContent` */
770+
/** Represents a `@example` node in a LiquidDoc comment - `@example exampleContent` */
771771
export interface LiquidDocExampleNode extends ASTNode<NodeTypes.LiquidDocExampleNode> {
772772
name: 'example';
773773
/** The contents of the example (e.g. "{{ product }}"). Can be multiline. */
@@ -1312,12 +1312,7 @@ function buildAst(
13121312
name: node.name,
13131313
position: position(node),
13141314
source: node.source,
1315-
exampleContent: {
1316-
type: NodeTypes.TextNode,
1317-
value: node.exampleContent.value,
1318-
position: position(node.exampleContent),
1319-
source: node.exampleContent.source,
1320-
},
1315+
exampleContent: toTextNode(node.exampleContent),
13211316
});
13221317
break;
13231318
}

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

+33-35
Original file line numberDiff line numberDiff line change
@@ -546,48 +546,46 @@ export function printLiquidDocExample(
546546
const node = path.getValue();
547547
const parts: Doc[] = ['@example'];
548548

549-
if (node.exampleContent?.value) {
550-
const content = node.exampleContent.value;
551-
if (content) {
552-
// Count leading newlines before content (\n\nmy content)
553-
const leadingNewlines = content.match(/^\n*/)?.[0]?.length ?? 0;
554-
const trimmedContent = content.trim();
555-
556-
// Push inline content to new line
549+
const content = node.exampleContent.value;
550+
if (content) {
551+
// Count leading newlines before content (\n\nmy content)
552+
const leadingNewlines = content.match(/^\n*/)?.[0]?.length ?? 0;
553+
const trimmedContent = content.trim();
554+
555+
// Push inline content to new line
556+
parts.push(hardline);
557+
558+
// If there were two or more leading newlines, push another new line
559+
if (leadingNewlines > 1) {
557560
parts.push(hardline);
561+
}
558562

559-
// If there were two or more leading newlines, push another new line
560-
if (leadingNewlines > 1) {
561-
parts.push(hardline);
562-
}
563+
// If content doesn't have newlines in it, make sure it's on a new line (not inline)
564+
if (!trimmedContent.includes('\n')) {
565+
parts.push(trimmedContent);
566+
return parts;
567+
}
563568

564-
// If content doesn't have newlines in it, make sure it's on a new line (not inline)
565-
if (!trimmedContent.includes('\n')) {
566-
parts.push(trimmedContent);
567-
return parts;
568-
}
569+
// For multi-line content
570+
const lines = trimmedContent.split('\n');
571+
const processedLines: string[] = [];
572+
let emptyLineCount = 0;
573+
574+
for (let i = 0; i < lines.length; i++) {
575+
const line = lines[i].trim();
569576

570-
// For multi-line content
571-
const lines = trimmedContent.split('\n');
572-
const processedLines: string[] = [];
573-
let emptyLineCount = 0;
574-
575-
for (let i = 0; i < lines.length; i++) {
576-
const line = lines[i].trim();
577-
578-
if (line === '') {
579-
emptyLineCount++;
580-
if (emptyLineCount <= 2) {
581-
processedLines.push('');
582-
}
583-
} else {
584-
emptyLineCount = 0;
585-
processedLines.push(line);
577+
if (line === '') {
578+
emptyLineCount++;
579+
if (emptyLineCount <= 2) {
580+
processedLines.push('');
586581
}
582+
} else {
583+
emptyLineCount = 0;
584+
processedLines.push(line);
587585
}
588-
589-
parts.push(join(hardline, processedLines));
590586
}
587+
588+
parts.push(join(hardline, processedLines));
591589
}
592590

593591
return parts;

‎packages/prettier-plugin-liquid/src/test/liquid-doc/fixed.liquid

+19-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ It should allow multiple empty lines between content
5656
with a single empty line
5757
{% enddoc %}
5858

59-
It should remove empty lines at the end of the content
59+
It should remove empty lines at the end of the example content
6060
{% doc %}
6161
@example
6262
@@ -70,3 +70,21 @@ It should respect example content with param and description
7070
7171
This is a valid example
7272
{% enddoc %}
73+
74+
It should allow multiple example nodes
75+
{% doc %}
76+
@example
77+
First Example
78+
@example
79+
Second Example
80+
{% enddoc %}
81+
82+
It should default to two lines between example content when there are three or more new lines
83+
{% doc %}
84+
@example
85+
86+
There are three lines between me and the next line
87+
88+
89+
It will format down to two lines
90+
{% enddoc %}

‎packages/prettier-plugin-liquid/src/test/liquid-doc/index.liquid

+21-2
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ It should allow single empty lines between content
4343
See?
4444
{% enddoc %}
4545

46-
It should allow multiple empty lines between content
46+
It should allow multiple empty lines between example content
4747
{% doc %}
4848
@example
4949
@@ -55,7 +55,7 @@ It should allow multiple empty lines between content
5555
with a single empty line
5656
{% enddoc %}
5757

58-
It should remove empty lines at the end of the content
58+
It should remove empty lines at the end of the example content
5959
{% doc %}
6060
@example
6161
@@ -70,3 +70,22 @@ It should respect example content with param and description
7070
7171
This is a valid example
7272
{% enddoc %}
73+
74+
It should allow multiple example nodes
75+
{% doc %}
76+
@example
77+
First Example
78+
@example
79+
Second Example
80+
{% enddoc %}
81+
82+
It should default to two lines between example content when there are three or more new lines
83+
{% doc %}
84+
@example
85+
86+
There are three lines between me and the next line
87+
88+
89+
90+
It will format down to two lines
91+
{% enddoc %}

0 commit comments

Comments
 (0)
Please sign in to comment.