From 12e99afb5e0deb32f0c6b7357c36d24da2470b46 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Sat, 26 Sep 2020 16:25:23 +0200 Subject: [PATCH] (fix) try to be smarter about unclosed tags Tries to parse the HTML document and work around the limitations of the underlying parser which will trip up when there's a non-closed tag and treat everything afterwards as its child. #547 --- .../src/lib/documents/utils.ts | 49 +++++++++++++++++++ .../test/lib/documents/utils.test.ts | 15 ++++++ 2 files changed, 64 insertions(+) diff --git a/packages/language-server/src/lib/documents/utils.ts b/packages/language-server/src/lib/documents/utils.ts index c3ea5f004..45440f249 100644 --- a/packages/language-server/src/lib/documents/utils.ts +++ b/packages/language-server/src/lib/documents/utils.ts @@ -44,6 +44,46 @@ const parser = getLanguageService(); * Parses text as HTML */ export function parseHtml(text: string): HTMLDocument { + const html = parseHTMLDocument(text); + return tryParse(text, html, 0) || html; +} + +/** + * Tries to parse the HTML document and work around the limitations of the underlying + * parsers which will trip up when there's a non-closed tag and treat everything afterwards as its child. + */ +function tryParse(text: string, html: HTMLDocument, run: number): HTMLDocument | null { + if (run > 5) { + // Stop before doing too much work, possibly having an endless loop + return null; + } + + let sanitizedText = text; + html.roots.forEach((node) => { + if ( + !(node).closed && + // This indicates a child tag falsely identified as an attribute + Object.keys(node.attributes || {}).some((key) => key.startsWith('<')) && + node.tag + ) { + // Replace { getText: () => text }); } @@ -332,3 +372,12 @@ export function getWordAt( return str.slice(left, right + pos); } + +export function replaceRangeWithStr( + text: string, + start: number, + end: number, + replacement: string, +): string { + return text.substring(0, start) + replacement + text.substring(end); +} diff --git a/packages/language-server/test/lib/documents/utils.test.ts b/packages/language-server/test/lib/documents/utils.test.ts index 013fc9fd0..77d09b81d 100644 --- a/packages/language-server/test/lib/documents/utils.test.ts +++ b/packages/language-server/test/lib/documents/utils.test.ts @@ -286,6 +286,21 @@ describe('document/utils', () => { container: { start: 151, end: 181 }, }); }); + + it('extract script when unclosed tag preceeding', () => { + const text = ` + let value = 2`; + assert.deepStrictEqual(extractScriptTags(text)?.script, { + content: 'let value = 2', + attributes: {}, + start: 43, + end: 56, + startPos: Position.create(2, 18), + endPos: Position.create(2, 31), + container: { start: 35, end: 65 }, + }); + }); }); describe('#getLineAtPosition', () => {