Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/bright-ignore-range.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/prettier-plugin-liquid': minor
---

Add support for prettier-ignore-start / prettier-ignore-end range-based ignoring in Liquid templates
80 changes: 79 additions & 1 deletion packages/prettier-plugin-liquid/src/printer/utils/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,85 @@ export function isPrettierIgnoreNode(
}

export function hasPrettierIgnore(node: LiquidHtmlNode) {
return isPrettierIgnoreNode(node) || isPrettierIgnoreNode(node.prev);
return (
isPrettierIgnoreNode(node) ||
isPrettierIgnoreNode(node.prev) ||
isPrettierIgnoreRangeStartNode(node) ||
isPrettierIgnoreRangeEndNode(node) ||
isInsidePrettierIgnoreRange(node)
);
}

export function isPrettierIgnoreRangeStartHtmlNode(
node: LiquidHtmlNode | undefined,
): node is HtmlComment {
return (
!!node &&
node.type === NodeTypes.HtmlComment &&
/^\s*prettier-ignore-start(?=\s|$)/m.test(node.body)
);
}

export function isPrettierIgnoreRangeStartLiquidNode(
node: LiquidHtmlNode | undefined,
): node is LiquidTag {
return (
!!node &&
node.type === NodeTypes.LiquidTag &&
node.name === '#' &&
/^\s*prettier-ignore-start(?=\s|$)/m.test(node.markup)
);
}

export function isPrettierIgnoreRangeStartNode(
node: LiquidHtmlNode | undefined,
): node is HtmlComment | LiquidTag {
return isPrettierIgnoreRangeStartHtmlNode(node) || isPrettierIgnoreRangeStartLiquidNode(node);
}

export function isPrettierIgnoreRangeEndHtmlNode(
node: LiquidHtmlNode | undefined,
): node is HtmlComment {
return (
!!node &&
node.type === NodeTypes.HtmlComment &&
/^\s*prettier-ignore-end(?=\s|$)/m.test(node.body)
);
}

export function isPrettierIgnoreRangeEndLiquidNode(
node: LiquidHtmlNode | undefined,
): node is LiquidTag {
return (
!!node &&
node.type === NodeTypes.LiquidTag &&
node.name === '#' &&
/^\s*prettier-ignore-end(?=\s|$)/m.test(node.markup)
);
}

export function isPrettierIgnoreRangeEndNode(
node: LiquidHtmlNode | undefined,
): node is HtmlComment | LiquidTag {
return isPrettierIgnoreRangeEndHtmlNode(node) || isPrettierIgnoreRangeEndLiquidNode(node);
}

/**
* Walk backward through siblings to determine if a node is inside an
* unmatched prettier-ignore-start / prettier-ignore-end range.
*/
export function isInsidePrettierIgnoreRange(node: LiquidHtmlNode): boolean {
let current = node.prev;
while (current) {
if (isPrettierIgnoreRangeEndNode(current)) {
return false;
}
if (isPrettierIgnoreRangeStartNode(current)) {
return true;
}
current = current.prev;
}
return false;
}

function getPrettierIgnoreAttributeCommentData(value: string): boolean {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
It should preserve formatting inside html prettier-ignore-start / prettier-ignore-end range
<!-- prettier-ignore-start -->
<div class="custom-layout">
{{ some_variable | complicated_filter: foo: bar }}
{% render 'component', foo: bar %}
</div>
<!-- prettier-ignore-end -->

It should preserve formatting inside liquid comment prettier-ignore-start / prettier-ignore-end range
{% # prettier-ignore-start %}
<div class="custom-layout">
{{ some_variable | complicated_filter: foo: bar }}
{% render 'component', foo: bar %}
</div>
{% # prettier-ignore-end %}

It should only ignore nodes between start and end, formatting nodes outside normally
printWidth: 40
<p>{{ a | append: 'b' }}</p>
<!-- prettier-ignore-start -->
<div>{{ some_variable | complicated_filter: foo: bar }}</div>
<!-- prettier-ignore-end -->
<p>{{ a | append: 'b' }}</p>

It should handle multiple ignore ranges in the same parent
printWidth: 40
<p>{{ a | append: 'b' }}</p>
<!-- prettier-ignore-start -->
<div>{{ x | y: z }}</div>
<!-- prettier-ignore-end -->
<p>{{ a | append: 'b' }}</p>
<!-- prettier-ignore-start -->
<span>{{ m | n: o }}</span>
<!-- prettier-ignore-end -->
<p>{{ a | append: 'b' }}</p>

It should handle liquid comment ranges with multiple nodes
{% # prettier-ignore-start %}
{%capture foo%}{% for x in (0 .. 1) %}{% cycle a,b,c %}{% endfor %}{%endcapture%}
<div>{{ x | y: z }}</div>
{% # prettier-ignore-end %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
It should preserve formatting inside html prettier-ignore-start / prettier-ignore-end range
<!-- prettier-ignore-start -->
<div class="custom-layout">
{{ some_variable | complicated_filter: foo: bar }}
{% render 'component', foo: bar %}
</div>
<!-- prettier-ignore-end -->

It should preserve formatting inside liquid comment prettier-ignore-start / prettier-ignore-end range
{% # prettier-ignore-start %}
<div class="custom-layout">
{{ some_variable | complicated_filter: foo: bar }}
{% render 'component', foo: bar %}
</div>
{% # prettier-ignore-end %}

It should only ignore nodes between start and end, formatting nodes outside normally
printWidth: 40
<p>{{ a | append: 'b' }}</p>
<!-- prettier-ignore-start -->
<div>{{ some_variable | complicated_filter: foo: bar }}</div>
<!-- prettier-ignore-end -->
<p>{{ a | append: 'b' }}</p>

It should handle multiple ignore ranges in the same parent
printWidth: 40
<p>{{ a | append: 'b' }}</p>
<!-- prettier-ignore-start -->
<div>{{ x | y: z }}</div>
<!-- prettier-ignore-end -->
<p>{{ a | append: 'b' }}</p>
<!-- prettier-ignore-start -->
<span>{{ m | n: o }}</span>
<!-- prettier-ignore-end -->
<p>{{ a | append: 'b' }}</p>

It should handle liquid comment ranges with multiple nodes
{% # prettier-ignore-start %}
{%capture foo%}{% for x in (0 .. 1) %}{% cycle a,b,c %}{% endfor %}{%endcapture%}
<div>{{ x | y: z }}</div>
{% # prettier-ignore-end %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { test } from 'vitest';
import { assertFormattedEqualsFixed } from '../test-helpers';

test('Unit: prettier-ignore-start / prettier-ignore-end range', async () => {
await assertFormattedEqualsFixed(__dirname);
});
Loading