UNPKG

vscode-gem-languageservice

Version:
221 lines (213 loc) 9.06 kB
#!/usr/bin/env node var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); // src/index.ts var import_vscode_languageserver_textdocument2 = require("vscode-languageserver-textdocument"); var import_node2 = require("vscode-languageserver/node"); // src/provider.ts var import_css_color_keywords = __toESM(require("css-color-keywords")); var import_color = require("duoyun-ui/lib/color"); var import_types = require("duoyun-ui/lib/types"); var import_node = require("vscode-languageserver/node"); // src/global.ts var import_vscode_css_languageservice = require("@mantou/vscode-css-languageservice"); var import_vscode_html_languageservice = require("@mantou/vscode-html-languageservice"); var import_cache2 = require("duoyun-ui/lib/cache"); // src/documents.ts var import_cache = require("duoyun-ui/lib/cache"); var import_tree_sitter = __toESM(require("tree-sitter")); var import_tree_sitter_typescript = __toESM(require("tree-sitter-typescript")); var import_vscode_languageserver_textdocument = require("vscode-languageserver-textdocument"); var language = import_tree_sitter_typescript.default.typescript; function processTemplate({ children }) { return { startIndex: children[1].startIndex, text: children.slice(1, -1).reduce((p, c) => p + (c.type === "template_substitution" ? c.text.replaceAll(/./g, "_") : c.text), "") }; } var CSTDocs = class extends WeakMap { #cssCache = new import_cache.Cache({ max: 1e3 }); #htmlCache = new import_cache.Cache({ max: 1e3 }); getTypeScriptCST(textDocument) { const parser = new import_tree_sitter.default(); parser.setLanguage(language); const oldTree = this.get(textDocument); if (oldTree?.getText(oldTree.rootNode) === textDocument.getText()) return oldTree; const newTree = parser.parse(textDocument.getText()); this.set(textDocument, newTree); return newTree; } getAllTemplate(textDocument, tag) { const tree = this.getTypeScriptCST(textDocument); const query = new import_tree_sitter.default.Query( language, ` (call_expression function: (identifier) @tag (#eq? @tag "${tag}") arguments: (template_string) @injection.content ) ` ); const matches = query.matches(tree.rootNode); const templateStrings = matches.map(({ captures }) => captures.pop().node); return templateStrings.map(processTemplate); } getStyles(textDocument) { const tree = this.getTypeScriptCST(textDocument); const query = new import_tree_sitter.default.Query( language, ` (call_expression function: (identifier) @_name (#eq? @_name "css") arguments: (arguments (object (pair value: (template_string) @injection.content ))) ) ` ); const matches = query.matches(tree.rootNode); const templateStrings = matches.map(({ captures }) => captures.pop().node); return templateStrings.map(processTemplate); } getAllStyleValue(textDocument) { const tree = this.getTypeScriptCST(textDocument); const query = new import_tree_sitter.default.Query( language, ` (call_expression function: (identifier) @_name (#eq? @_name "styleMap") arguments: (arguments (object (pair value: (string (string_fragment) @injection.content) ))) ) ` ); const matches = query.matches(tree.rootNode); return matches.map(({ captures }) => captures.pop().node); } getAllCSS(textDocument) { return this.getAllTemplate(textDocument, "css").map((e) => { const doc = import_vscode_languageserver_textdocument.TextDocument.create(``, "css", 1, e.text); const cssDoc = this.#cssCache.get(e.text, () => cssLanguageService.parseStylesheet(doc)); return { ...e, doc, cssDoc }; }); } getAllCSSFragment(textDocument) { return [...this.getAllTemplate(textDocument, "styled"), ...this.getStyles(textDocument)].map((e) => { const doc = import_vscode_languageserver_textdocument.TextDocument.create(``, "css", 1, `.parent {${e.text}}`); const cssDoc = this.#cssCache.get(e.text, () => cssLanguageService.parseStylesheet(doc)); return { ...e, startIndex: e.startIndex - 9, doc, cssDoc }; }); } getAllHTML(textDocument) { return this.getAllTemplate(textDocument, "html").map((e) => { const doc = import_vscode_languageserver_textdocument.TextDocument.create(``, "html", 1, e.text); const htmlDoc = this.#htmlCache.get(e.text, () => htmlLanguageService.parseHTMLDocument(doc)); return { ...e, doc, htmlDoc }; }); } }; // src/global.ts var cssLanguageService = (0, import_vscode_css_languageservice.getCSSLanguageService)(); var htmlLanguageService = (0, import_vscode_html_languageservice.getLanguageService)(); var documents = new CSTDocs(); var cssCache = new import_cache2.Cache({ max: 1e3 }); var htmlCache = new import_cache2.Cache({ max: 1e3 }); // src/provider.ts var Provider = class { provideDocumentColors(document) { return [ // NOTE: ignore `<style>` ...[...documents.getAllCSS(document), ...documents.getAllCSSFragment(document)].flatMap( ({ doc, startIndex, cssDoc }) => { const colors = cssLanguageService.findDocumentColors(doc, cssDoc); return colors.map((e) => ({ ...e, range: { start: document.positionAt(startIndex + doc.offsetAt(e.range.start)), end: document.positionAt(startIndex + doc.offsetAt(e.range.end)) } })); } ), ...documents.getAllStyleValue(document).map(({ text, startIndex }) => { const hex = import_css_color_keywords.default[text] || text; if (!hex.startsWith("#")) return; const [red, green, blue, alpha] = (0, import_color.parseHexColor)(hex); const range = import_node.Range.create(document.positionAt(startIndex), document.positionAt(startIndex + hex.length)); const color = import_node.Color.create(red / 255, green / 255, blue / 255, alpha); return { range, color }; }).filter(import_types.isNotNullish) ]; } provideColorPresentations({ red, green, blue, alpha }) { return [{ label: (0, import_color.rgbToHexColor)([red * 255, green * 255, blue * 255, alpha]) }]; } provideDocumentSymbols(document) { return [ ...documents.getAllCSS(document).map((e) => { const symbols = cssLanguageService.findDocumentSymbols(e.doc, e.cssDoc); return { ...e, symbols }; }), ...documents.getAllHTML(document).map((e) => { const symbols = htmlLanguageService.findDocumentSymbols(e.doc, e.htmlDoc); return { ...e, symbols }; }) ].flatMap( ({ startIndex, symbols, doc }) => symbols.map((symbol) => ({ ...symbol, location: { uri: document.uri, range: { start: document.positionAt(startIndex + doc.offsetAt(symbol.location.range.start)), end: document.positionAt(startIndex + doc.offsetAt(symbol.location.range.end)) } } })) ); } }; // src/index.ts var connection = (0, import_node2.createConnection)(import_node2.ProposedFeatures.all); var documents2 = new import_node2.TextDocuments(import_vscode_languageserver_textdocument2.TextDocument); connection.onInitialize(() => { return { capabilities: { colorProvider: true, documentSymbolProvider: true } }; }); var provider = new Provider(); connection.onColorPresentation(({ color }) => { return provider.provideColorPresentations(color); }); connection.onDocumentColor(({ textDocument }) => { return provider.provideDocumentColors(documents2.get(textDocument.uri)); }); connection.onDocumentSymbol(({ textDocument }) => { return provider.provideDocumentSymbols(documents2.get(textDocument.uri)); }); documents2.listen(connection); connection.listen(); //# sourceMappingURL=index.js.map