UNPKG

vscode-json-languageservice

Version:
286 lines (285 loc) 14.1 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ (function (factory) { if (typeof module === "object" && typeof module.exports === "object") { var v = factory(require, exports); if (v !== undefined) module.exports = v; } else if (typeof define === "function" && define.amd) { define(["require", "exports", "../parser/jsonParser", "../utils/strings", "../utils/colors", "@vscode/l10n", "../jsonLanguageTypes"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.JSONDocumentSymbols = void 0; const Parser = require("../parser/jsonParser"); const Strings = require("../utils/strings"); const colors_1 = require("../utils/colors"); const l10n = require("@vscode/l10n"); const jsonLanguageTypes_1 = require("../jsonLanguageTypes"); class JSONDocumentSymbols { constructor(schemaService) { this.schemaService = schemaService; } findDocumentSymbols(document, doc, context = { resultLimit: Number.MAX_VALUE }) { const root = doc.root; if (!root) { return []; } let limit = context.resultLimit || Number.MAX_VALUE; // special handling for key bindings const resourceString = document.uri; if ((resourceString === 'vscode://defaultsettings/keybindings.json') || Strings.endsWith(resourceString.toLowerCase(), '/user/keybindings.json')) { if (root.type === 'array') { const result = []; for (const item of root.items) { if (item.type === 'object') { for (const property of item.properties) { if (property.keyNode.value === 'key' && property.valueNode) { const location = jsonLanguageTypes_1.Location.create(document.uri, getRange(document, item)); result.push({ name: getName(property.valueNode), kind: jsonLanguageTypes_1.SymbolKind.Function, location: location }); limit--; if (limit <= 0) { if (context && context.onResultLimitExceeded) { context.onResultLimitExceeded(resourceString); } return result; } } } } } return result; } } const toVisit = [ { node: root, containerName: '' } ]; let nextToVisit = 0; let limitExceeded = false; const result = []; const collectOutlineEntries = (node, containerName) => { if (node.type === 'array') { node.items.forEach(node => { if (node) { toVisit.push({ node, containerName }); } }); } else if (node.type === 'object') { node.properties.forEach((property) => { const valueNode = property.valueNode; if (valueNode) { if (limit > 0) { limit--; const location = jsonLanguageTypes_1.Location.create(document.uri, getRange(document, property)); const childContainerName = containerName ? containerName + '.' + property.keyNode.value : property.keyNode.value; result.push({ name: this.getKeyLabel(property), kind: this.getSymbolKind(valueNode.type), location: location, containerName: containerName }); toVisit.push({ node: valueNode, containerName: childContainerName }); } else { limitExceeded = true; } } }); } }; // breath first traversal while (nextToVisit < toVisit.length) { const next = toVisit[nextToVisit++]; collectOutlineEntries(next.node, next.containerName); } if (limitExceeded && context && context.onResultLimitExceeded) { context.onResultLimitExceeded(resourceString); } return result; } findDocumentSymbols2(document, doc, context = { resultLimit: Number.MAX_VALUE }) { const root = doc.root; if (!root) { return []; } let limit = context.resultLimit || Number.MAX_VALUE; // special handling for key bindings const resourceString = document.uri; if ((resourceString === 'vscode://defaultsettings/keybindings.json') || Strings.endsWith(resourceString.toLowerCase(), '/user/keybindings.json')) { if (root.type === 'array') { const result = []; for (const item of root.items) { if (item.type === 'object') { for (const property of item.properties) { if (property.keyNode.value === 'key' && property.valueNode) { const range = getRange(document, item); const selectionRange = getRange(document, property.keyNode); result.push({ name: getName(property.valueNode), kind: jsonLanguageTypes_1.SymbolKind.Function, range, selectionRange }); limit--; if (limit <= 0) { if (context && context.onResultLimitExceeded) { context.onResultLimitExceeded(resourceString); } return result; } } } } } return result; } } const result = []; const toVisit = [ { node: root, result } ]; let nextToVisit = 0; let limitExceeded = false; const collectOutlineEntries = (node, result) => { if (node.type === 'array') { node.items.forEach((node, index) => { if (node) { if (limit > 0) { limit--; const range = getRange(document, node); const selectionRange = range; const name = String(index); const symbol = { name, kind: this.getSymbolKind(node.type), range, selectionRange, children: [] }; result.push(symbol); toVisit.push({ result: symbol.children, node }); } else { limitExceeded = true; } } }); } else if (node.type === 'object') { node.properties.forEach((property) => { const valueNode = property.valueNode; if (valueNode) { if (limit > 0) { limit--; const range = getRange(document, property); const selectionRange = getRange(document, property.keyNode); const children = []; const symbol = { name: this.getKeyLabel(property), kind: this.getSymbolKind(valueNode.type), range, selectionRange, children, detail: this.getDetail(valueNode) }; result.push(symbol); toVisit.push({ result: children, node: valueNode }); } else { limitExceeded = true; } } }); } }; // breath first traversal while (nextToVisit < toVisit.length) { const next = toVisit[nextToVisit++]; collectOutlineEntries(next.node, next.result); } if (limitExceeded && context && context.onResultLimitExceeded) { context.onResultLimitExceeded(resourceString); } return result; } getSymbolKind(nodeType) { switch (nodeType) { case 'object': return jsonLanguageTypes_1.SymbolKind.Module; case 'string': return jsonLanguageTypes_1.SymbolKind.String; case 'number': return jsonLanguageTypes_1.SymbolKind.Number; case 'array': return jsonLanguageTypes_1.SymbolKind.Array; case 'boolean': return jsonLanguageTypes_1.SymbolKind.Boolean; default: // 'null' return jsonLanguageTypes_1.SymbolKind.Variable; } } getKeyLabel(property) { let name = property.keyNode.value; if (name) { name = name.replace(/[\n]/g, '↵'); } if (name && name.trim()) { return name; } return `"${name}"`; } getDetail(node) { if (!node) { return undefined; } if (node.type === 'boolean' || node.type === 'number' || node.type === 'null' || node.type === 'string') { return String(node.value); } else { if (node.type === 'array') { return node.children.length ? undefined : '[]'; } else if (node.type === 'object') { return node.children.length ? undefined : '{}'; } } return undefined; } findDocumentColors(document, doc, context) { return this.schemaService.getSchemaForResource(document.uri, doc).then(schema => { const result = []; if (schema) { let limit = context && typeof context.resultLimit === 'number' ? context.resultLimit : Number.MAX_VALUE; const matchingSchemas = doc.getMatchingSchemas(schema.schema); const visitedNode = {}; for (const s of matchingSchemas) { if (!s.inverted && s.schema && (s.schema.format === 'color' || s.schema.format === 'color-hex') && s.node && s.node.type === 'string') { const nodeId = String(s.node.offset); if (!visitedNode[nodeId]) { const color = (0, colors_1.colorFromHex)(Parser.getNodeValue(s.node)); if (color) { const range = getRange(document, s.node); result.push({ color, range }); } visitedNode[nodeId] = true; limit--; if (limit <= 0) { if (context && context.onResultLimitExceeded) { context.onResultLimitExceeded(document.uri); } return result; } } } } } return result; }); } getColorPresentations(document, doc, color, range) { const result = []; const red256 = Math.round(color.red * 255), green256 = Math.round(color.green * 255), blue256 = Math.round(color.blue * 255); function toTwoDigitHex(n) { const r = n.toString(16); return r.length !== 2 ? '0' + r : r; } let label; if (color.alpha === 1) { label = `#${toTwoDigitHex(red256)}${toTwoDigitHex(green256)}${toTwoDigitHex(blue256)}`; } else { label = `#${toTwoDigitHex(red256)}${toTwoDigitHex(green256)}${toTwoDigitHex(blue256)}${toTwoDigitHex(Math.round(color.alpha * 255))}`; } result.push({ label: label, textEdit: jsonLanguageTypes_1.TextEdit.replace(range, JSON.stringify(label)) }); return result; } } exports.JSONDocumentSymbols = JSONDocumentSymbols; function getRange(document, node) { return jsonLanguageTypes_1.Range.create(document.positionAt(node.offset), document.positionAt(node.offset + node.length)); } function getName(node) { return Parser.getNodeValue(node) || l10n.t('<empty>'); } });