jsonDocumentSymbols.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. import * as Parser from '../parser/jsonParser';
  6. import * as Strings from '../utils/strings';
  7. import { colorFromHex } from '../utils/colors';
  8. import { Range, TextEdit, SymbolKind, Location } from "../jsonLanguageTypes";
  9. var JSONDocumentSymbols = /** @class */ (function () {
  10. function JSONDocumentSymbols(schemaService) {
  11. this.schemaService = schemaService;
  12. }
  13. JSONDocumentSymbols.prototype.findDocumentSymbols = function (document, doc, context) {
  14. var _this = this;
  15. if (context === void 0) { context = { resultLimit: Number.MAX_VALUE }; }
  16. var root = doc.root;
  17. if (!root) {
  18. return [];
  19. }
  20. var limit = context.resultLimit || Number.MAX_VALUE;
  21. // special handling for key bindings
  22. var resourceString = document.uri;
  23. if ((resourceString === 'vscode://defaultsettings/keybindings.json') || Strings.endsWith(resourceString.toLowerCase(), '/user/keybindings.json')) {
  24. if (root.type === 'array') {
  25. var result_1 = [];
  26. for (var _i = 0, _a = root.items; _i < _a.length; _i++) {
  27. var item = _a[_i];
  28. if (item.type === 'object') {
  29. for (var _b = 0, _c = item.properties; _b < _c.length; _b++) {
  30. var property = _c[_b];
  31. if (property.keyNode.value === 'key' && property.valueNode) {
  32. var location = Location.create(document.uri, getRange(document, item));
  33. result_1.push({ name: Parser.getNodeValue(property.valueNode), kind: SymbolKind.Function, location: location });
  34. limit--;
  35. if (limit <= 0) {
  36. if (context && context.onResultLimitExceeded) {
  37. context.onResultLimitExceeded(resourceString);
  38. }
  39. return result_1;
  40. }
  41. }
  42. }
  43. }
  44. }
  45. return result_1;
  46. }
  47. }
  48. var toVisit = [
  49. { node: root, containerName: '' }
  50. ];
  51. var nextToVisit = 0;
  52. var limitExceeded = false;
  53. var result = [];
  54. var collectOutlineEntries = function (node, containerName) {
  55. if (node.type === 'array') {
  56. node.items.forEach(function (node) {
  57. if (node) {
  58. toVisit.push({ node: node, containerName: containerName });
  59. }
  60. });
  61. }
  62. else if (node.type === 'object') {
  63. node.properties.forEach(function (property) {
  64. var valueNode = property.valueNode;
  65. if (valueNode) {
  66. if (limit > 0) {
  67. limit--;
  68. var location = Location.create(document.uri, getRange(document, property));
  69. var childContainerName = containerName ? containerName + '.' + property.keyNode.value : property.keyNode.value;
  70. result.push({ name: _this.getKeyLabel(property), kind: _this.getSymbolKind(valueNode.type), location: location, containerName: containerName });
  71. toVisit.push({ node: valueNode, containerName: childContainerName });
  72. }
  73. else {
  74. limitExceeded = true;
  75. }
  76. }
  77. });
  78. }
  79. };
  80. // breath first traversal
  81. while (nextToVisit < toVisit.length) {
  82. var next = toVisit[nextToVisit++];
  83. collectOutlineEntries(next.node, next.containerName);
  84. }
  85. if (limitExceeded && context && context.onResultLimitExceeded) {
  86. context.onResultLimitExceeded(resourceString);
  87. }
  88. return result;
  89. };
  90. JSONDocumentSymbols.prototype.findDocumentSymbols2 = function (document, doc, context) {
  91. var _this = this;
  92. if (context === void 0) { context = { resultLimit: Number.MAX_VALUE }; }
  93. var root = doc.root;
  94. if (!root) {
  95. return [];
  96. }
  97. var limit = context.resultLimit || Number.MAX_VALUE;
  98. // special handling for key bindings
  99. var resourceString = document.uri;
  100. if ((resourceString === 'vscode://defaultsettings/keybindings.json') || Strings.endsWith(resourceString.toLowerCase(), '/user/keybindings.json')) {
  101. if (root.type === 'array') {
  102. var result_2 = [];
  103. for (var _i = 0, _a = root.items; _i < _a.length; _i++) {
  104. var item = _a[_i];
  105. if (item.type === 'object') {
  106. for (var _b = 0, _c = item.properties; _b < _c.length; _b++) {
  107. var property = _c[_b];
  108. if (property.keyNode.value === 'key' && property.valueNode) {
  109. var range = getRange(document, item);
  110. var selectionRange = getRange(document, property.keyNode);
  111. result_2.push({ name: Parser.getNodeValue(property.valueNode), kind: SymbolKind.Function, range: range, selectionRange: selectionRange });
  112. limit--;
  113. if (limit <= 0) {
  114. if (context && context.onResultLimitExceeded) {
  115. context.onResultLimitExceeded(resourceString);
  116. }
  117. return result_2;
  118. }
  119. }
  120. }
  121. }
  122. }
  123. return result_2;
  124. }
  125. }
  126. var result = [];
  127. var toVisit = [
  128. { node: root, result: result }
  129. ];
  130. var nextToVisit = 0;
  131. var limitExceeded = false;
  132. var collectOutlineEntries = function (node, result) {
  133. if (node.type === 'array') {
  134. node.items.forEach(function (node, index) {
  135. if (node) {
  136. if (limit > 0) {
  137. limit--;
  138. var range = getRange(document, node);
  139. var selectionRange = range;
  140. var name = String(index);
  141. var symbol = { name: name, kind: _this.getSymbolKind(node.type), range: range, selectionRange: selectionRange, children: [] };
  142. result.push(symbol);
  143. toVisit.push({ result: symbol.children, node: node });
  144. }
  145. else {
  146. limitExceeded = true;
  147. }
  148. }
  149. });
  150. }
  151. else if (node.type === 'object') {
  152. node.properties.forEach(function (property) {
  153. var valueNode = property.valueNode;
  154. if (valueNode) {
  155. if (limit > 0) {
  156. limit--;
  157. var range = getRange(document, property);
  158. var selectionRange = getRange(document, property.keyNode);
  159. var children = [];
  160. var symbol = { name: _this.getKeyLabel(property), kind: _this.getSymbolKind(valueNode.type), range: range, selectionRange: selectionRange, children: children, detail: _this.getDetail(valueNode) };
  161. result.push(symbol);
  162. toVisit.push({ result: children, node: valueNode });
  163. }
  164. else {
  165. limitExceeded = true;
  166. }
  167. }
  168. });
  169. }
  170. };
  171. // breath first traversal
  172. while (nextToVisit < toVisit.length) {
  173. var next = toVisit[nextToVisit++];
  174. collectOutlineEntries(next.node, next.result);
  175. }
  176. if (limitExceeded && context && context.onResultLimitExceeded) {
  177. context.onResultLimitExceeded(resourceString);
  178. }
  179. return result;
  180. };
  181. JSONDocumentSymbols.prototype.getSymbolKind = function (nodeType) {
  182. switch (nodeType) {
  183. case 'object':
  184. return SymbolKind.Module;
  185. case 'string':
  186. return SymbolKind.String;
  187. case 'number':
  188. return SymbolKind.Number;
  189. case 'array':
  190. return SymbolKind.Array;
  191. case 'boolean':
  192. return SymbolKind.Boolean;
  193. default: // 'null'
  194. return SymbolKind.Variable;
  195. }
  196. };
  197. JSONDocumentSymbols.prototype.getKeyLabel = function (property) {
  198. var name = property.keyNode.value;
  199. if (name) {
  200. name = name.replace(/[\n]/g, '↵');
  201. }
  202. if (name && name.trim()) {
  203. return name;
  204. }
  205. return "\"" + name + "\"";
  206. };
  207. JSONDocumentSymbols.prototype.getDetail = function (node) {
  208. if (!node) {
  209. return undefined;
  210. }
  211. if (node.type === 'boolean' || node.type === 'number' || node.type === 'null' || node.type === 'string') {
  212. return String(node.value);
  213. }
  214. else {
  215. if (node.type === 'array') {
  216. return node.children.length ? undefined : '[]';
  217. }
  218. else if (node.type === 'object') {
  219. return node.children.length ? undefined : '{}';
  220. }
  221. }
  222. return undefined;
  223. };
  224. JSONDocumentSymbols.prototype.findDocumentColors = function (document, doc, context) {
  225. return this.schemaService.getSchemaForResource(document.uri, doc).then(function (schema) {
  226. var result = [];
  227. if (schema) {
  228. var limit = context && typeof context.resultLimit === 'number' ? context.resultLimit : Number.MAX_VALUE;
  229. var matchingSchemas = doc.getMatchingSchemas(schema.schema);
  230. var visitedNode = {};
  231. for (var _i = 0, matchingSchemas_1 = matchingSchemas; _i < matchingSchemas_1.length; _i++) {
  232. var s = matchingSchemas_1[_i];
  233. if (!s.inverted && s.schema && (s.schema.format === 'color' || s.schema.format === 'color-hex') && s.node && s.node.type === 'string') {
  234. var nodeId = String(s.node.offset);
  235. if (!visitedNode[nodeId]) {
  236. var color = colorFromHex(Parser.getNodeValue(s.node));
  237. if (color) {
  238. var range = getRange(document, s.node);
  239. result.push({ color: color, range: range });
  240. }
  241. visitedNode[nodeId] = true;
  242. limit--;
  243. if (limit <= 0) {
  244. if (context && context.onResultLimitExceeded) {
  245. context.onResultLimitExceeded(document.uri);
  246. }
  247. return result;
  248. }
  249. }
  250. }
  251. }
  252. }
  253. return result;
  254. });
  255. };
  256. JSONDocumentSymbols.prototype.getColorPresentations = function (document, doc, color, range) {
  257. var result = [];
  258. var red256 = Math.round(color.red * 255), green256 = Math.round(color.green * 255), blue256 = Math.round(color.blue * 255);
  259. function toTwoDigitHex(n) {
  260. var r = n.toString(16);
  261. return r.length !== 2 ? '0' + r : r;
  262. }
  263. var label;
  264. if (color.alpha === 1) {
  265. label = "#" + toTwoDigitHex(red256) + toTwoDigitHex(green256) + toTwoDigitHex(blue256);
  266. }
  267. else {
  268. label = "#" + toTwoDigitHex(red256) + toTwoDigitHex(green256) + toTwoDigitHex(blue256) + toTwoDigitHex(Math.round(color.alpha * 255));
  269. }
  270. result.push({ label: label, textEdit: TextEdit.replace(range, JSON.stringify(label)) });
  271. return result;
  272. };
  273. return JSONDocumentSymbols;
  274. }());
  275. export { JSONDocumentSymbols };
  276. function getRange(document, node) {
  277. return Range.create(document.positionAt(node.offset), document.positionAt(node.offset + node.length));
  278. }