UNPKG

typescript-lit-html-plugin

Version:

TypeScript language service plugin that adds IntelliSense for html tagged templates

189 lines 7.57 kB
"use strict"; /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Original code forked from https://github.com/vscode-langservers/vscode-html-languageserver/ Object.defineProperty(exports, "__esModule", { value: true }); exports.getDocumentRegions = exports.CSS_STYLE_RULE = void 0; const vscode_html_languageservice_1 = require("vscode-html-languageservice"); exports.CSS_STYLE_RULE = '__'; /** * For template expressions, typescript-template-language-service-decorator * will replace them with placeholder `x`'s, when the line does not consist only of * expressions and whitespace. * * This regex can be used to check if CSS content contains only expressions and whitspace. */ const onlyPlaceholdersRegex = /^ *x{3,}( *x{3,})* *$/; function getDocumentRegions(languageService, document) { const regions = []; const scanner = languageService.createScanner(document.getText()); let lastTagName = ''; let lastAttributeName = null; let languageIdFromType; const importedScripts = []; let token = scanner.scan(); while (token !== vscode_html_languageservice_1.TokenType.EOS) { switch (token) { case vscode_html_languageservice_1.TokenType.StartTag: lastTagName = scanner.getTokenText(); lastAttributeName = null; languageIdFromType = 'javascript'; break; case vscode_html_languageservice_1.TokenType.Styles: regions.push({ languageId: 'css', start: scanner.getTokenOffset(), end: scanner.getTokenEnd(), onlyPlaceholders: onlyPlaceholdersRegex.test(scanner.getTokenText()), }); break; case vscode_html_languageservice_1.TokenType.Script: regions.push({ languageId: languageIdFromType, start: scanner.getTokenOffset(), end: scanner.getTokenEnd(), onlyPlaceholders: onlyPlaceholdersRegex.test(scanner.getTokenText()), }); break; case vscode_html_languageservice_1.TokenType.AttributeName: lastAttributeName = scanner.getTokenText(); break; case vscode_html_languageservice_1.TokenType.AttributeValue: if (lastAttributeName === 'src' && lastTagName.toLowerCase() === 'script') { let value = scanner.getTokenText(); if (value[0] === '\'' || value[0] === '"') { value = value.substr(1, value.length - 1); } importedScripts.push(value); } else if (lastAttributeName === 'type' && lastTagName.toLowerCase() === 'script') { if (/["'](module|(text|application)\/(java|ecma)script)["']/.test(scanner.getTokenText())) { languageIdFromType = 'javascript'; } else { languageIdFromType = void 0; } } else { const attributeLanguageId = getAttributeLanguage(lastAttributeName); if (attributeLanguageId) { let start = scanner.getTokenOffset(); let end = scanner.getTokenEnd(); const firstChar = document.getText()[start]; if (firstChar === '\'' || firstChar === '"') { start++; end--; } const onlyPlaceholders = onlyPlaceholdersRegex.test(document.getText().slice(start, end)); regions.push({ languageId: attributeLanguageId, start, end, onlyPlaceholders, attributeValue: true, }); } } lastAttributeName = null; break; } token = scanner.scan(); } return { getEmbeddedDocument: (languageId, ignoreAttributeValues) => getEmbeddedDocument(document, regions, languageId, ignoreAttributeValues), getLanguageAtPosition: (position) => getLanguageAtPosition(document, regions, position), }; } exports.getDocumentRegions = getDocumentRegions; function getLanguageAtPosition(document, regions, position) { const offset = document.offsetAt(position); for (const region of regions) { if (region.start <= offset) { if (offset <= region.end) { return region.languageId; } } else { break; } } return 'html'; } function getEmbeddedDocument(document, contents, languageId, ignoreAttributeValues) { let currentPos = 0; const oldContent = document.getText(); let result = ''; let lastSuffix = ''; for (const c of contents) { if (c.languageId === languageId && (!ignoreAttributeValues || !c.attributeValue)) { result = substituteWithWhitespace(result, currentPos, c.start, oldContent, lastSuffix, getPrefix(c)); result += oldContent.substring(c.start, c.end) .replace(onlyPlaceholdersRegex, match => ' '.repeat(match.length)); currentPos = c.end; lastSuffix = getSuffix(c); } } result = substituteWithWhitespace(result, currentPos, oldContent.length, oldContent, lastSuffix, ''); return vscode_html_languageservice_1.TextDocument.create(document.uri, languageId, document.version, result); } function getPrefix(c) { if (c.attributeValue && !c.onlyPlaceholders) { switch (c.languageId) { case 'css': return exports.CSS_STYLE_RULE + '{'; } } return ''; } function getSuffix(c) { if (c.attributeValue && !c.onlyPlaceholders) { switch (c.languageId) { case 'css': return '}'; case 'javascript': return ';'; } } return ''; } function substituteWithWhitespace(result, start, end, oldContent, before, after) { let accumulatedWS = 0; result += before; for (let i = start + before.length; i < end; i++) { const ch = oldContent[i]; if (ch === '\n' || ch === '\r') { // only write new lines, skip the whitespace accumulatedWS = 0; result += ch; } else { accumulatedWS++; } } result = append(result, ' ', accumulatedWS - after.length); result += after; return result; } function append(result, str, n) { while (n > 0) { if (n & 1) { result += str; } n >>= 1; str += str; } return result; } function getAttributeLanguage(attributeName) { const match = attributeName.match(/^(style)$|^(on\w+)$/i); if (!match) { return null; } return match[1] ? 'css' : 'javascript'; } //# sourceMappingURL=embeddedSupport.js.map