Skip to content

Commit 722a261

Browse files
authored
(fix) blank if tag content (#449)
if-blocks can contain the `<` operator, which mistakingly is parsed as a "open tag" character by the html parser. To prevent this, just replace the whole content inside the if with whitespace. #326 Also remove the `i` modifier from regex because {#If or {#IF are not valid.
1 parent 00a1179 commit 722a261

File tree

2 files changed

+55
-7
lines changed

2 files changed

+55
-7
lines changed

packages/language-server/src/lib/documents/utils.ts

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,31 @@ function parseHtml(text: string) {
4444
return parser.parseHTMLDocument(<any>{ getText: () => text });
4545
}
4646

47-
const regexIf = new RegExp('{#if\\s.*?}', 'igms');
48-
const regexIfEnd = new RegExp('{/if}', 'igms');
49-
const regexEach = new RegExp('{#each\\s.*?}', 'igms');
50-
const regexEachEnd = new RegExp('{/each}', 'igms');
51-
const regexAwait = new RegExp('{#await\\s.*?}', 'igms');
52-
const regexAwaitEnd = new RegExp('{/await}', 'igms');
53-
const regexHtml = new RegExp('{@html\\s.*?', 'igms');
47+
const regexIf = new RegExp('{#if\\s.*?}', 'gms');
48+
const regexIfElseIf = new RegExp('{:else if\\s.*?}', 'gms');
49+
const regexIfEnd = new RegExp('{/if}', 'gms');
50+
const regexEach = new RegExp('{#each\\s.*?}', 'gms');
51+
const regexEachEnd = new RegExp('{/each}', 'gms');
52+
const regexAwait = new RegExp('{#await\\s.*?}', 'gms');
53+
const regexAwaitEnd = new RegExp('{/await}', 'gms');
54+
const regexHtml = new RegExp('{@html\\s.*?', 'gms');
55+
56+
/**
57+
* if-blocks can contain the `<` operator, which mistakingly is
58+
* parsed as a "open tag" character by the html parser.
59+
* To prevent this, just replace the whole content inside the if with whitespace.
60+
*/
61+
function blankIfBlocks(text: string): string {
62+
return text
63+
.replace(regexIf, (substr) => {
64+
return '{#if' + substr.replace(/[^\n]/g, ' ').substring(4, substr.length - 1) + '}';
65+
})
66+
.replace(regexIfElseIf, (substr) => {
67+
return (
68+
'{:else if' + substr.replace(/[^\n]/g, ' ').substring(9, substr.length - 1) + '}'
69+
);
70+
});
71+
}
5472

5573
/**
5674
* Extracts a tag (style or script) from the given text
@@ -60,6 +78,7 @@ const regexHtml = new RegExp('{@html\\s.*?', 'igms');
6078
* @param tag the tag to extract
6179
*/
6280
function extractTags(text: string, tag: 'script' | 'style'): TagInformation[] {
81+
text = blankIfBlocks(text);
6382
const rootNodes = parseHtml(text).roots;
6483
const matchedNodes = rootNodes
6584
.filter((node) => node.tag === tag)

packages/language-server/test/lib/documents/utils.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,35 @@ describe('document/utils', () => {
256256
},
257257
});
258258
});
259+
260+
it('extract tag correctly with #if and < operator', () => {
261+
const text = `
262+
{#if value < 3}
263+
<div>
264+
bla
265+
</div>
266+
{:else if value < 4}
267+
{/if}
268+
<script>let value = 2</script>
269+
270+
<div>
271+
{#if value < 3}
272+
<div>
273+
bla
274+
</div>
275+
{:else if value < 4}
276+
{/if}
277+
</div>`;
278+
assert.deepStrictEqual(extractScriptTags(text)?.script, {
279+
content: 'let value = 2',
280+
attributes: {},
281+
start: 159,
282+
end: 172,
283+
startPos: Position.create(7, 18),
284+
endPos: Position.create(7, 31),
285+
container: { start: 151, end: 181 },
286+
});
287+
});
259288
});
260289

261290
describe('#getLineAtPosition', () => {

0 commit comments

Comments
 (0)