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 *--------------------------------------------------------------------------------------------*/
6 if (typeof module === "object" && typeof module.exports === "object") {
7 var v = factory(require, exports);
8 if (v !== undefined) module.exports = v;
10 else if (typeof define === "function" && define.amd) {
11 define(["require", "exports", "../parser/jsonParser", "jsonc-parser", "../utils/json", "../utils/strings", "../utils/objects", "../jsonLanguageTypes", "vscode-nls"], factory);
13 })(function (require, exports) {
15 Object.defineProperty(exports, "__esModule", { value: true });
16 exports.JSONCompletion = void 0;
17 var Parser = require("../parser/jsonParser");
18 var Json = require("jsonc-parser");
19 var json_1 = require("../utils/json");
20 var strings_1 = require("../utils/strings");
21 var objects_1 = require("../utils/objects");
22 var jsonLanguageTypes_1 = require("../jsonLanguageTypes");
23 var nls = require("vscode-nls");
24 var localize = nls.loadMessageBundle();
25 var valueCommitCharacters = [',', '}', ']'];
26 var propertyCommitCharacters = [':'];
27 var JSONCompletion = /** @class */ (function () {
28 function JSONCompletion(schemaService, contributions, promiseConstructor, clientCapabilities) {
29 if (contributions === void 0) { contributions = []; }
30 if (promiseConstructor === void 0) { promiseConstructor = Promise; }
31 if (clientCapabilities === void 0) { clientCapabilities = {}; }
32 this.schemaService = schemaService;
33 this.contributions = contributions;
34 this.promiseConstructor = promiseConstructor;
35 this.clientCapabilities = clientCapabilities;
37 JSONCompletion.prototype.doResolve = function (item) {
38 for (var i = this.contributions.length - 1; i >= 0; i--) {
39 var resolveCompletion = this.contributions[i].resolveCompletion;
40 if (resolveCompletion) {
41 var resolver = resolveCompletion(item);
47 return this.promiseConstructor.resolve(item);
49 JSONCompletion.prototype.doComplete = function (document, position, doc) {
55 var text = document.getText();
56 var offset = document.offsetAt(position);
57 var node = doc.getNodeFromOffset(offset, true);
58 if (this.isInComment(document, node ? node.offset : 0, offset)) {
59 return Promise.resolve(result);
61 if (node && (offset === node.offset + node.length) && offset > 0) {
62 var ch = text[offset - 1];
63 if (node.type === 'object' && ch === '}' || node.type === 'array' && ch === ']') {
68 var currentWord = this.getCurrentWord(document, offset);
70 if (node && (node.type === 'string' || node.type === 'number' || node.type === 'boolean' || node.type === 'null')) {
71 overwriteRange = jsonLanguageTypes_1.Range.create(document.positionAt(node.offset), document.positionAt(node.offset + node.length));
74 var overwriteStart = offset - currentWord.length;
75 if (overwriteStart > 0 && text[overwriteStart - 1] === '"') {
78 overwriteRange = jsonLanguageTypes_1.Range.create(document.positionAt(overwriteStart), position);
80 var supportsCommitCharacters = false; //this.doesSupportsCommitCharacters(); disabled for now, waiting for new API: https://github.com/microsoft/vscode/issues/42544
83 add: function (suggestion) {
84 var label = suggestion.label;
85 var existing = proposed[label];
87 label = label.replace(/[\n]/g, '↵');
88 if (label.length > 60) {
89 var shortendedLabel = label.substr(0, 57).trim() + '...';
90 if (!proposed[shortendedLabel]) {
91 label = shortendedLabel;
94 if (overwriteRange && suggestion.insertText !== undefined) {
95 suggestion.textEdit = jsonLanguageTypes_1.TextEdit.replace(overwriteRange, suggestion.insertText);
97 if (supportsCommitCharacters) {
98 suggestion.commitCharacters = suggestion.kind === jsonLanguageTypes_1.CompletionItemKind.Property ? propertyCommitCharacters : valueCommitCharacters;
100 suggestion.label = label;
101 proposed[label] = suggestion;
102 result.items.push(suggestion);
105 if (!existing.documentation) {
106 existing.documentation = suggestion.documentation;
108 if (!existing.detail) {
109 existing.detail = suggestion.detail;
113 setAsIncomplete: function () {
114 result.isIncomplete = true;
116 error: function (message) {
117 console.error(message);
119 log: function (message) {
120 console.log(message);
122 getNumberOfProposals: function () {
123 return result.items.length;
126 return this.schemaService.getSchemaForResource(document.uri, doc).then(function (schema) {
127 var collectionPromises = [];
130 var currentProperty = undefined;
132 if (node.type === 'string') {
133 var parent = node.parent;
134 if (parent && parent.type === 'property' && parent.keyNode === node) {
135 addValue = !parent.valueNode;
136 currentProperty = parent;
137 currentKey = text.substr(node.offset + 1, node.length - 2);
139 node = parent.parent;
144 // proposals for properties
145 if (node && node.type === 'object') {
146 // don't suggest keys when the cursor is just before the opening curly brace
147 if (node.offset === offset) {
150 // don't suggest properties that are already present
151 var properties = node.properties;
152 properties.forEach(function (p) {
153 if (!currentProperty || currentProperty !== p) {
154 proposed[p.keyNode.value] = jsonLanguageTypes_1.CompletionItem.create('__');
157 var separatorAfter_1 = '';
159 separatorAfter_1 = _this.evaluateSeparatorAfter(document, document.offsetAt(overwriteRange.end));
162 // property proposals with schema
163 _this.getPropertyCompletions(schema, doc, node, addValue, separatorAfter_1, collector);
166 // property proposals without schema
167 _this.getSchemaLessPropertyCompletions(doc, node, currentKey, collector);
169 var location_1 = Parser.getNodePath(node);
170 _this.contributions.forEach(function (contribution) {
171 var collectPromise = contribution.collectPropertyCompletions(document.uri, location_1, currentWord, addValue, separatorAfter_1 === '', collector);
172 if (collectPromise) {
173 collectionPromises.push(collectPromise);
176 if ((!schema && currentWord.length > 0 && text.charAt(offset - currentWord.length - 1) !== '"')) {
178 kind: jsonLanguageTypes_1.CompletionItemKind.Property,
179 label: _this.getLabelForValue(currentWord),
180 insertText: _this.getInsertTextForProperty(currentWord, undefined, false, separatorAfter_1),
181 insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet, documentation: '',
183 collector.setAsIncomplete();
186 // proposals for values
189 // value proposals with schema
190 _this.getValueCompletions(schema, doc, node, offset, document, collector, types);
193 // value proposals without schema
194 _this.getSchemaLessValueCompletions(doc, node, offset, document, collector);
196 if (_this.contributions.length > 0) {
197 _this.getContributedValueCompletions(doc, node, offset, document, collector, collectionPromises);
199 return _this.promiseConstructor.all(collectionPromises).then(function () {
200 if (collector.getNumberOfProposals() === 0) {
201 var offsetForSeparator = offset;
202 if (node && (node.type === 'string' || node.type === 'number' || node.type === 'boolean' || node.type === 'null')) {
203 offsetForSeparator = node.offset + node.length;
205 var separatorAfter = _this.evaluateSeparatorAfter(document, offsetForSeparator);
206 _this.addFillerValueCompletions(types, separatorAfter, collector);
212 JSONCompletion.prototype.getPropertyCompletions = function (schema, doc, node, addValue, separatorAfter, collector) {
214 var matchingSchemas = doc.getMatchingSchemas(schema.schema, node.offset);
215 matchingSchemas.forEach(function (s) {
216 if (s.node === node && !s.inverted) {
217 var schemaProperties_1 = s.schema.properties;
218 if (schemaProperties_1) {
219 Object.keys(schemaProperties_1).forEach(function (key) {
220 var propertySchema = schemaProperties_1[key];
221 if (typeof propertySchema === 'object' && !propertySchema.deprecationMessage && !propertySchema.doNotSuggest) {
223 kind: jsonLanguageTypes_1.CompletionItemKind.Property,
225 insertText: _this.getInsertTextForProperty(key, propertySchema, addValue, separatorAfter),
226 insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
227 filterText: _this.getFilterTextForValue(key),
228 documentation: _this.fromMarkup(propertySchema.markdownDescription) || propertySchema.description || '',
230 if (propertySchema.suggestSortText !== undefined) {
231 proposal.sortText = propertySchema.suggestSortText;
233 if (proposal.insertText && strings_1.endsWith(proposal.insertText, "$1" + separatorAfter)) {
236 command: 'editor.action.triggerSuggest'
239 collector.add(proposal);
243 var schemaPropertyNames_1 = s.schema.propertyNames;
244 if (typeof schemaPropertyNames_1 === 'object' && !schemaPropertyNames_1.deprecationMessage && !schemaPropertyNames_1.doNotSuggest) {
245 var propertyNameCompletionItem = function (name, enumDescription) {
246 if (enumDescription === void 0) { enumDescription = undefined; }
248 kind: jsonLanguageTypes_1.CompletionItemKind.Property,
250 insertText: _this.getInsertTextForProperty(name, undefined, addValue, separatorAfter),
251 insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
252 filterText: _this.getFilterTextForValue(name),
253 documentation: enumDescription || _this.fromMarkup(schemaPropertyNames_1.markdownDescription) || schemaPropertyNames_1.description || '',
255 if (schemaPropertyNames_1.suggestSortText !== undefined) {
256 proposal.sortText = schemaPropertyNames_1.suggestSortText;
258 if (proposal.insertText && strings_1.endsWith(proposal.insertText, "$1" + separatorAfter)) {
261 command: 'editor.action.triggerSuggest'
264 collector.add(proposal);
266 if (schemaPropertyNames_1.enum) {
267 for (var i = 0; i < schemaPropertyNames_1.enum.length; i++) {
268 var enumDescription = undefined;
269 if (schemaPropertyNames_1.markdownEnumDescriptions && i < schemaPropertyNames_1.markdownEnumDescriptions.length) {
270 enumDescription = _this.fromMarkup(schemaPropertyNames_1.markdownEnumDescriptions[i]);
272 else if (schemaPropertyNames_1.enumDescriptions && i < schemaPropertyNames_1.enumDescriptions.length) {
273 enumDescription = schemaPropertyNames_1.enumDescriptions[i];
275 propertyNameCompletionItem(schemaPropertyNames_1.enum[i], enumDescription);
278 if (schemaPropertyNames_1.const) {
279 propertyNameCompletionItem(schemaPropertyNames_1.const);
285 JSONCompletion.prototype.getSchemaLessPropertyCompletions = function (doc, node, currentKey, collector) {
287 var collectCompletionsForSimilarObject = function (obj) {
288 obj.properties.forEach(function (p) {
289 var key = p.keyNode.value;
291 kind: jsonLanguageTypes_1.CompletionItemKind.Property,
293 insertText: _this.getInsertTextForValue(key, ''),
294 insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
295 filterText: _this.getFilterTextForValue(key),
301 if (node.parent.type === 'property') {
302 // if the object is a property value, check the tree for other objects that hang under a property of the same name
303 var parentKey_1 = node.parent.keyNode.value;
304 doc.visit(function (n) {
305 if (n.type === 'property' && n !== node.parent && n.keyNode.value === parentKey_1 && n.valueNode && n.valueNode.type === 'object') {
306 collectCompletionsForSimilarObject(n.valueNode);
311 else if (node.parent.type === 'array') {
312 // if the object is in an array, use all other array elements as similar objects
313 node.parent.items.forEach(function (n) {
314 if (n.type === 'object' && n !== node) {
315 collectCompletionsForSimilarObject(n);
320 else if (node.type === 'object') {
322 kind: jsonLanguageTypes_1.CompletionItemKind.Property,
324 insertText: this.getInsertTextForProperty('$schema', undefined, true, ''),
325 insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet, documentation: '',
326 filterText: this.getFilterTextForValue("$schema")
330 JSONCompletion.prototype.getSchemaLessValueCompletions = function (doc, node, offset, document, collector) {
332 var offsetForSeparator = offset;
333 if (node && (node.type === 'string' || node.type === 'number' || node.type === 'boolean' || node.type === 'null')) {
334 offsetForSeparator = node.offset + node.length;
339 kind: this.getSuggestionKind('object'),
340 label: 'Empty object',
341 insertText: this.getInsertTextForValue({}, ''),
342 insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
346 kind: this.getSuggestionKind('array'),
347 label: 'Empty array',
348 insertText: this.getInsertTextForValue([], ''),
349 insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
354 var separatorAfter = this.evaluateSeparatorAfter(document, offsetForSeparator);
355 var collectSuggestionsForValues = function (value) {
356 if (value.parent && !Parser.contains(value.parent, offset, true)) {
358 kind: _this.getSuggestionKind(value.type),
359 label: _this.getLabelTextForMatchingNode(value, document),
360 insertText: _this.getInsertTextForMatchingNode(value, document, separatorAfter),
361 insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet, documentation: ''
364 if (value.type === 'boolean') {
365 _this.addBooleanValueCompletion(!value.value, separatorAfter, collector);
368 if (node.type === 'property') {
369 if (offset > (node.colonOffset || 0)) {
370 var valueNode = node.valueNode;
371 if (valueNode && (offset > (valueNode.offset + valueNode.length) || valueNode.type === 'object' || valueNode.type === 'array')) {
374 // suggest values at the same key
375 var parentKey_2 = node.keyNode.value;
376 doc.visit(function (n) {
377 if (n.type === 'property' && n.keyNode.value === parentKey_2 && n.valueNode) {
378 collectSuggestionsForValues(n.valueNode);
382 if (parentKey_2 === '$schema' && node.parent && !node.parent.parent) {
383 this.addDollarSchemaCompletions(separatorAfter, collector);
387 if (node.type === 'array') {
388 if (node.parent && node.parent.type === 'property') {
389 // suggest items of an array at the same key
390 var parentKey_3 = node.parent.keyNode.value;
391 doc.visit(function (n) {
392 if (n.type === 'property' && n.keyNode.value === parentKey_3 && n.valueNode && n.valueNode.type === 'array') {
393 n.valueNode.items.forEach(collectSuggestionsForValues);
399 // suggest items in the same array
400 node.items.forEach(collectSuggestionsForValues);
404 JSONCompletion.prototype.getValueCompletions = function (schema, doc, node, offset, document, collector, types) {
405 var offsetForSeparator = offset;
406 var parentKey = undefined;
407 var valueNode = undefined;
408 if (node && (node.type === 'string' || node.type === 'number' || node.type === 'boolean' || node.type === 'null')) {
409 offsetForSeparator = node.offset + node.length;
414 this.addSchemaValueCompletions(schema.schema, '', collector, types);
417 if ((node.type === 'property') && offset > (node.colonOffset || 0)) {
418 var valueNode_1 = node.valueNode;
419 if (valueNode_1 && offset > (valueNode_1.offset + valueNode_1.length)) {
420 return; // we are past the value node
422 parentKey = node.keyNode.value;
425 if (node && (parentKey !== undefined || node.type === 'array')) {
426 var separatorAfter = this.evaluateSeparatorAfter(document, offsetForSeparator);
427 var matchingSchemas = doc.getMatchingSchemas(schema.schema, node.offset, valueNode);
428 for (var _i = 0, matchingSchemas_1 = matchingSchemas; _i < matchingSchemas_1.length; _i++) {
429 var s = matchingSchemas_1[_i];
430 if (s.node === node && !s.inverted && s.schema) {
431 if (node.type === 'array' && s.schema.items) {
432 if (Array.isArray(s.schema.items)) {
433 var index = this.findItemAtOffset(node, document, offset);
434 if (index < s.schema.items.length) {
435 this.addSchemaValueCompletions(s.schema.items[index], separatorAfter, collector, types);
439 this.addSchemaValueCompletions(s.schema.items, separatorAfter, collector, types);
442 if (parentKey !== undefined) {
443 var propertyMatched = false;
444 if (s.schema.properties) {
445 var propertySchema = s.schema.properties[parentKey];
446 if (propertySchema) {
447 propertyMatched = true;
448 this.addSchemaValueCompletions(propertySchema, separatorAfter, collector, types);
451 if (s.schema.patternProperties && !propertyMatched) {
452 for (var _a = 0, _b = Object.keys(s.schema.patternProperties); _a < _b.length; _a++) {
453 var pattern = _b[_a];
454 var regex = strings_1.extendedRegExp(pattern);
455 if (regex.test(parentKey)) {
456 propertyMatched = true;
457 var propertySchema = s.schema.patternProperties[pattern];
458 this.addSchemaValueCompletions(propertySchema, separatorAfter, collector, types);
462 if (s.schema.additionalProperties && !propertyMatched) {
463 var propertySchema = s.schema.additionalProperties;
464 this.addSchemaValueCompletions(propertySchema, separatorAfter, collector, types);
469 if (parentKey === '$schema' && !node.parent) {
470 this.addDollarSchemaCompletions(separatorAfter, collector);
472 if (types['boolean']) {
473 this.addBooleanValueCompletion(true, separatorAfter, collector);
474 this.addBooleanValueCompletion(false, separatorAfter, collector);
477 this.addNullValueCompletion(separatorAfter, collector);
481 JSONCompletion.prototype.getContributedValueCompletions = function (doc, node, offset, document, collector, collectionPromises) {
483 this.contributions.forEach(function (contribution) {
484 var collectPromise = contribution.collectDefaultCompletions(document.uri, collector);
485 if (collectPromise) {
486 collectionPromises.push(collectPromise);
491 if (node.type === 'string' || node.type === 'number' || node.type === 'boolean' || node.type === 'null') {
494 if (node && (node.type === 'property') && offset > (node.colonOffset || 0)) {
495 var parentKey_4 = node.keyNode.value;
496 var valueNode = node.valueNode;
497 if ((!valueNode || offset <= (valueNode.offset + valueNode.length)) && node.parent) {
498 var location_2 = Parser.getNodePath(node.parent);
499 this.contributions.forEach(function (contribution) {
500 var collectPromise = contribution.collectValueCompletions(document.uri, location_2, parentKey_4, collector);
501 if (collectPromise) {
502 collectionPromises.push(collectPromise);
509 JSONCompletion.prototype.addSchemaValueCompletions = function (schema, separatorAfter, collector, types) {
511 if (typeof schema === 'object') {
512 this.addEnumValueCompletions(schema, separatorAfter, collector);
513 this.addDefaultValueCompletions(schema, separatorAfter, collector);
514 this.collectTypes(schema, types);
515 if (Array.isArray(schema.allOf)) {
516 schema.allOf.forEach(function (s) { return _this.addSchemaValueCompletions(s, separatorAfter, collector, types); });
518 if (Array.isArray(schema.anyOf)) {
519 schema.anyOf.forEach(function (s) { return _this.addSchemaValueCompletions(s, separatorAfter, collector, types); });
521 if (Array.isArray(schema.oneOf)) {
522 schema.oneOf.forEach(function (s) { return _this.addSchemaValueCompletions(s, separatorAfter, collector, types); });
526 JSONCompletion.prototype.addDefaultValueCompletions = function (schema, separatorAfter, collector, arrayDepth) {
528 if (arrayDepth === void 0) { arrayDepth = 0; }
529 var hasProposals = false;
530 if (objects_1.isDefined(schema.default)) {
531 var type = schema.type;
532 var value = schema.default;
533 for (var i = arrayDepth; i > 0; i--) {
538 kind: this.getSuggestionKind(type),
539 label: this.getLabelForValue(value),
540 insertText: this.getInsertTextForValue(value, separatorAfter),
541 insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
542 detail: localize('json.suggest.default', 'Default value')
546 if (Array.isArray(schema.examples)) {
547 schema.examples.forEach(function (example) {
548 var type = schema.type;
550 for (var i = arrayDepth; i > 0; i--) {
555 kind: _this.getSuggestionKind(type),
556 label: _this.getLabelForValue(value),
557 insertText: _this.getInsertTextForValue(value, separatorAfter),
558 insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet
563 if (Array.isArray(schema.defaultSnippets)) {
564 schema.defaultSnippets.forEach(function (s) {
565 var type = schema.type;
570 if (objects_1.isDefined(value)) {
571 var type_1 = schema.type;
572 for (var i = arrayDepth; i > 0; i--) {
576 insertText = _this.getInsertTextForSnippetValue(value, separatorAfter);
577 filterText = _this.getFilterTextForSnippetValue(value);
578 label = label || _this.getLabelForSnippetValue(value);
580 else if (typeof s.bodyText === 'string') {
581 var prefix = '', suffix = '', indent = '';
582 for (var i = arrayDepth; i > 0; i--) {
583 prefix = prefix + indent + '[\n';
584 suffix = suffix + '\n' + indent + ']';
588 insertText = prefix + indent + s.bodyText.split('\n').join('\n' + indent) + suffix + separatorAfter;
589 label = label || insertText,
590 filterText = insertText.replace(/[\n]/g, ''); // remove new lines
596 kind: _this.getSuggestionKind(type),
598 documentation: _this.fromMarkup(s.markdownDescription) || s.description,
599 insertText: insertText,
600 insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
601 filterText: filterText
606 if (!hasProposals && typeof schema.items === 'object' && !Array.isArray(schema.items) && arrayDepth < 5 /* beware of recursion */) {
607 this.addDefaultValueCompletions(schema.items, separatorAfter, collector, arrayDepth + 1);
610 JSONCompletion.prototype.addEnumValueCompletions = function (schema, separatorAfter, collector) {
611 if (objects_1.isDefined(schema.const)) {
613 kind: this.getSuggestionKind(schema.type),
614 label: this.getLabelForValue(schema.const),
615 insertText: this.getInsertTextForValue(schema.const, separatorAfter),
616 insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
617 documentation: this.fromMarkup(schema.markdownDescription) || schema.description
620 if (Array.isArray(schema.enum)) {
621 for (var i = 0, length = schema.enum.length; i < length; i++) {
622 var enm = schema.enum[i];
623 var documentation = this.fromMarkup(schema.markdownDescription) || schema.description;
624 if (schema.markdownEnumDescriptions && i < schema.markdownEnumDescriptions.length && this.doesSupportMarkdown()) {
625 documentation = this.fromMarkup(schema.markdownEnumDescriptions[i]);
627 else if (schema.enumDescriptions && i < schema.enumDescriptions.length) {
628 documentation = schema.enumDescriptions[i];
631 kind: this.getSuggestionKind(schema.type),
632 label: this.getLabelForValue(enm),
633 insertText: this.getInsertTextForValue(enm, separatorAfter),
634 insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
635 documentation: documentation
640 JSONCompletion.prototype.collectTypes = function (schema, types) {
641 if (Array.isArray(schema.enum) || objects_1.isDefined(schema.const)) {
644 var type = schema.type;
645 if (Array.isArray(type)) {
646 type.forEach(function (t) { return types[t] = true; });
652 JSONCompletion.prototype.addFillerValueCompletions = function (types, separatorAfter, collector) {
653 if (types['object']) {
655 kind: this.getSuggestionKind('object'),
657 insertText: this.getInsertTextForGuessedValue({}, separatorAfter),
658 insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
659 detail: localize('defaults.object', 'New object'),
663 if (types['array']) {
665 kind: this.getSuggestionKind('array'),
667 insertText: this.getInsertTextForGuessedValue([], separatorAfter),
668 insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
669 detail: localize('defaults.array', 'New array'),
674 JSONCompletion.prototype.addBooleanValueCompletion = function (value, separatorAfter, collector) {
676 kind: this.getSuggestionKind('boolean'),
677 label: value ? 'true' : 'false',
678 insertText: this.getInsertTextForValue(value, separatorAfter),
679 insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
683 JSONCompletion.prototype.addNullValueCompletion = function (separatorAfter, collector) {
685 kind: this.getSuggestionKind('null'),
687 insertText: 'null' + separatorAfter,
688 insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
692 JSONCompletion.prototype.addDollarSchemaCompletions = function (separatorAfter, collector) {
694 var schemaIds = this.schemaService.getRegisteredSchemaIds(function (schema) { return schema === 'http' || schema === 'https'; });
695 schemaIds.forEach(function (schemaId) { return collector.add({
696 kind: jsonLanguageTypes_1.CompletionItemKind.Module,
697 label: _this.getLabelForValue(schemaId),
698 filterText: _this.getFilterTextForValue(schemaId),
699 insertText: _this.getInsertTextForValue(schemaId, separatorAfter),
700 insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet, documentation: ''
703 JSONCompletion.prototype.getLabelForValue = function (value) {
704 return JSON.stringify(value);
706 JSONCompletion.prototype.getFilterTextForValue = function (value) {
707 return JSON.stringify(value);
709 JSONCompletion.prototype.getFilterTextForSnippetValue = function (value) {
710 return JSON.stringify(value).replace(/\$\{\d+:([^}]+)\}|\$\d+/g, '$1');
712 JSONCompletion.prototype.getLabelForSnippetValue = function (value) {
713 var label = JSON.stringify(value);
714 return label.replace(/\$\{\d+:([^}]+)\}|\$\d+/g, '$1');
716 JSONCompletion.prototype.getInsertTextForPlainText = function (text) {
717 return text.replace(/[\\\$\}]/g, '\\$&'); // escape $, \ and }
719 JSONCompletion.prototype.getInsertTextForValue = function (value, separatorAfter) {
720 var text = JSON.stringify(value, null, '\t');
722 return '{$1}' + separatorAfter;
724 else if (text === '[]') {
725 return '[$1]' + separatorAfter;
727 return this.getInsertTextForPlainText(text + separatorAfter);
729 JSONCompletion.prototype.getInsertTextForSnippetValue = function (value, separatorAfter) {
730 var replacer = function (value) {
731 if (typeof value === 'string') {
732 if (value[0] === '^') {
733 return value.substr(1);
736 return JSON.stringify(value);
738 return json_1.stringifyObject(value, '', replacer) + separatorAfter;
740 JSONCompletion.prototype.getInsertTextForGuessedValue = function (value, separatorAfter) {
741 switch (typeof value) {
743 if (value === null) {
744 return '${1:null}' + separatorAfter;
746 return this.getInsertTextForValue(value, separatorAfter);
748 var snippetValue = JSON.stringify(value);
749 snippetValue = snippetValue.substr(1, snippetValue.length - 2); // remove quotes
750 snippetValue = this.getInsertTextForPlainText(snippetValue); // escape \ and }
751 return '"${1:' + snippetValue + '}"' + separatorAfter;
754 return '${1:' + JSON.stringify(value) + '}' + separatorAfter;
756 return this.getInsertTextForValue(value, separatorAfter);
758 JSONCompletion.prototype.getSuggestionKind = function (type) {
759 if (Array.isArray(type)) {
761 type = array.length > 0 ? array[0] : undefined;
764 return jsonLanguageTypes_1.CompletionItemKind.Value;
767 case 'string': return jsonLanguageTypes_1.CompletionItemKind.Value;
768 case 'object': return jsonLanguageTypes_1.CompletionItemKind.Module;
769 case 'property': return jsonLanguageTypes_1.CompletionItemKind.Property;
770 default: return jsonLanguageTypes_1.CompletionItemKind.Value;
773 JSONCompletion.prototype.getLabelTextForMatchingNode = function (node, document) {
780 var content = document.getText().substr(node.offset, node.length);
784 JSONCompletion.prototype.getInsertTextForMatchingNode = function (node, document, separatorAfter) {
787 return this.getInsertTextForValue([], separatorAfter);
789 return this.getInsertTextForValue({}, separatorAfter);
791 var content = document.getText().substr(node.offset, node.length) + separatorAfter;
792 return this.getInsertTextForPlainText(content);
795 JSONCompletion.prototype.getInsertTextForProperty = function (key, propertySchema, addValue, separatorAfter) {
796 var propertyText = this.getInsertTextForValue(key, '');
800 var resultText = propertyText + ': ';
802 var nValueProposals = 0;
803 if (propertySchema) {
804 if (Array.isArray(propertySchema.defaultSnippets)) {
805 if (propertySchema.defaultSnippets.length === 1) {
806 var body = propertySchema.defaultSnippets[0].body;
807 if (objects_1.isDefined(body)) {
808 value = this.getInsertTextForSnippetValue(body, '');
811 nValueProposals += propertySchema.defaultSnippets.length;
813 if (propertySchema.enum) {
814 if (!value && propertySchema.enum.length === 1) {
815 value = this.getInsertTextForGuessedValue(propertySchema.enum[0], '');
817 nValueProposals += propertySchema.enum.length;
819 if (objects_1.isDefined(propertySchema.default)) {
821 value = this.getInsertTextForGuessedValue(propertySchema.default, '');
825 if (Array.isArray(propertySchema.examples) && propertySchema.examples.length) {
827 value = this.getInsertTextForGuessedValue(propertySchema.examples[0], '');
829 nValueProposals += propertySchema.examples.length;
831 if (nValueProposals === 0) {
832 var type = Array.isArray(propertySchema.type) ? propertySchema.type[0] : propertySchema.type;
834 if (propertySchema.properties) {
837 else if (propertySchema.items) {
866 if (!value || nValueProposals > 1) {
869 return resultText + value + separatorAfter;
871 JSONCompletion.prototype.getCurrentWord = function (document, offset) {
873 var text = document.getText();
874 while (i >= 0 && ' \t\n\r\v":{[,]}'.indexOf(text.charAt(i)) === -1) {
877 return text.substring(i + 1, offset);
879 JSONCompletion.prototype.evaluateSeparatorAfter = function (document, offset) {
880 var scanner = Json.createScanner(document.getText(), true);
881 scanner.setPosition(offset);
882 var token = scanner.scan();
884 case 5 /* CommaToken */:
885 case 2 /* CloseBraceToken */:
886 case 4 /* CloseBracketToken */:
893 JSONCompletion.prototype.findItemAtOffset = function (node, document, offset) {
894 var scanner = Json.createScanner(document.getText(), true);
895 var children = node.items;
896 for (var i = children.length - 1; i >= 0; i--) {
897 var child = children[i];
898 if (offset > child.offset + child.length) {
899 scanner.setPosition(child.offset + child.length);
900 var token = scanner.scan();
901 if (token === 5 /* CommaToken */ && offset >= scanner.getTokenOffset() + scanner.getTokenLength()) {
906 else if (offset >= child.offset) {
912 JSONCompletion.prototype.isInComment = function (document, start, offset) {
913 var scanner = Json.createScanner(document.getText(), false);
914 scanner.setPosition(start);
915 var token = scanner.scan();
916 while (token !== 17 /* EOF */ && (scanner.getTokenOffset() + scanner.getTokenLength() < offset)) {
917 token = scanner.scan();
919 return (token === 12 /* LineCommentTrivia */ || token === 13 /* BlockCommentTrivia */) && scanner.getTokenOffset() <= offset;
921 JSONCompletion.prototype.fromMarkup = function (markupString) {
922 if (markupString && this.doesSupportMarkdown()) {
924 kind: jsonLanguageTypes_1.MarkupKind.Markdown,
930 JSONCompletion.prototype.doesSupportMarkdown = function () {
931 if (!objects_1.isDefined(this.supportsMarkdown)) {
932 var completion = this.clientCapabilities.textDocument && this.clientCapabilities.textDocument.completion;
933 this.supportsMarkdown = completion && completion.completionItem && Array.isArray(completion.completionItem.documentationFormat) && completion.completionItem.documentationFormat.indexOf(jsonLanguageTypes_1.MarkupKind.Markdown) !== -1;
935 return this.supportsMarkdown;
937 JSONCompletion.prototype.doesSupportsCommitCharacters = function () {
938 if (!objects_1.isDefined(this.supportsCommitCharacters)) {
939 var completion = this.clientCapabilities.textDocument && this.clientCapabilities.textDocument.completion;
940 this.supportsCommitCharacters = completion && completion.completionItem && !!completion.completionItem.commitCharactersSupport;
942 return this.supportsCommitCharacters;
944 return JSONCompletion;
946 exports.JSONCompletion = JSONCompletion;