yaml-language-server
Version:
223 lines • 8.63 kB
JavaScript
;
/*---------------------------------------------------------------------------------------------
* Copyright (c) Red Hat, Inc. All rights reserved.
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.YAMLDocumentSymbols = void 0;
const vscode_languageserver_types_1 = require("vscode-languageserver-types");
const yaml_documents_1 = require("../parser/yaml-documents");
const yaml_1 = require("yaml");
class YAMLDocumentSymbols {
constructor(telemetry) {
this.telemetry = telemetry;
}
findDocumentSymbols(document, context = { resultLimit: Number.MAX_VALUE }) {
let results = [];
try {
const doc = yaml_documents_1.yamlDocumentsCache.getYamlDocument(document);
if (!doc || doc.documents.length === 0) {
return null;
}
for (const yamlDoc of doc.documents) {
if (yamlDoc.root) {
results = results.concat(this.findFlatDocumentSymbols(document, yamlDoc.root, context));
}
}
}
catch (err) {
this.telemetry?.sendError('yaml.documentSymbols.error', err);
}
return results;
}
findHierarchicalDocumentSymbols(document, context = { resultLimit: Number.MAX_VALUE }) {
let results = [];
try {
const doc = yaml_documents_1.yamlDocumentsCache.getYamlDocument(document);
if (!doc || doc.documents.length === 0) {
return null;
}
for (const yamlDoc of doc.documents) {
if (yamlDoc.root) {
results = results.concat(this.findHierarchicalSymbols(document, yamlDoc.root, context));
}
}
}
catch (err) {
this.telemetry?.sendError('yaml.hierarchicalDocumentSymbols.error', err);
}
return results;
}
findFlatDocumentSymbols(document, root, context) {
let limit = context.resultLimit || Number.MAX_VALUE;
const toVisit = [{ node: root, containerName: '' }];
let nextToVisit = 0;
let limitExceeded = false;
const result = [];
const collectOutlineEntries = (node, containerName) => {
if (node.type === 'array') {
node.items.forEach((item) => {
if (item) {
toVisit.push({ node: item, containerName });
}
});
}
else if (node.type === 'object') {
node.properties.forEach((property) => {
const valueNode = property.valueNode;
if (!valueNode) {
return;
}
if (limit > 0) {
limit--;
const location = vscode_languageserver_types_1.Location.create(document.uri, getRange(document, property));
const childContainerName = containerName ? containerName + '.' + property.keyNode.value : property.keyNode.value;
result.push({
name: getKeyLabel(property),
kind: getSymbolKind(valueNode.type),
location,
containerName,
});
toVisit.push({ node: valueNode, containerName: childContainerName });
}
else {
limitExceeded = true;
}
});
}
};
while (nextToVisit < toVisit.length) {
const next = toVisit[nextToVisit++];
collectOutlineEntries(next.node, next.containerName);
}
if (limitExceeded) {
context.onResultLimitExceeded?.(document.uri);
}
return result;
}
findHierarchicalSymbols(document, root, context) {
let limit = context.resultLimit || Number.MAX_VALUE;
const result = [];
const toVisit = [{ node: root, result }];
let nextToVisit = 0;
let limitExceeded = false;
const collectOutlineEntries = (node, result) => {
if (node.type === 'array') {
node.items.forEach((item, index) => {
if (!item) {
return;
}
if (limit > 0) {
limit--;
const range = getRange(document, item);
const symbol = {
name: String(index),
kind: getSymbolKind(item.type),
range,
selectionRange: range,
children: [],
};
result.push(symbol);
toVisit.push({ result: symbol.children, node: item });
}
else {
limitExceeded = true;
}
});
}
else if (node.type === 'object') {
node.properties.forEach((property) => {
const valueNode = property.valueNode;
if (!valueNode) {
return;
}
if (limit > 0) {
limit--;
const children = [];
const symbol = {
name: getKeyLabel(property),
kind: getSymbolKind(valueNode.type),
range: getRange(document, property),
selectionRange: getRange(document, property.keyNode),
children,
detail: getDetail(valueNode),
};
result.push(symbol);
toVisit.push({ result: children, node: valueNode });
}
else {
limitExceeded = true;
}
});
}
};
while (nextToVisit < toVisit.length) {
const next = toVisit[nextToVisit++];
collectOutlineEntries(next.node, next.result);
}
if (limitExceeded) {
context.onResultLimitExceeded?.(document.uri);
}
return result;
}
}
exports.YAMLDocumentSymbols = YAMLDocumentSymbols;
function getSymbolKind(nodeType) {
switch (nodeType) {
case 'object':
return vscode_languageserver_types_1.SymbolKind.Module;
case 'string':
return vscode_languageserver_types_1.SymbolKind.String;
case 'number':
return vscode_languageserver_types_1.SymbolKind.Number;
case 'array':
return vscode_languageserver_types_1.SymbolKind.Array;
case 'boolean':
return vscode_languageserver_types_1.SymbolKind.Boolean;
default:
return vscode_languageserver_types_1.SymbolKind.Variable;
}
}
function getKeyLabel(property) {
const keyNode = property.keyNode.internalNode;
let name;
if ((0, yaml_1.isMap)(keyNode)) {
name = '{}';
}
else if ((0, yaml_1.isSeq)(keyNode)) {
name = '[]';
}
else if ('source' in keyNode && typeof keyNode.source === 'string') {
name = keyNode.source;
}
else {
name = property.keyNode.value;
}
if (name) {
name = name.replace(/[\n]/g, '↵');
}
if (name && name.trim()) {
return name;
}
return `"${name}"`;
}
function getDetail(node) {
if (!node) {
return undefined;
}
if (node.type === 'boolean' || node.type === 'number' || node.type === 'null' || node.type === 'string') {
return String(node.value);
}
if (node.type === 'array') {
return node.children.length ? undefined : '[]';
}
if (node.type === 'object') {
return node.children.length ? undefined : '{}';
}
return undefined;
}
function getRange(document, node) {
return vscode_languageserver_types_1.Range.create(document.positionAt(node.offset), document.positionAt(node.offset + node.length));
}
//# sourceMappingURL=documentSymbols.js.map