UNPKG

svelte-language-server

Version:
160 lines 6.79 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseHtml = parseHtml; exports.getAttributeContextAtPosition = getAttributeContextAtPosition; const vscode_html_languageservice_1 = require("vscode-html-languageservice"); const utils_1 = require("./utils"); const parser = (0, vscode_html_languageservice_1.getLanguageService)(); /** * Parses text as HTML */ function parseHtml(text) { const preprocessed = preprocess(text); // We can safely only set getText because only this is used for parsing const parsedDoc = parser.parseHTMLDocument({ getText: () => preprocessed }); return parsedDoc; } const createScanner = parser.createScanner; /** * scan the text and remove any `>` or `<` that cause the tag to end short, */ function preprocess(text) { let scanner = createScanner(text); let token = scanner.scan(); let currentStartTagStart = null; let moustacheCheckStart = 0; let moustacheCheckEnd = 0; let lastToken = token; while (token !== vscode_html_languageservice_1.TokenType.EOS) { const offset = scanner.getTokenOffset(); let blanked = false; switch (token) { case vscode_html_languageservice_1.TokenType.StartTagOpen: if (shouldBlankStartOrEndTagLike(offset)) { blankStartOrEndTagLike(offset); blanked = true; } else { currentStartTagStart = offset; } break; case vscode_html_languageservice_1.TokenType.StartTagClose: if (shouldBlankStartOrEndTagLike(offset)) { blankStartOrEndTagLike(offset); blanked = true; } else { currentStartTagStart = null; } break; case vscode_html_languageservice_1.TokenType.StartTagSelfClose: currentStartTagStart = null; break; // <Foo checked={a < 1}> // https://github.com/microsoft/vscode-html-languageservice/blob/71806ef57be07e1068ee40900ef8b0899c80e68a/src/parser/htmlScanner.ts#L327 case vscode_html_languageservice_1.TokenType.Unknown: if (scanner.getScannerState() === vscode_html_languageservice_1.ScannerState.WithinTag && scanner.getTokenText() === '<' && shouldBlankStartOrEndTagLike(offset)) { blankStartOrEndTagLike(offset); blanked = true; } break; case vscode_html_languageservice_1.TokenType.Content: { moustacheCheckEnd = scanner.getTokenEnd(); if (token !== lastToken) { moustacheCheckStart = offset; } break; } } // blanked, so the token type is invalid if (!blanked) { lastToken = token; } token = scanner.scan(); } return text; function shouldBlankStartOrEndTagLike(offset) { if (currentStartTagStart != null) { return (0, utils_1.isInsideMoustacheTag)(text, currentStartTagStart, offset); } const index = text .substring(moustacheCheckStart, moustacheCheckEnd) .lastIndexOf('{', offset); const lastMustacheTagStart = index === -1 ? null : moustacheCheckStart + index; if (lastMustacheTagStart == null) { return false; } return (0, utils_1.isInsideMoustacheTag)(text.substring(lastMustacheTagStart), null, offset - lastMustacheTagStart); } function blankStartOrEndTagLike(offset) { text = text.substring(0, offset) + ' ' + text.substring(offset + 1); scanner = createScanner(text, offset, currentStartTagStart != null ? vscode_html_languageservice_1.ScannerState.WithinTag : vscode_html_languageservice_1.ScannerState.WithinContent); } } function getAttributeContextAtPosition(document, position) { const offset = document.offsetAt(position); const { html } = document; const tag = html.findNodeAt(offset); if (!inStartTag(offset, tag) || !tag.attributes) { return null; } const text = document.getText(); const beforeStartTagEnd = text.substring(0, tag.start) + preprocess(text.substring(tag.start, tag.startTagEnd)); const scanner = createScanner(beforeStartTagEnd, tag.start); let token = scanner.scan(); let currentAttributeName; const inTokenRange = () => scanner.getTokenOffset() <= offset && offset <= scanner.getTokenEnd(); while (token != vscode_html_languageservice_1.TokenType.EOS) { // adopted from https://github.com/microsoft/vscode-html-languageservice/blob/2f7ae4df298ac2c299a40e9024d118f4a9dc0c68/src/services/htmlCompletion.ts#L402 if (token === vscode_html_languageservice_1.TokenType.AttributeName) { currentAttributeName = scanner.getTokenText(); if (inTokenRange()) { return { elementTag: tag, name: currentAttributeName, inValue: false }; } } else if (token === vscode_html_languageservice_1.TokenType.DelimiterAssign) { if (scanner.getTokenEnd() === offset && currentAttributeName) { const nextToken = scanner.scan(); return { elementTag: tag, name: currentAttributeName, inValue: true, valueRange: [ offset, nextToken === vscode_html_languageservice_1.TokenType.AttributeValue ? scanner.getTokenEnd() : offset ] }; } } else if (token === vscode_html_languageservice_1.TokenType.AttributeValue) { if (inTokenRange() && currentAttributeName) { let start = scanner.getTokenOffset(); let end = scanner.getTokenEnd(); const char = text[start]; if (char === '"' || char === "'") { start++; end--; } return { elementTag: tag, name: currentAttributeName, inValue: true, valueRange: [start, end] }; } currentAttributeName = undefined; } token = scanner.scan(); } return null; } function inStartTag(offset, node) { return offset > node.start && node.startTagEnd != undefined && offset < node.startTagEnd; } //# sourceMappingURL=parseHtml.js.map