Skip to content

Commit ee71950

Browse files
authored
Merge pull request #1039 from Shopify/bug-fix-multiple-instance-syntax-errors
Fix syntax check for tags where multiple instances of same error occur
2 parents 61545e3 + b226e52 commit ee71950

File tree

5 files changed

+71
-18
lines changed

5 files changed

+71
-18
lines changed

.changeset/weak-rules-notice.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@shopify/theme-check-common': patch
3+
---
4+
5+
Fix syntax check for tags where multiple instances of same error occur

packages/theme-check-common/src/checks/liquid-html-syntax-error/checks/InvalidEchoValue.spec.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { expect, describe, it, vi } from 'vitest';
1+
import { expect, describe, it, vi, beforeEach } from 'vitest';
22
import { applyFix, runLiquidCheck } from '../../../test';
33
import { LiquidHTMLSyntaxError } from '../index';
44
import { toLiquidAST } from '@shopify/liquid-html-parser';
@@ -17,6 +17,10 @@ vi.mock('@shopify/liquid-html-parser', async (importOriginal) => {
1717
});
1818

1919
describe('detectInvalidEchoValue', async () => {
20+
beforeEach(() => {
21+
vi.clearAllMocks();
22+
});
23+
2024
it('should not report when echo value is valid', async () => {
2125
const testCases = [
2226
`{% echo '123' %}`,
@@ -78,6 +82,27 @@ describe('detectInvalidEchoValue', async () => {
7882
}
7983
});
8084

85+
it('should report when there are multiple instances of the error', async () => {
86+
const sourceCode = `{% echo zero %} {% echo one two %} {% echo one two %}`;
87+
88+
const offenses = await runLiquidCheck(LiquidHTMLSyntaxError, sourceCode);
89+
expect(offenses).to.have.length(2);
90+
expect(offenses[0].message).to.equal('Syntax is not supported');
91+
expect(offenses[1].message).to.equal('Syntax is not supported');
92+
93+
expect(toLiquidAST).toHaveBeenCalledTimes(2);
94+
expect(toLiquidAST).toHaveBeenCalledWith(`{% echo one %}`, {
95+
allowUnclosedDocumentNode: false,
96+
mode: 'strict',
97+
});
98+
99+
const fixed = applyFix(sourceCode, offenses[0]);
100+
expect(fixed).to.equal(`{% echo zero %} {% echo one %} {% echo one two %}`);
101+
102+
const fixed2 = applyFix(sourceCode, offenses[1]);
103+
expect(fixed2).to.equal(`{% echo zero %} {% echo one two %} {% echo one %}`);
104+
});
105+
81106
it('should report when there is no value', async () => {
82107
const testCases = [
83108
[`{% echo | upcase %}`, '{% echo blank %}'],

packages/theme-check-common/src/checks/liquid-html-syntax-error/checks/InvalidEchoValue.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,30 +48,27 @@ export function detectInvalidEchoValue(
4848
};
4949
}
5050

51-
const removalIndices = (source: string) => {
52-
const offset = source.indexOf(markup);
51+
const removalIndices = (source: string, startingIndex: number) => {
52+
const offset = source.indexOf(markup, startingIndex);
5353

5454
return {
5555
startIndex: offset + firstEchoValue.length,
5656
endIndex: offset + echoValue.trimEnd().length,
5757
};
5858
};
5959

60-
const tagSource = node.source.slice(node.position.start, node.position.end);
61-
const { startIndex: tagSourceRemovalStartIndex, endIndex: tagSourceRemovalEndIndex } =
62-
removalIndices(tagSource);
60+
const { startIndex, endIndex } = removalIndices(node.source, node.position.start);
6361

6462
if (
6563
!ensureValidAst(
66-
tagSource.slice(0, tagSourceRemovalStartIndex) + tagSource.slice(tagSourceRemovalEndIndex),
64+
node.source.slice(node.position.start, startIndex) +
65+
node.source.slice(endIndex, node.position.end),
6766
)
6867
) {
6968
// If the new AST is invalid, we don't want to auto-fix it
7069
return;
7170
}
7271

73-
const { startIndex, endIndex } = removalIndices(node.source);
74-
7572
return {
7673
message: INVALID_SYNTAX_MESSAGE,
7774
startIndex,

packages/theme-check-common/src/checks/liquid-html-syntax-error/checks/MultipleAssignValues.spec.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { expect, describe, it, vi } from 'vitest';
1+
import { expect, describe, it, vi, beforeEach } from 'vitest';
22
import { applyFix, runLiquidCheck } from '../../../test';
33
import { LiquidHTMLSyntaxError } from '../index';
44
import { toLiquidAST } from '@shopify/liquid-html-parser';
@@ -17,6 +17,10 @@ vi.mock('@shopify/liquid-html-parser', async (importOriginal) => {
1717
});
1818

1919
describe('detectMultipleAssignValues', async () => {
20+
beforeEach(() => {
21+
vi.clearAllMocks();
22+
});
23+
2024
it('should not report when there are no trailing values', async () => {
2125
const testCases = [`{% assign foo = '123' %}`, `{% assign foo = '123' | upcase %}`];
2226

@@ -44,6 +48,31 @@ describe('detectMultipleAssignValues', async () => {
4448
}
4549
});
4650

51+
it('should report when there are multiple instances of the error', async () => {
52+
const sourceCode = `{% assign foo = blank %} {% assign foo = '123' 555 text %} {% assign foo = '123' 555 text %}`;
53+
54+
const offenses = await runLiquidCheck(LiquidHTMLSyntaxError, sourceCode);
55+
expect(offenses).to.have.length(2);
56+
expect(offenses[0].message).to.equal('Syntax is not supported');
57+
expect(offenses[1].message).to.equal('Syntax is not supported');
58+
59+
expect(toLiquidAST).toHaveBeenCalledTimes(2);
60+
expect(toLiquidAST).toHaveBeenCalledWith(`{% assign foo = '123' %}`, {
61+
allowUnclosedDocumentNode: false,
62+
mode: 'strict',
63+
});
64+
65+
const fixed = applyFix(sourceCode, offenses[0]);
66+
expect(fixed).to.equal(
67+
`{% assign foo = blank %} {% assign foo = '123' %} {% assign foo = '123' 555 text %}`,
68+
);
69+
70+
const fixed2 = applyFix(sourceCode, offenses[1]);
71+
expect(fixed2).to.equal(
72+
`{% assign foo = blank %} {% assign foo = '123' 555 text %} {% assign foo = '123' %}`,
73+
);
74+
});
75+
4776
it('should report when there are multiple values (with filters)', async () => {
4877
const testCases = [
4978
[`{% assign foo = '123' 555 text | upcase %}`, "{% assign foo = '123' | upcase %}"],

packages/theme-check-common/src/checks/liquid-html-syntax-error/checks/MultipleAssignValues.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ export function detectMultipleAssignValues(
4848
return;
4949
}
5050

51-
const removalIndices = (source: string) => {
52-
const offset = source.indexOf(markup);
51+
const removalIndices = (source: string, startingIndex: number) => {
52+
const offset = source.indexOf(markup, startingIndex);
5353

5454
return {
5555
startIndex:
@@ -65,21 +65,18 @@ export function detectMultipleAssignValues(
6565
};
6666
};
6767

68-
const tagSource = node.source.slice(node.position.start, node.position.end);
69-
const { startIndex: tagSourceRemovalStartIndex, endIndex: tagSourceRemovalEndIndex } =
70-
removalIndices(tagSource);
68+
const { startIndex, endIndex } = removalIndices(node.source, node.position.start);
7169

7270
if (
7371
!ensureValidAst(
74-
tagSource.slice(0, tagSourceRemovalStartIndex) + tagSource.slice(tagSourceRemovalEndIndex),
72+
node.source.slice(node.position.start, startIndex) +
73+
node.source.slice(endIndex, node.position.end),
7574
)
7675
) {
7776
// If the new AST is invalid, we don't want to auto-fix it
7877
return;
7978
}
8079

81-
const { startIndex, endIndex } = removalIndices(node.source);
82-
8380
return {
8481
message: INVALID_SYNTAX_MESSAGE,
8582
startIndex,

0 commit comments

Comments
 (0)