vscode-gem-languageservice
Version:
Language service for Gem
221 lines (213 loc) • 9.06 kB
JavaScript
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