vscode-json-languageservice 4.2.1 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +7 -1
  2. package/SECURITY.md +41 -0
  3. package/lib/esm/jsonContributions.d.ts +17 -17
  4. package/lib/esm/jsonContributions.js +1 -1
  5. package/lib/esm/jsonLanguageService.d.ts +29 -29
  6. package/lib/esm/jsonLanguageService.js +66 -66
  7. package/lib/esm/jsonLanguageTypes.d.ts +279 -278
  8. package/lib/esm/jsonLanguageTypes.js +46 -45
  9. package/lib/esm/jsonSchema.d.ts +89 -70
  10. package/lib/esm/jsonSchema.js +1 -1
  11. package/lib/esm/parser/jsonParser.js +1214 -1218
  12. package/lib/esm/services/configuration.js +528 -528
  13. package/lib/esm/services/jsonCompletion.js +918 -934
  14. package/lib/esm/services/jsonDocumentSymbols.js +267 -278
  15. package/lib/esm/services/jsonFolding.js +120 -121
  16. package/lib/esm/services/jsonHover.js +109 -112
  17. package/lib/esm/services/jsonLinks.js +72 -73
  18. package/lib/esm/services/jsonSchemaService.js +586 -605
  19. package/lib/esm/services/jsonSelectionRanges.js +61 -61
  20. package/lib/esm/services/jsonValidation.js +151 -149
  21. package/lib/esm/utils/colors.js +68 -69
  22. package/lib/esm/utils/glob.js +124 -124
  23. package/lib/esm/utils/json.js +42 -42
  24. package/lib/esm/utils/objects.js +68 -65
  25. package/lib/esm/utils/strings.js +64 -64
  26. package/lib/umd/jsonContributions.d.ts +17 -17
  27. package/lib/umd/jsonContributions.js +12 -12
  28. package/lib/umd/jsonLanguageService.d.ts +29 -29
  29. package/lib/umd/jsonLanguageService.js +90 -90
  30. package/lib/umd/jsonLanguageTypes.d.ts +279 -278
  31. package/lib/umd/jsonLanguageTypes.js +93 -92
  32. package/lib/umd/jsonSchema.d.ts +89 -70
  33. package/lib/umd/jsonSchema.js +12 -12
  34. package/lib/umd/parser/jsonParser.js +1243 -1237
  35. package/lib/umd/services/configuration.js +541 -541
  36. package/lib/umd/services/jsonCompletion.js +932 -947
  37. package/lib/umd/services/jsonDocumentSymbols.js +281 -291
  38. package/lib/umd/services/jsonFolding.js +134 -135
  39. package/lib/umd/services/jsonHover.js +123 -125
  40. package/lib/umd/services/jsonLinks.js +86 -87
  41. package/lib/umd/services/jsonSchemaService.js +602 -618
  42. package/lib/umd/services/jsonSelectionRanges.js +75 -75
  43. package/lib/umd/services/jsonValidation.js +165 -162
  44. package/lib/umd/utils/colors.js +84 -85
  45. package/lib/umd/utils/glob.js +138 -138
  46. package/lib/umd/utils/json.js +56 -56
  47. package/lib/umd/utils/objects.js +87 -83
  48. package/lib/umd/utils/strings.js +82 -82
  49. package/package.json +10 -10
@@ -1,947 +1,932 @@
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
- (function (factory) {
6
- if (typeof module === "object" && typeof module.exports === "object") {
7
- var v = factory(require, exports);
8
- if (v !== undefined) module.exports = v;
9
- }
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);
12
- }
13
- })(function (require, exports) {
14
- "use strict";
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;
36
- }
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);
42
- if (resolver) {
43
- return resolver;
44
- }
45
- }
46
- }
47
- return this.promiseConstructor.resolve(item);
48
- };
49
- JSONCompletion.prototype.doComplete = function (document, position, doc) {
50
- var _this = this;
51
- var result = {
52
- items: [],
53
- isIncomplete: false
54
- };
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);
60
- }
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 === ']') {
64
- // after ] or }
65
- node = node.parent;
66
- }
67
- }
68
- var currentWord = this.getCurrentWord(document, offset);
69
- var overwriteRange;
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));
72
- }
73
- else {
74
- var overwriteStart = offset - currentWord.length;
75
- if (overwriteStart > 0 && text[overwriteStart - 1] === '"') {
76
- overwriteStart--;
77
- }
78
- overwriteRange = jsonLanguageTypes_1.Range.create(document.positionAt(overwriteStart), position);
79
- }
80
- var supportsCommitCharacters = false; //this.doesSupportsCommitCharacters(); disabled for now, waiting for new API: https://github.com/microsoft/vscode/issues/42544
81
- var proposed = {};
82
- var collector = {
83
- add: function (suggestion) {
84
- var label = suggestion.label;
85
- var existing = proposed[label];
86
- if (!existing) {
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;
92
- }
93
- }
94
- if (overwriteRange && suggestion.insertText !== undefined) {
95
- suggestion.textEdit = jsonLanguageTypes_1.TextEdit.replace(overwriteRange, suggestion.insertText);
96
- }
97
- if (supportsCommitCharacters) {
98
- suggestion.commitCharacters = suggestion.kind === jsonLanguageTypes_1.CompletionItemKind.Property ? propertyCommitCharacters : valueCommitCharacters;
99
- }
100
- suggestion.label = label;
101
- proposed[label] = suggestion;
102
- result.items.push(suggestion);
103
- }
104
- else {
105
- if (!existing.documentation) {
106
- existing.documentation = suggestion.documentation;
107
- }
108
- if (!existing.detail) {
109
- existing.detail = suggestion.detail;
110
- }
111
- }
112
- },
113
- setAsIncomplete: function () {
114
- result.isIncomplete = true;
115
- },
116
- error: function (message) {
117
- console.error(message);
118
- },
119
- log: function (message) {
120
- console.log(message);
121
- },
122
- getNumberOfProposals: function () {
123
- return result.items.length;
124
- }
125
- };
126
- return this.schemaService.getSchemaForResource(document.uri, doc).then(function (schema) {
127
- var collectionPromises = [];
128
- var addValue = true;
129
- var currentKey = '';
130
- var currentProperty = undefined;
131
- if (node) {
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);
138
- if (parent) {
139
- node = parent.parent;
140
- }
141
- }
142
- }
143
- }
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) {
148
- return result;
149
- }
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('__');
155
- }
156
- });
157
- var separatorAfter_1 = '';
158
- if (addValue) {
159
- separatorAfter_1 = _this.evaluateSeparatorAfter(document, document.offsetAt(overwriteRange.end));
160
- }
161
- if (schema) {
162
- // property proposals with schema
163
- _this.getPropertyCompletions(schema, doc, node, addValue, separatorAfter_1, collector);
164
- }
165
- else {
166
- // property proposals without schema
167
- _this.getSchemaLessPropertyCompletions(doc, node, currentKey, collector);
168
- }
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);
174
- }
175
- });
176
- if ((!schema && currentWord.length > 0 && text.charAt(offset - currentWord.length - 1) !== '"')) {
177
- collector.add({
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: '',
182
- });
183
- collector.setAsIncomplete();
184
- }
185
- }
186
- // proposals for values
187
- var types = {};
188
- if (schema) {
189
- // value proposals with schema
190
- _this.getValueCompletions(schema, doc, node, offset, document, collector, types);
191
- }
192
- else {
193
- // value proposals without schema
194
- _this.getSchemaLessValueCompletions(doc, node, offset, document, collector);
195
- }
196
- if (_this.contributions.length > 0) {
197
- _this.getContributedValueCompletions(doc, node, offset, document, collector, collectionPromises);
198
- }
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;
204
- }
205
- var separatorAfter = _this.evaluateSeparatorAfter(document, offsetForSeparator);
206
- _this.addFillerValueCompletions(types, separatorAfter, collector);
207
- }
208
- return result;
209
- });
210
- });
211
- };
212
- JSONCompletion.prototype.getPropertyCompletions = function (schema, doc, node, addValue, separatorAfter, collector) {
213
- var _this = this;
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) {
222
- var proposal = {
223
- kind: jsonLanguageTypes_1.CompletionItemKind.Property,
224
- label: key,
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 || '',
229
- };
230
- if (propertySchema.suggestSortText !== undefined) {
231
- proposal.sortText = propertySchema.suggestSortText;
232
- }
233
- if (proposal.insertText && (0, strings_1.endsWith)(proposal.insertText, "$1".concat(separatorAfter))) {
234
- proposal.command = {
235
- title: 'Suggest',
236
- command: 'editor.action.triggerSuggest'
237
- };
238
- }
239
- collector.add(proposal);
240
- }
241
- });
242
- }
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; }
247
- var proposal = {
248
- kind: jsonLanguageTypes_1.CompletionItemKind.Property,
249
- label: name,
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 || '',
254
- };
255
- if (schemaPropertyNames_1.suggestSortText !== undefined) {
256
- proposal.sortText = schemaPropertyNames_1.suggestSortText;
257
- }
258
- if (proposal.insertText && (0, strings_1.endsWith)(proposal.insertText, "$1".concat(separatorAfter))) {
259
- proposal.command = {
260
- title: 'Suggest',
261
- command: 'editor.action.triggerSuggest'
262
- };
263
- }
264
- collector.add(proposal);
265
- };
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]);
271
- }
272
- else if (schemaPropertyNames_1.enumDescriptions && i < schemaPropertyNames_1.enumDescriptions.length) {
273
- enumDescription = schemaPropertyNames_1.enumDescriptions[i];
274
- }
275
- propertyNameCompletionItem(schemaPropertyNames_1.enum[i], enumDescription);
276
- }
277
- }
278
- if (schemaPropertyNames_1.const) {
279
- propertyNameCompletionItem(schemaPropertyNames_1.const);
280
- }
281
- }
282
- }
283
- });
284
- };
285
- JSONCompletion.prototype.getSchemaLessPropertyCompletions = function (doc, node, currentKey, collector) {
286
- var _this = this;
287
- var collectCompletionsForSimilarObject = function (obj) {
288
- obj.properties.forEach(function (p) {
289
- var key = p.keyNode.value;
290
- collector.add({
291
- kind: jsonLanguageTypes_1.CompletionItemKind.Property,
292
- label: key,
293
- insertText: _this.getInsertTextForValue(key, ''),
294
- insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
295
- filterText: _this.getFilterTextForValue(key),
296
- documentation: ''
297
- });
298
- });
299
- };
300
- if (node.parent) {
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);
307
- }
308
- return true;
309
- });
310
- }
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);
316
- }
317
- });
318
- }
319
- }
320
- else if (node.type === 'object') {
321
- collector.add({
322
- kind: jsonLanguageTypes_1.CompletionItemKind.Property,
323
- label: '$schema',
324
- insertText: this.getInsertTextForProperty('$schema', undefined, true, ''),
325
- insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet, documentation: '',
326
- filterText: this.getFilterTextForValue("$schema")
327
- });
328
- }
329
- };
330
- JSONCompletion.prototype.getSchemaLessValueCompletions = function (doc, node, offset, document, collector) {
331
- var _this = this;
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;
335
- node = node.parent;
336
- }
337
- if (!node) {
338
- collector.add({
339
- kind: this.getSuggestionKind('object'),
340
- label: 'Empty object',
341
- insertText: this.getInsertTextForValue({}, ''),
342
- insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
343
- documentation: ''
344
- });
345
- collector.add({
346
- kind: this.getSuggestionKind('array'),
347
- label: 'Empty array',
348
- insertText: this.getInsertTextForValue([], ''),
349
- insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
350
- documentation: ''
351
- });
352
- return;
353
- }
354
- var separatorAfter = this.evaluateSeparatorAfter(document, offsetForSeparator);
355
- var collectSuggestionsForValues = function (value) {
356
- if (value.parent && !Parser.contains(value.parent, offset, true)) {
357
- collector.add({
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: ''
362
- });
363
- }
364
- if (value.type === 'boolean') {
365
- _this.addBooleanValueCompletion(!value.value, separatorAfter, collector);
366
- }
367
- };
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')) {
372
- return;
373
- }
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);
379
- }
380
- return true;
381
- });
382
- if (parentKey_2 === '$schema' && node.parent && !node.parent.parent) {
383
- this.addDollarSchemaCompletions(separatorAfter, collector);
384
- }
385
- }
386
- }
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);
394
- }
395
- return true;
396
- });
397
- }
398
- else {
399
- // suggest items in the same array
400
- node.items.forEach(collectSuggestionsForValues);
401
- }
402
- }
403
- };
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;
410
- valueNode = node;
411
- node = node.parent;
412
- }
413
- if (!node) {
414
- this.addSchemaValueCompletions(schema.schema, '', collector, types);
415
- return;
416
- }
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
421
- }
422
- parentKey = node.keyNode.value;
423
- node = node.parent;
424
- }
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);
436
- }
437
- }
438
- else {
439
- this.addSchemaValueCompletions(s.schema.items, separatorAfter, collector, types);
440
- }
441
- }
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);
449
- }
450
- }
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 = (0, strings_1.extendedRegExp)(pattern);
455
- if (regex === null || regex === void 0 ? void 0 : regex.test(parentKey)) {
456
- propertyMatched = true;
457
- var propertySchema = s.schema.patternProperties[pattern];
458
- this.addSchemaValueCompletions(propertySchema, separatorAfter, collector, types);
459
- }
460
- }
461
- }
462
- if (s.schema.additionalProperties && !propertyMatched) {
463
- var propertySchema = s.schema.additionalProperties;
464
- this.addSchemaValueCompletions(propertySchema, separatorAfter, collector, types);
465
- }
466
- }
467
- }
468
- }
469
- if (parentKey === '$schema' && !node.parent) {
470
- this.addDollarSchemaCompletions(separatorAfter, collector);
471
- }
472
- if (types['boolean']) {
473
- this.addBooleanValueCompletion(true, separatorAfter, collector);
474
- this.addBooleanValueCompletion(false, separatorAfter, collector);
475
- }
476
- if (types['null']) {
477
- this.addNullValueCompletion(separatorAfter, collector);
478
- }
479
- }
480
- };
481
- JSONCompletion.prototype.getContributedValueCompletions = function (doc, node, offset, document, collector, collectionPromises) {
482
- if (!node) {
483
- this.contributions.forEach(function (contribution) {
484
- var collectPromise = contribution.collectDefaultCompletions(document.uri, collector);
485
- if (collectPromise) {
486
- collectionPromises.push(collectPromise);
487
- }
488
- });
489
- }
490
- else {
491
- if (node.type === 'string' || node.type === 'number' || node.type === 'boolean' || node.type === 'null') {
492
- node = node.parent;
493
- }
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);
503
- }
504
- });
505
- }
506
- }
507
- }
508
- };
509
- JSONCompletion.prototype.addSchemaValueCompletions = function (schema, separatorAfter, collector, types) {
510
- var _this = this;
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); });
517
- }
518
- if (Array.isArray(schema.anyOf)) {
519
- schema.anyOf.forEach(function (s) { return _this.addSchemaValueCompletions(s, separatorAfter, collector, types); });
520
- }
521
- if (Array.isArray(schema.oneOf)) {
522
- schema.oneOf.forEach(function (s) { return _this.addSchemaValueCompletions(s, separatorAfter, collector, types); });
523
- }
524
- }
525
- };
526
- JSONCompletion.prototype.addDefaultValueCompletions = function (schema, separatorAfter, collector, arrayDepth) {
527
- var _this = this;
528
- if (arrayDepth === void 0) { arrayDepth = 0; }
529
- var hasProposals = false;
530
- if ((0, objects_1.isDefined)(schema.default)) {
531
- var type = schema.type;
532
- var value = schema.default;
533
- for (var i = arrayDepth; i > 0; i--) {
534
- value = [value];
535
- type = 'array';
536
- }
537
- collector.add({
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')
543
- });
544
- hasProposals = true;
545
- }
546
- if (Array.isArray(schema.examples)) {
547
- schema.examples.forEach(function (example) {
548
- var type = schema.type;
549
- var value = example;
550
- for (var i = arrayDepth; i > 0; i--) {
551
- value = [value];
552
- type = 'array';
553
- }
554
- collector.add({
555
- kind: _this.getSuggestionKind(type),
556
- label: _this.getLabelForValue(value),
557
- insertText: _this.getInsertTextForValue(value, separatorAfter),
558
- insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet
559
- });
560
- hasProposals = true;
561
- });
562
- }
563
- if (Array.isArray(schema.defaultSnippets)) {
564
- schema.defaultSnippets.forEach(function (s) {
565
- var type = schema.type;
566
- var value = s.body;
567
- var label = s.label;
568
- var insertText;
569
- var filterText;
570
- if ((0, objects_1.isDefined)(value)) {
571
- var type_1 = schema.type;
572
- for (var i = arrayDepth; i > 0; i--) {
573
- value = [value];
574
- type_1 = 'array';
575
- }
576
- insertText = _this.getInsertTextForSnippetValue(value, separatorAfter);
577
- filterText = _this.getFilterTextForSnippetValue(value);
578
- label = label || _this.getLabelForSnippetValue(value);
579
- }
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 + ']';
585
- indent += '\t';
586
- type = 'array';
587
- }
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
591
- }
592
- else {
593
- return;
594
- }
595
- collector.add({
596
- kind: _this.getSuggestionKind(type),
597
- label: label,
598
- documentation: _this.fromMarkup(s.markdownDescription) || s.description,
599
- insertText: insertText,
600
- insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
601
- filterText: filterText
602
- });
603
- hasProposals = true;
604
- });
605
- }
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);
608
- }
609
- };
610
- JSONCompletion.prototype.addEnumValueCompletions = function (schema, separatorAfter, collector) {
611
- if ((0, objects_1.isDefined)(schema.const)) {
612
- collector.add({
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
618
- });
619
- }
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]);
626
- }
627
- else if (schema.enumDescriptions && i < schema.enumDescriptions.length) {
628
- documentation = schema.enumDescriptions[i];
629
- }
630
- collector.add({
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
636
- });
637
- }
638
- }
639
- };
640
- JSONCompletion.prototype.collectTypes = function (schema, types) {
641
- if (Array.isArray(schema.enum) || (0, objects_1.isDefined)(schema.const)) {
642
- return;
643
- }
644
- var type = schema.type;
645
- if (Array.isArray(type)) {
646
- type.forEach(function (t) { return types[t] = true; });
647
- }
648
- else if (type) {
649
- types[type] = true;
650
- }
651
- };
652
- JSONCompletion.prototype.addFillerValueCompletions = function (types, separatorAfter, collector) {
653
- if (types['object']) {
654
- collector.add({
655
- kind: this.getSuggestionKind('object'),
656
- label: '{}',
657
- insertText: this.getInsertTextForGuessedValue({}, separatorAfter),
658
- insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
659
- detail: localize('defaults.object', 'New object'),
660
- documentation: ''
661
- });
662
- }
663
- if (types['array']) {
664
- collector.add({
665
- kind: this.getSuggestionKind('array'),
666
- label: '[]',
667
- insertText: this.getInsertTextForGuessedValue([], separatorAfter),
668
- insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
669
- detail: localize('defaults.array', 'New array'),
670
- documentation: ''
671
- });
672
- }
673
- };
674
- JSONCompletion.prototype.addBooleanValueCompletion = function (value, separatorAfter, collector) {
675
- collector.add({
676
- kind: this.getSuggestionKind('boolean'),
677
- label: value ? 'true' : 'false',
678
- insertText: this.getInsertTextForValue(value, separatorAfter),
679
- insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
680
- documentation: ''
681
- });
682
- };
683
- JSONCompletion.prototype.addNullValueCompletion = function (separatorAfter, collector) {
684
- collector.add({
685
- kind: this.getSuggestionKind('null'),
686
- label: 'null',
687
- insertText: 'null' + separatorAfter,
688
- insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
689
- documentation: ''
690
- });
691
- };
692
- JSONCompletion.prototype.addDollarSchemaCompletions = function (separatorAfter, collector) {
693
- var _this = this;
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: ''
701
- }); });
702
- };
703
- JSONCompletion.prototype.getLabelForValue = function (value) {
704
- return JSON.stringify(value);
705
- };
706
- JSONCompletion.prototype.getFilterTextForValue = function (value) {
707
- return JSON.stringify(value);
708
- };
709
- JSONCompletion.prototype.getFilterTextForSnippetValue = function (value) {
710
- return JSON.stringify(value).replace(/\$\{\d+:([^}]+)\}|\$\d+/g, '$1');
711
- };
712
- JSONCompletion.prototype.getLabelForSnippetValue = function (value) {
713
- var label = JSON.stringify(value);
714
- return label.replace(/\$\{\d+:([^}]+)\}|\$\d+/g, '$1');
715
- };
716
- JSONCompletion.prototype.getInsertTextForPlainText = function (text) {
717
- return text.replace(/[\\\$\}]/g, '\\$&'); // escape $, \ and }
718
- };
719
- JSONCompletion.prototype.getInsertTextForValue = function (value, separatorAfter) {
720
- var text = JSON.stringify(value, null, '\t');
721
- if (text === '{}') {
722
- return '{$1}' + separatorAfter;
723
- }
724
- else if (text === '[]') {
725
- return '[$1]' + separatorAfter;
726
- }
727
- return this.getInsertTextForPlainText(text + separatorAfter);
728
- };
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);
734
- }
735
- }
736
- return JSON.stringify(value);
737
- };
738
- return (0, json_1.stringifyObject)(value, '', replacer) + separatorAfter;
739
- };
740
- JSONCompletion.prototype.getInsertTextForGuessedValue = function (value, separatorAfter) {
741
- switch (typeof value) {
742
- case 'object':
743
- if (value === null) {
744
- return '${1:null}' + separatorAfter;
745
- }
746
- return this.getInsertTextForValue(value, separatorAfter);
747
- case 'string':
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;
752
- case 'number':
753
- case 'boolean':
754
- return '${1:' + JSON.stringify(value) + '}' + separatorAfter;
755
- }
756
- return this.getInsertTextForValue(value, separatorAfter);
757
- };
758
- JSONCompletion.prototype.getSuggestionKind = function (type) {
759
- if (Array.isArray(type)) {
760
- var array = type;
761
- type = array.length > 0 ? array[0] : undefined;
762
- }
763
- if (!type) {
764
- return jsonLanguageTypes_1.CompletionItemKind.Value;
765
- }
766
- switch (type) {
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;
771
- }
772
- };
773
- JSONCompletion.prototype.getLabelTextForMatchingNode = function (node, document) {
774
- switch (node.type) {
775
- case 'array':
776
- return '[]';
777
- case 'object':
778
- return '{}';
779
- default:
780
- var content = document.getText().substr(node.offset, node.length);
781
- return content;
782
- }
783
- };
784
- JSONCompletion.prototype.getInsertTextForMatchingNode = function (node, document, separatorAfter) {
785
- switch (node.type) {
786
- case 'array':
787
- return this.getInsertTextForValue([], separatorAfter);
788
- case 'object':
789
- return this.getInsertTextForValue({}, separatorAfter);
790
- default:
791
- var content = document.getText().substr(node.offset, node.length) + separatorAfter;
792
- return this.getInsertTextForPlainText(content);
793
- }
794
- };
795
- JSONCompletion.prototype.getInsertTextForProperty = function (key, propertySchema, addValue, separatorAfter) {
796
- var propertyText = this.getInsertTextForValue(key, '');
797
- if (!addValue) {
798
- return propertyText;
799
- }
800
- var resultText = propertyText + ': ';
801
- var value;
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 ((0, objects_1.isDefined)(body)) {
808
- value = this.getInsertTextForSnippetValue(body, '');
809
- }
810
- }
811
- nValueProposals += propertySchema.defaultSnippets.length;
812
- }
813
- if (propertySchema.enum) {
814
- if (!value && propertySchema.enum.length === 1) {
815
- value = this.getInsertTextForGuessedValue(propertySchema.enum[0], '');
816
- }
817
- nValueProposals += propertySchema.enum.length;
818
- }
819
- if ((0, objects_1.isDefined)(propertySchema.default)) {
820
- if (!value) {
821
- value = this.getInsertTextForGuessedValue(propertySchema.default, '');
822
- }
823
- nValueProposals++;
824
- }
825
- if (Array.isArray(propertySchema.examples) && propertySchema.examples.length) {
826
- if (!value) {
827
- value = this.getInsertTextForGuessedValue(propertySchema.examples[0], '');
828
- }
829
- nValueProposals += propertySchema.examples.length;
830
- }
831
- if (nValueProposals === 0) {
832
- var type = Array.isArray(propertySchema.type) ? propertySchema.type[0] : propertySchema.type;
833
- if (!type) {
834
- if (propertySchema.properties) {
835
- type = 'object';
836
- }
837
- else if (propertySchema.items) {
838
- type = 'array';
839
- }
840
- }
841
- switch (type) {
842
- case 'boolean':
843
- value = '$1';
844
- break;
845
- case 'string':
846
- value = '"$1"';
847
- break;
848
- case 'object':
849
- value = '{$1}';
850
- break;
851
- case 'array':
852
- value = '[$1]';
853
- break;
854
- case 'number':
855
- case 'integer':
856
- value = '${1:0}';
857
- break;
858
- case 'null':
859
- value = '${1:null}';
860
- break;
861
- default:
862
- return propertyText;
863
- }
864
- }
865
- }
866
- if (!value || nValueProposals > 1) {
867
- value = '$1';
868
- }
869
- return resultText + value + separatorAfter;
870
- };
871
- JSONCompletion.prototype.getCurrentWord = function (document, offset) {
872
- var i = offset - 1;
873
- var text = document.getText();
874
- while (i >= 0 && ' \t\n\r\v":{[,]}'.indexOf(text.charAt(i)) === -1) {
875
- i--;
876
- }
877
- return text.substring(i + 1, offset);
878
- };
879
- JSONCompletion.prototype.evaluateSeparatorAfter = function (document, offset) {
880
- var scanner = Json.createScanner(document.getText(), true);
881
- scanner.setPosition(offset);
882
- var token = scanner.scan();
883
- switch (token) {
884
- case 5 /* CommaToken */:
885
- case 2 /* CloseBraceToken */:
886
- case 4 /* CloseBracketToken */:
887
- case 17 /* EOF */:
888
- return '';
889
- default:
890
- return ',';
891
- }
892
- };
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()) {
902
- return i + 1;
903
- }
904
- return i;
905
- }
906
- else if (offset >= child.offset) {
907
- return i;
908
- }
909
- }
910
- return 0;
911
- };
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();
918
- }
919
- return (token === 12 /* LineCommentTrivia */ || token === 13 /* BlockCommentTrivia */) && scanner.getTokenOffset() <= offset;
920
- };
921
- JSONCompletion.prototype.fromMarkup = function (markupString) {
922
- if (markupString && this.doesSupportMarkdown()) {
923
- return {
924
- kind: jsonLanguageTypes_1.MarkupKind.Markdown,
925
- value: markupString
926
- };
927
- }
928
- return undefined;
929
- };
930
- JSONCompletion.prototype.doesSupportMarkdown = function () {
931
- if (!(0, 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;
934
- }
935
- return this.supportsMarkdown;
936
- };
937
- JSONCompletion.prototype.doesSupportsCommitCharacters = function () {
938
- if (!(0, objects_1.isDefined)(this.supportsCommitCharacters)) {
939
- var completion = this.clientCapabilities.textDocument && this.clientCapabilities.textDocument.completion;
940
- this.supportsCommitCharacters = completion && completion.completionItem && !!completion.completionItem.commitCharactersSupport;
941
- }
942
- return this.supportsCommitCharacters;
943
- };
944
- return JSONCompletion;
945
- }());
946
- exports.JSONCompletion = JSONCompletion;
947
- });
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
+ (function (factory) {
6
+ if (typeof module === "object" && typeof module.exports === "object") {
7
+ var v = factory(require, exports);
8
+ if (v !== undefined) module.exports = v;
9
+ }
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);
12
+ }
13
+ })(function (require, exports) {
14
+ "use strict";
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.JSONCompletion = void 0;
17
+ const Parser = require("../parser/jsonParser");
18
+ const Json = require("jsonc-parser");
19
+ const json_1 = require("../utils/json");
20
+ const strings_1 = require("../utils/strings");
21
+ const objects_1 = require("../utils/objects");
22
+ const jsonLanguageTypes_1 = require("../jsonLanguageTypes");
23
+ const nls = require("vscode-nls");
24
+ const localize = nls.loadMessageBundle();
25
+ const valueCommitCharacters = [',', '}', ']'];
26
+ const propertyCommitCharacters = [':'];
27
+ class JSONCompletion {
28
+ constructor(schemaService, contributions = [], promiseConstructor = Promise, clientCapabilities = {}) {
29
+ this.schemaService = schemaService;
30
+ this.contributions = contributions;
31
+ this.promiseConstructor = promiseConstructor;
32
+ this.clientCapabilities = clientCapabilities;
33
+ }
34
+ doResolve(item) {
35
+ for (let i = this.contributions.length - 1; i >= 0; i--) {
36
+ const resolveCompletion = this.contributions[i].resolveCompletion;
37
+ if (resolveCompletion) {
38
+ const resolver = resolveCompletion(item);
39
+ if (resolver) {
40
+ return resolver;
41
+ }
42
+ }
43
+ }
44
+ return this.promiseConstructor.resolve(item);
45
+ }
46
+ doComplete(document, position, doc) {
47
+ const result = {
48
+ items: [],
49
+ isIncomplete: false
50
+ };
51
+ const text = document.getText();
52
+ const offset = document.offsetAt(position);
53
+ let node = doc.getNodeFromOffset(offset, true);
54
+ if (this.isInComment(document, node ? node.offset : 0, offset)) {
55
+ return Promise.resolve(result);
56
+ }
57
+ if (node && (offset === node.offset + node.length) && offset > 0) {
58
+ const ch = text[offset - 1];
59
+ if (node.type === 'object' && ch === '}' || node.type === 'array' && ch === ']') {
60
+ // after ] or }
61
+ node = node.parent;
62
+ }
63
+ }
64
+ const currentWord = this.getCurrentWord(document, offset);
65
+ let overwriteRange;
66
+ if (node && (node.type === 'string' || node.type === 'number' || node.type === 'boolean' || node.type === 'null')) {
67
+ overwriteRange = jsonLanguageTypes_1.Range.create(document.positionAt(node.offset), document.positionAt(node.offset + node.length));
68
+ }
69
+ else {
70
+ let overwriteStart = offset - currentWord.length;
71
+ if (overwriteStart > 0 && text[overwriteStart - 1] === '"') {
72
+ overwriteStart--;
73
+ }
74
+ overwriteRange = jsonLanguageTypes_1.Range.create(document.positionAt(overwriteStart), position);
75
+ }
76
+ const supportsCommitCharacters = false; //this.doesSupportsCommitCharacters(); disabled for now, waiting for new API: https://github.com/microsoft/vscode/issues/42544
77
+ const proposed = {};
78
+ const collector = {
79
+ add: (suggestion) => {
80
+ let label = suggestion.label;
81
+ const existing = proposed[label];
82
+ if (!existing) {
83
+ label = label.replace(/[\n]/g, '↵');
84
+ if (label.length > 60) {
85
+ const shortendedLabel = label.substr(0, 57).trim() + '...';
86
+ if (!proposed[shortendedLabel]) {
87
+ label = shortendedLabel;
88
+ }
89
+ }
90
+ if (overwriteRange && suggestion.insertText !== undefined) {
91
+ suggestion.textEdit = jsonLanguageTypes_1.TextEdit.replace(overwriteRange, suggestion.insertText);
92
+ }
93
+ if (supportsCommitCharacters) {
94
+ suggestion.commitCharacters = suggestion.kind === jsonLanguageTypes_1.CompletionItemKind.Property ? propertyCommitCharacters : valueCommitCharacters;
95
+ }
96
+ suggestion.label = label;
97
+ proposed[label] = suggestion;
98
+ result.items.push(suggestion);
99
+ }
100
+ else {
101
+ if (!existing.documentation) {
102
+ existing.documentation = suggestion.documentation;
103
+ }
104
+ if (!existing.detail) {
105
+ existing.detail = suggestion.detail;
106
+ }
107
+ }
108
+ },
109
+ setAsIncomplete: () => {
110
+ result.isIncomplete = true;
111
+ },
112
+ error: (message) => {
113
+ console.error(message);
114
+ },
115
+ log: (message) => {
116
+ console.log(message);
117
+ },
118
+ getNumberOfProposals: () => {
119
+ return result.items.length;
120
+ }
121
+ };
122
+ return this.schemaService.getSchemaForResource(document.uri, doc).then((schema) => {
123
+ const collectionPromises = [];
124
+ let addValue = true;
125
+ let currentKey = '';
126
+ let currentProperty = undefined;
127
+ if (node) {
128
+ if (node.type === 'string') {
129
+ const parent = node.parent;
130
+ if (parent && parent.type === 'property' && parent.keyNode === node) {
131
+ addValue = !parent.valueNode;
132
+ currentProperty = parent;
133
+ currentKey = text.substr(node.offset + 1, node.length - 2);
134
+ if (parent) {
135
+ node = parent.parent;
136
+ }
137
+ }
138
+ }
139
+ }
140
+ // proposals for properties
141
+ if (node && node.type === 'object') {
142
+ // don't suggest keys when the cursor is just before the opening curly brace
143
+ if (node.offset === offset) {
144
+ return result;
145
+ }
146
+ // don't suggest properties that are already present
147
+ const properties = node.properties;
148
+ properties.forEach(p => {
149
+ if (!currentProperty || currentProperty !== p) {
150
+ proposed[p.keyNode.value] = jsonLanguageTypes_1.CompletionItem.create('__');
151
+ }
152
+ });
153
+ let separatorAfter = '';
154
+ if (addValue) {
155
+ separatorAfter = this.evaluateSeparatorAfter(document, document.offsetAt(overwriteRange.end));
156
+ }
157
+ if (schema) {
158
+ // property proposals with schema
159
+ this.getPropertyCompletions(schema, doc, node, addValue, separatorAfter, collector);
160
+ }
161
+ else {
162
+ // property proposals without schema
163
+ this.getSchemaLessPropertyCompletions(doc, node, currentKey, collector);
164
+ }
165
+ const location = Parser.getNodePath(node);
166
+ this.contributions.forEach((contribution) => {
167
+ const collectPromise = contribution.collectPropertyCompletions(document.uri, location, currentWord, addValue, separatorAfter === '', collector);
168
+ if (collectPromise) {
169
+ collectionPromises.push(collectPromise);
170
+ }
171
+ });
172
+ if ((!schema && currentWord.length > 0 && text.charAt(offset - currentWord.length - 1) !== '"')) {
173
+ collector.add({
174
+ kind: jsonLanguageTypes_1.CompletionItemKind.Property,
175
+ label: this.getLabelForValue(currentWord),
176
+ insertText: this.getInsertTextForProperty(currentWord, undefined, false, separatorAfter),
177
+ insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet, documentation: '',
178
+ });
179
+ collector.setAsIncomplete();
180
+ }
181
+ }
182
+ // proposals for values
183
+ const types = {};
184
+ if (schema) {
185
+ // value proposals with schema
186
+ this.getValueCompletions(schema, doc, node, offset, document, collector, types);
187
+ }
188
+ else {
189
+ // value proposals without schema
190
+ this.getSchemaLessValueCompletions(doc, node, offset, document, collector);
191
+ }
192
+ if (this.contributions.length > 0) {
193
+ this.getContributedValueCompletions(doc, node, offset, document, collector, collectionPromises);
194
+ }
195
+ return this.promiseConstructor.all(collectionPromises).then(() => {
196
+ if (collector.getNumberOfProposals() === 0) {
197
+ let offsetForSeparator = offset;
198
+ if (node && (node.type === 'string' || node.type === 'number' || node.type === 'boolean' || node.type === 'null')) {
199
+ offsetForSeparator = node.offset + node.length;
200
+ }
201
+ const separatorAfter = this.evaluateSeparatorAfter(document, offsetForSeparator);
202
+ this.addFillerValueCompletions(types, separatorAfter, collector);
203
+ }
204
+ return result;
205
+ });
206
+ });
207
+ }
208
+ getPropertyCompletions(schema, doc, node, addValue, separatorAfter, collector) {
209
+ const matchingSchemas = doc.getMatchingSchemas(schema.schema, node.offset);
210
+ matchingSchemas.forEach((s) => {
211
+ if (s.node === node && !s.inverted) {
212
+ const schemaProperties = s.schema.properties;
213
+ if (schemaProperties) {
214
+ Object.keys(schemaProperties).forEach((key) => {
215
+ const propertySchema = schemaProperties[key];
216
+ if (typeof propertySchema === 'object' && !propertySchema.deprecationMessage && !propertySchema.doNotSuggest) {
217
+ const proposal = {
218
+ kind: jsonLanguageTypes_1.CompletionItemKind.Property,
219
+ label: key,
220
+ insertText: this.getInsertTextForProperty(key, propertySchema, addValue, separatorAfter),
221
+ insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
222
+ filterText: this.getFilterTextForValue(key),
223
+ documentation: this.fromMarkup(propertySchema.markdownDescription) || propertySchema.description || '',
224
+ };
225
+ if (propertySchema.suggestSortText !== undefined) {
226
+ proposal.sortText = propertySchema.suggestSortText;
227
+ }
228
+ if (proposal.insertText && (0, strings_1.endsWith)(proposal.insertText, `$1${separatorAfter}`)) {
229
+ proposal.command = {
230
+ title: 'Suggest',
231
+ command: 'editor.action.triggerSuggest'
232
+ };
233
+ }
234
+ collector.add(proposal);
235
+ }
236
+ });
237
+ }
238
+ const schemaPropertyNames = s.schema.propertyNames;
239
+ if (typeof schemaPropertyNames === 'object' && !schemaPropertyNames.deprecationMessage && !schemaPropertyNames.doNotSuggest) {
240
+ const propertyNameCompletionItem = (name, enumDescription = undefined) => {
241
+ const proposal = {
242
+ kind: jsonLanguageTypes_1.CompletionItemKind.Property,
243
+ label: name,
244
+ insertText: this.getInsertTextForProperty(name, undefined, addValue, separatorAfter),
245
+ insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
246
+ filterText: this.getFilterTextForValue(name),
247
+ documentation: enumDescription || this.fromMarkup(schemaPropertyNames.markdownDescription) || schemaPropertyNames.description || '',
248
+ };
249
+ if (schemaPropertyNames.suggestSortText !== undefined) {
250
+ proposal.sortText = schemaPropertyNames.suggestSortText;
251
+ }
252
+ if (proposal.insertText && (0, strings_1.endsWith)(proposal.insertText, `$1${separatorAfter}`)) {
253
+ proposal.command = {
254
+ title: 'Suggest',
255
+ command: 'editor.action.triggerSuggest'
256
+ };
257
+ }
258
+ collector.add(proposal);
259
+ };
260
+ if (schemaPropertyNames.enum) {
261
+ for (let i = 0; i < schemaPropertyNames.enum.length; i++) {
262
+ let enumDescription = undefined;
263
+ if (schemaPropertyNames.markdownEnumDescriptions && i < schemaPropertyNames.markdownEnumDescriptions.length) {
264
+ enumDescription = this.fromMarkup(schemaPropertyNames.markdownEnumDescriptions[i]);
265
+ }
266
+ else if (schemaPropertyNames.enumDescriptions && i < schemaPropertyNames.enumDescriptions.length) {
267
+ enumDescription = schemaPropertyNames.enumDescriptions[i];
268
+ }
269
+ propertyNameCompletionItem(schemaPropertyNames.enum[i], enumDescription);
270
+ }
271
+ }
272
+ if (schemaPropertyNames.const) {
273
+ propertyNameCompletionItem(schemaPropertyNames.const);
274
+ }
275
+ }
276
+ }
277
+ });
278
+ }
279
+ getSchemaLessPropertyCompletions(doc, node, currentKey, collector) {
280
+ const collectCompletionsForSimilarObject = (obj) => {
281
+ obj.properties.forEach((p) => {
282
+ const key = p.keyNode.value;
283
+ collector.add({
284
+ kind: jsonLanguageTypes_1.CompletionItemKind.Property,
285
+ label: key,
286
+ insertText: this.getInsertTextForValue(key, ''),
287
+ insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
288
+ filterText: this.getFilterTextForValue(key),
289
+ documentation: ''
290
+ });
291
+ });
292
+ };
293
+ if (node.parent) {
294
+ if (node.parent.type === 'property') {
295
+ // if the object is a property value, check the tree for other objects that hang under a property of the same name
296
+ const parentKey = node.parent.keyNode.value;
297
+ doc.visit(n => {
298
+ if (n.type === 'property' && n !== node.parent && n.keyNode.value === parentKey && n.valueNode && n.valueNode.type === 'object') {
299
+ collectCompletionsForSimilarObject(n.valueNode);
300
+ }
301
+ return true;
302
+ });
303
+ }
304
+ else if (node.parent.type === 'array') {
305
+ // if the object is in an array, use all other array elements as similar objects
306
+ node.parent.items.forEach(n => {
307
+ if (n.type === 'object' && n !== node) {
308
+ collectCompletionsForSimilarObject(n);
309
+ }
310
+ });
311
+ }
312
+ }
313
+ else if (node.type === 'object') {
314
+ collector.add({
315
+ kind: jsonLanguageTypes_1.CompletionItemKind.Property,
316
+ label: '$schema',
317
+ insertText: this.getInsertTextForProperty('$schema', undefined, true, ''),
318
+ insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet, documentation: '',
319
+ filterText: this.getFilterTextForValue("$schema")
320
+ });
321
+ }
322
+ }
323
+ getSchemaLessValueCompletions(doc, node, offset, document, collector) {
324
+ let offsetForSeparator = offset;
325
+ if (node && (node.type === 'string' || node.type === 'number' || node.type === 'boolean' || node.type === 'null')) {
326
+ offsetForSeparator = node.offset + node.length;
327
+ node = node.parent;
328
+ }
329
+ if (!node) {
330
+ collector.add({
331
+ kind: this.getSuggestionKind('object'),
332
+ label: 'Empty object',
333
+ insertText: this.getInsertTextForValue({}, ''),
334
+ insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
335
+ documentation: ''
336
+ });
337
+ collector.add({
338
+ kind: this.getSuggestionKind('array'),
339
+ label: 'Empty array',
340
+ insertText: this.getInsertTextForValue([], ''),
341
+ insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
342
+ documentation: ''
343
+ });
344
+ return;
345
+ }
346
+ const separatorAfter = this.evaluateSeparatorAfter(document, offsetForSeparator);
347
+ const collectSuggestionsForValues = (value) => {
348
+ if (value.parent && !Parser.contains(value.parent, offset, true)) {
349
+ collector.add({
350
+ kind: this.getSuggestionKind(value.type),
351
+ label: this.getLabelTextForMatchingNode(value, document),
352
+ insertText: this.getInsertTextForMatchingNode(value, document, separatorAfter),
353
+ insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet, documentation: ''
354
+ });
355
+ }
356
+ if (value.type === 'boolean') {
357
+ this.addBooleanValueCompletion(!value.value, separatorAfter, collector);
358
+ }
359
+ };
360
+ if (node.type === 'property') {
361
+ if (offset > (node.colonOffset || 0)) {
362
+ const valueNode = node.valueNode;
363
+ if (valueNode && (offset > (valueNode.offset + valueNode.length) || valueNode.type === 'object' || valueNode.type === 'array')) {
364
+ return;
365
+ }
366
+ // suggest values at the same key
367
+ const parentKey = node.keyNode.value;
368
+ doc.visit(n => {
369
+ if (n.type === 'property' && n.keyNode.value === parentKey && n.valueNode) {
370
+ collectSuggestionsForValues(n.valueNode);
371
+ }
372
+ return true;
373
+ });
374
+ if (parentKey === '$schema' && node.parent && !node.parent.parent) {
375
+ this.addDollarSchemaCompletions(separatorAfter, collector);
376
+ }
377
+ }
378
+ }
379
+ if (node.type === 'array') {
380
+ if (node.parent && node.parent.type === 'property') {
381
+ // suggest items of an array at the same key
382
+ const parentKey = node.parent.keyNode.value;
383
+ doc.visit((n) => {
384
+ if (n.type === 'property' && n.keyNode.value === parentKey && n.valueNode && n.valueNode.type === 'array') {
385
+ n.valueNode.items.forEach(collectSuggestionsForValues);
386
+ }
387
+ return true;
388
+ });
389
+ }
390
+ else {
391
+ // suggest items in the same array
392
+ node.items.forEach(collectSuggestionsForValues);
393
+ }
394
+ }
395
+ }
396
+ getValueCompletions(schema, doc, node, offset, document, collector, types) {
397
+ let offsetForSeparator = offset;
398
+ let parentKey = undefined;
399
+ let valueNode = undefined;
400
+ if (node && (node.type === 'string' || node.type === 'number' || node.type === 'boolean' || node.type === 'null')) {
401
+ offsetForSeparator = node.offset + node.length;
402
+ valueNode = node;
403
+ node = node.parent;
404
+ }
405
+ if (!node) {
406
+ this.addSchemaValueCompletions(schema.schema, '', collector, types);
407
+ return;
408
+ }
409
+ if ((node.type === 'property') && offset > (node.colonOffset || 0)) {
410
+ const valueNode = node.valueNode;
411
+ if (valueNode && offset > (valueNode.offset + valueNode.length)) {
412
+ return; // we are past the value node
413
+ }
414
+ parentKey = node.keyNode.value;
415
+ node = node.parent;
416
+ }
417
+ if (node && (parentKey !== undefined || node.type === 'array')) {
418
+ const separatorAfter = this.evaluateSeparatorAfter(document, offsetForSeparator);
419
+ const matchingSchemas = doc.getMatchingSchemas(schema.schema, node.offset, valueNode);
420
+ for (const s of matchingSchemas) {
421
+ if (s.node === node && !s.inverted && s.schema) {
422
+ if (node.type === 'array' && s.schema.items) {
423
+ if (Array.isArray(s.schema.items)) {
424
+ const index = this.findItemAtOffset(node, document, offset);
425
+ if (index < s.schema.items.length) {
426
+ this.addSchemaValueCompletions(s.schema.items[index], separatorAfter, collector, types);
427
+ }
428
+ }
429
+ else {
430
+ this.addSchemaValueCompletions(s.schema.items, separatorAfter, collector, types);
431
+ }
432
+ }
433
+ if (parentKey !== undefined) {
434
+ let propertyMatched = false;
435
+ if (s.schema.properties) {
436
+ const propertySchema = s.schema.properties[parentKey];
437
+ if (propertySchema) {
438
+ propertyMatched = true;
439
+ this.addSchemaValueCompletions(propertySchema, separatorAfter, collector, types);
440
+ }
441
+ }
442
+ if (s.schema.patternProperties && !propertyMatched) {
443
+ for (const pattern of Object.keys(s.schema.patternProperties)) {
444
+ const regex = (0, strings_1.extendedRegExp)(pattern);
445
+ if (regex?.test(parentKey)) {
446
+ propertyMatched = true;
447
+ const propertySchema = s.schema.patternProperties[pattern];
448
+ this.addSchemaValueCompletions(propertySchema, separatorAfter, collector, types);
449
+ }
450
+ }
451
+ }
452
+ if (s.schema.additionalProperties && !propertyMatched) {
453
+ const propertySchema = s.schema.additionalProperties;
454
+ this.addSchemaValueCompletions(propertySchema, separatorAfter, collector, types);
455
+ }
456
+ }
457
+ }
458
+ }
459
+ if (parentKey === '$schema' && !node.parent) {
460
+ this.addDollarSchemaCompletions(separatorAfter, collector);
461
+ }
462
+ if (types['boolean']) {
463
+ this.addBooleanValueCompletion(true, separatorAfter, collector);
464
+ this.addBooleanValueCompletion(false, separatorAfter, collector);
465
+ }
466
+ if (types['null']) {
467
+ this.addNullValueCompletion(separatorAfter, collector);
468
+ }
469
+ }
470
+ }
471
+ getContributedValueCompletions(doc, node, offset, document, collector, collectionPromises) {
472
+ if (!node) {
473
+ this.contributions.forEach((contribution) => {
474
+ const collectPromise = contribution.collectDefaultCompletions(document.uri, collector);
475
+ if (collectPromise) {
476
+ collectionPromises.push(collectPromise);
477
+ }
478
+ });
479
+ }
480
+ else {
481
+ if (node.type === 'string' || node.type === 'number' || node.type === 'boolean' || node.type === 'null') {
482
+ node = node.parent;
483
+ }
484
+ if (node && (node.type === 'property') && offset > (node.colonOffset || 0)) {
485
+ const parentKey = node.keyNode.value;
486
+ const valueNode = node.valueNode;
487
+ if ((!valueNode || offset <= (valueNode.offset + valueNode.length)) && node.parent) {
488
+ const location = Parser.getNodePath(node.parent);
489
+ this.contributions.forEach((contribution) => {
490
+ const collectPromise = contribution.collectValueCompletions(document.uri, location, parentKey, collector);
491
+ if (collectPromise) {
492
+ collectionPromises.push(collectPromise);
493
+ }
494
+ });
495
+ }
496
+ }
497
+ }
498
+ }
499
+ addSchemaValueCompletions(schema, separatorAfter, collector, types) {
500
+ if (typeof schema === 'object') {
501
+ this.addEnumValueCompletions(schema, separatorAfter, collector);
502
+ this.addDefaultValueCompletions(schema, separatorAfter, collector);
503
+ this.collectTypes(schema, types);
504
+ if (Array.isArray(schema.allOf)) {
505
+ schema.allOf.forEach(s => this.addSchemaValueCompletions(s, separatorAfter, collector, types));
506
+ }
507
+ if (Array.isArray(schema.anyOf)) {
508
+ schema.anyOf.forEach(s => this.addSchemaValueCompletions(s, separatorAfter, collector, types));
509
+ }
510
+ if (Array.isArray(schema.oneOf)) {
511
+ schema.oneOf.forEach(s => this.addSchemaValueCompletions(s, separatorAfter, collector, types));
512
+ }
513
+ }
514
+ }
515
+ addDefaultValueCompletions(schema, separatorAfter, collector, arrayDepth = 0) {
516
+ let hasProposals = false;
517
+ if ((0, objects_1.isDefined)(schema.default)) {
518
+ let type = schema.type;
519
+ let value = schema.default;
520
+ for (let i = arrayDepth; i > 0; i--) {
521
+ value = [value];
522
+ type = 'array';
523
+ }
524
+ collector.add({
525
+ kind: this.getSuggestionKind(type),
526
+ label: this.getLabelForValue(value),
527
+ insertText: this.getInsertTextForValue(value, separatorAfter),
528
+ insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
529
+ detail: localize('json.suggest.default', 'Default value')
530
+ });
531
+ hasProposals = true;
532
+ }
533
+ if (Array.isArray(schema.examples)) {
534
+ schema.examples.forEach(example => {
535
+ let type = schema.type;
536
+ let value = example;
537
+ for (let i = arrayDepth; i > 0; i--) {
538
+ value = [value];
539
+ type = 'array';
540
+ }
541
+ collector.add({
542
+ kind: this.getSuggestionKind(type),
543
+ label: this.getLabelForValue(value),
544
+ insertText: this.getInsertTextForValue(value, separatorAfter),
545
+ insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet
546
+ });
547
+ hasProposals = true;
548
+ });
549
+ }
550
+ if (Array.isArray(schema.defaultSnippets)) {
551
+ schema.defaultSnippets.forEach(s => {
552
+ let type = schema.type;
553
+ let value = s.body;
554
+ let label = s.label;
555
+ let insertText;
556
+ let filterText;
557
+ if ((0, objects_1.isDefined)(value)) {
558
+ let type = schema.type;
559
+ for (let i = arrayDepth; i > 0; i--) {
560
+ value = [value];
561
+ type = 'array';
562
+ }
563
+ insertText = this.getInsertTextForSnippetValue(value, separatorAfter);
564
+ filterText = this.getFilterTextForSnippetValue(value);
565
+ label = label || this.getLabelForSnippetValue(value);
566
+ }
567
+ else if (typeof s.bodyText === 'string') {
568
+ let prefix = '', suffix = '', indent = '';
569
+ for (let i = arrayDepth; i > 0; i--) {
570
+ prefix = prefix + indent + '[\n';
571
+ suffix = suffix + '\n' + indent + ']';
572
+ indent += '\t';
573
+ type = 'array';
574
+ }
575
+ insertText = prefix + indent + s.bodyText.split('\n').join('\n' + indent) + suffix + separatorAfter;
576
+ label = label || insertText,
577
+ filterText = insertText.replace(/[\n]/g, ''); // remove new lines
578
+ }
579
+ else {
580
+ return;
581
+ }
582
+ collector.add({
583
+ kind: this.getSuggestionKind(type),
584
+ label,
585
+ documentation: this.fromMarkup(s.markdownDescription) || s.description,
586
+ insertText,
587
+ insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
588
+ filterText
589
+ });
590
+ hasProposals = true;
591
+ });
592
+ }
593
+ if (!hasProposals && typeof schema.items === 'object' && !Array.isArray(schema.items) && arrayDepth < 5 /* beware of recursion */) {
594
+ this.addDefaultValueCompletions(schema.items, separatorAfter, collector, arrayDepth + 1);
595
+ }
596
+ }
597
+ addEnumValueCompletions(schema, separatorAfter, collector) {
598
+ if ((0, objects_1.isDefined)(schema.const)) {
599
+ collector.add({
600
+ kind: this.getSuggestionKind(schema.type),
601
+ label: this.getLabelForValue(schema.const),
602
+ insertText: this.getInsertTextForValue(schema.const, separatorAfter),
603
+ insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
604
+ documentation: this.fromMarkup(schema.markdownDescription) || schema.description
605
+ });
606
+ }
607
+ if (Array.isArray(schema.enum)) {
608
+ for (let i = 0, length = schema.enum.length; i < length; i++) {
609
+ const enm = schema.enum[i];
610
+ let documentation = this.fromMarkup(schema.markdownDescription) || schema.description;
611
+ if (schema.markdownEnumDescriptions && i < schema.markdownEnumDescriptions.length && this.doesSupportMarkdown()) {
612
+ documentation = this.fromMarkup(schema.markdownEnumDescriptions[i]);
613
+ }
614
+ else if (schema.enumDescriptions && i < schema.enumDescriptions.length) {
615
+ documentation = schema.enumDescriptions[i];
616
+ }
617
+ collector.add({
618
+ kind: this.getSuggestionKind(schema.type),
619
+ label: this.getLabelForValue(enm),
620
+ insertText: this.getInsertTextForValue(enm, separatorAfter),
621
+ insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
622
+ documentation
623
+ });
624
+ }
625
+ }
626
+ }
627
+ collectTypes(schema, types) {
628
+ if (Array.isArray(schema.enum) || (0, objects_1.isDefined)(schema.const)) {
629
+ return;
630
+ }
631
+ const type = schema.type;
632
+ if (Array.isArray(type)) {
633
+ type.forEach(t => types[t] = true);
634
+ }
635
+ else if (type) {
636
+ types[type] = true;
637
+ }
638
+ }
639
+ addFillerValueCompletions(types, separatorAfter, collector) {
640
+ if (types['object']) {
641
+ collector.add({
642
+ kind: this.getSuggestionKind('object'),
643
+ label: '{}',
644
+ insertText: this.getInsertTextForGuessedValue({}, separatorAfter),
645
+ insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
646
+ detail: localize('defaults.object', 'New object'),
647
+ documentation: ''
648
+ });
649
+ }
650
+ if (types['array']) {
651
+ collector.add({
652
+ kind: this.getSuggestionKind('array'),
653
+ label: '[]',
654
+ insertText: this.getInsertTextForGuessedValue([], separatorAfter),
655
+ insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
656
+ detail: localize('defaults.array', 'New array'),
657
+ documentation: ''
658
+ });
659
+ }
660
+ }
661
+ addBooleanValueCompletion(value, separatorAfter, collector) {
662
+ collector.add({
663
+ kind: this.getSuggestionKind('boolean'),
664
+ label: value ? 'true' : 'false',
665
+ insertText: this.getInsertTextForValue(value, separatorAfter),
666
+ insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
667
+ documentation: ''
668
+ });
669
+ }
670
+ addNullValueCompletion(separatorAfter, collector) {
671
+ collector.add({
672
+ kind: this.getSuggestionKind('null'),
673
+ label: 'null',
674
+ insertText: 'null' + separatorAfter,
675
+ insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet,
676
+ documentation: ''
677
+ });
678
+ }
679
+ addDollarSchemaCompletions(separatorAfter, collector) {
680
+ const schemaIds = this.schemaService.getRegisteredSchemaIds(schema => schema === 'http' || schema === 'https');
681
+ schemaIds.forEach(schemaId => collector.add({
682
+ kind: jsonLanguageTypes_1.CompletionItemKind.Module,
683
+ label: this.getLabelForValue(schemaId),
684
+ filterText: this.getFilterTextForValue(schemaId),
685
+ insertText: this.getInsertTextForValue(schemaId, separatorAfter),
686
+ insertTextFormat: jsonLanguageTypes_1.InsertTextFormat.Snippet, documentation: ''
687
+ }));
688
+ }
689
+ getLabelForValue(value) {
690
+ return JSON.stringify(value);
691
+ }
692
+ getFilterTextForValue(value) {
693
+ return JSON.stringify(value);
694
+ }
695
+ getFilterTextForSnippetValue(value) {
696
+ return JSON.stringify(value).replace(/\$\{\d+:([^}]+)\}|\$\d+/g, '$1');
697
+ }
698
+ getLabelForSnippetValue(value) {
699
+ const label = JSON.stringify(value);
700
+ return label.replace(/\$\{\d+:([^}]+)\}|\$\d+/g, '$1');
701
+ }
702
+ getInsertTextForPlainText(text) {
703
+ return text.replace(/[\\\$\}]/g, '\\$&'); // escape $, \ and }
704
+ }
705
+ getInsertTextForValue(value, separatorAfter) {
706
+ var text = JSON.stringify(value, null, '\t');
707
+ if (text === '{}') {
708
+ return '{$1}' + separatorAfter;
709
+ }
710
+ else if (text === '[]') {
711
+ return '[$1]' + separatorAfter;
712
+ }
713
+ return this.getInsertTextForPlainText(text + separatorAfter);
714
+ }
715
+ getInsertTextForSnippetValue(value, separatorAfter) {
716
+ const replacer = (value) => {
717
+ if (typeof value === 'string') {
718
+ if (value[0] === '^') {
719
+ return value.substr(1);
720
+ }
721
+ }
722
+ return JSON.stringify(value);
723
+ };
724
+ return (0, json_1.stringifyObject)(value, '', replacer) + separatorAfter;
725
+ }
726
+ getInsertTextForGuessedValue(value, separatorAfter) {
727
+ switch (typeof value) {
728
+ case 'object':
729
+ if (value === null) {
730
+ return '${1:null}' + separatorAfter;
731
+ }
732
+ return this.getInsertTextForValue(value, separatorAfter);
733
+ case 'string':
734
+ let snippetValue = JSON.stringify(value);
735
+ snippetValue = snippetValue.substr(1, snippetValue.length - 2); // remove quotes
736
+ snippetValue = this.getInsertTextForPlainText(snippetValue); // escape \ and }
737
+ return '"${1:' + snippetValue + '}"' + separatorAfter;
738
+ case 'number':
739
+ case 'boolean':
740
+ return '${1:' + JSON.stringify(value) + '}' + separatorAfter;
741
+ }
742
+ return this.getInsertTextForValue(value, separatorAfter);
743
+ }
744
+ getSuggestionKind(type) {
745
+ if (Array.isArray(type)) {
746
+ const array = type;
747
+ type = array.length > 0 ? array[0] : undefined;
748
+ }
749
+ if (!type) {
750
+ return jsonLanguageTypes_1.CompletionItemKind.Value;
751
+ }
752
+ switch (type) {
753
+ case 'string': return jsonLanguageTypes_1.CompletionItemKind.Value;
754
+ case 'object': return jsonLanguageTypes_1.CompletionItemKind.Module;
755
+ case 'property': return jsonLanguageTypes_1.CompletionItemKind.Property;
756
+ default: return jsonLanguageTypes_1.CompletionItemKind.Value;
757
+ }
758
+ }
759
+ getLabelTextForMatchingNode(node, document) {
760
+ switch (node.type) {
761
+ case 'array':
762
+ return '[]';
763
+ case 'object':
764
+ return '{}';
765
+ default:
766
+ const content = document.getText().substr(node.offset, node.length);
767
+ return content;
768
+ }
769
+ }
770
+ getInsertTextForMatchingNode(node, document, separatorAfter) {
771
+ switch (node.type) {
772
+ case 'array':
773
+ return this.getInsertTextForValue([], separatorAfter);
774
+ case 'object':
775
+ return this.getInsertTextForValue({}, separatorAfter);
776
+ default:
777
+ const content = document.getText().substr(node.offset, node.length) + separatorAfter;
778
+ return this.getInsertTextForPlainText(content);
779
+ }
780
+ }
781
+ getInsertTextForProperty(key, propertySchema, addValue, separatorAfter) {
782
+ const propertyText = this.getInsertTextForValue(key, '');
783
+ if (!addValue) {
784
+ return propertyText;
785
+ }
786
+ const resultText = propertyText + ': ';
787
+ let value;
788
+ let nValueProposals = 0;
789
+ if (propertySchema) {
790
+ if (Array.isArray(propertySchema.defaultSnippets)) {
791
+ if (propertySchema.defaultSnippets.length === 1) {
792
+ const body = propertySchema.defaultSnippets[0].body;
793
+ if ((0, objects_1.isDefined)(body)) {
794
+ value = this.getInsertTextForSnippetValue(body, '');
795
+ }
796
+ }
797
+ nValueProposals += propertySchema.defaultSnippets.length;
798
+ }
799
+ if (propertySchema.enum) {
800
+ if (!value && propertySchema.enum.length === 1) {
801
+ value = this.getInsertTextForGuessedValue(propertySchema.enum[0], '');
802
+ }
803
+ nValueProposals += propertySchema.enum.length;
804
+ }
805
+ if ((0, objects_1.isDefined)(propertySchema.default)) {
806
+ if (!value) {
807
+ value = this.getInsertTextForGuessedValue(propertySchema.default, '');
808
+ }
809
+ nValueProposals++;
810
+ }
811
+ if (Array.isArray(propertySchema.examples) && propertySchema.examples.length) {
812
+ if (!value) {
813
+ value = this.getInsertTextForGuessedValue(propertySchema.examples[0], '');
814
+ }
815
+ nValueProposals += propertySchema.examples.length;
816
+ }
817
+ if (nValueProposals === 0) {
818
+ var type = Array.isArray(propertySchema.type) ? propertySchema.type[0] : propertySchema.type;
819
+ if (!type) {
820
+ if (propertySchema.properties) {
821
+ type = 'object';
822
+ }
823
+ else if (propertySchema.items) {
824
+ type = 'array';
825
+ }
826
+ }
827
+ switch (type) {
828
+ case 'boolean':
829
+ value = '$1';
830
+ break;
831
+ case 'string':
832
+ value = '"$1"';
833
+ break;
834
+ case 'object':
835
+ value = '{$1}';
836
+ break;
837
+ case 'array':
838
+ value = '[$1]';
839
+ break;
840
+ case 'number':
841
+ case 'integer':
842
+ value = '${1:0}';
843
+ break;
844
+ case 'null':
845
+ value = '${1:null}';
846
+ break;
847
+ default:
848
+ return propertyText;
849
+ }
850
+ }
851
+ }
852
+ if (!value || nValueProposals > 1) {
853
+ value = '$1';
854
+ }
855
+ return resultText + value + separatorAfter;
856
+ }
857
+ getCurrentWord(document, offset) {
858
+ var i = offset - 1;
859
+ var text = document.getText();
860
+ while (i >= 0 && ' \t\n\r\v":{[,]}'.indexOf(text.charAt(i)) === -1) {
861
+ i--;
862
+ }
863
+ return text.substring(i + 1, offset);
864
+ }
865
+ evaluateSeparatorAfter(document, offset) {
866
+ const scanner = Json.createScanner(document.getText(), true);
867
+ scanner.setPosition(offset);
868
+ const token = scanner.scan();
869
+ switch (token) {
870
+ case 5 /* CommaToken */:
871
+ case 2 /* CloseBraceToken */:
872
+ case 4 /* CloseBracketToken */:
873
+ case 17 /* EOF */:
874
+ return '';
875
+ default:
876
+ return ',';
877
+ }
878
+ }
879
+ findItemAtOffset(node, document, offset) {
880
+ const scanner = Json.createScanner(document.getText(), true);
881
+ const children = node.items;
882
+ for (let i = children.length - 1; i >= 0; i--) {
883
+ const child = children[i];
884
+ if (offset > child.offset + child.length) {
885
+ scanner.setPosition(child.offset + child.length);
886
+ const token = scanner.scan();
887
+ if (token === 5 /* CommaToken */ && offset >= scanner.getTokenOffset() + scanner.getTokenLength()) {
888
+ return i + 1;
889
+ }
890
+ return i;
891
+ }
892
+ else if (offset >= child.offset) {
893
+ return i;
894
+ }
895
+ }
896
+ return 0;
897
+ }
898
+ isInComment(document, start, offset) {
899
+ const scanner = Json.createScanner(document.getText(), false);
900
+ scanner.setPosition(start);
901
+ let token = scanner.scan();
902
+ while (token !== 17 /* EOF */ && (scanner.getTokenOffset() + scanner.getTokenLength() < offset)) {
903
+ token = scanner.scan();
904
+ }
905
+ return (token === 12 /* LineCommentTrivia */ || token === 13 /* BlockCommentTrivia */) && scanner.getTokenOffset() <= offset;
906
+ }
907
+ fromMarkup(markupString) {
908
+ if (markupString && this.doesSupportMarkdown()) {
909
+ return {
910
+ kind: jsonLanguageTypes_1.MarkupKind.Markdown,
911
+ value: markupString
912
+ };
913
+ }
914
+ return undefined;
915
+ }
916
+ doesSupportMarkdown() {
917
+ if (!(0, objects_1.isDefined)(this.supportsMarkdown)) {
918
+ const completion = this.clientCapabilities.textDocument && this.clientCapabilities.textDocument.completion;
919
+ this.supportsMarkdown = completion && completion.completionItem && Array.isArray(completion.completionItem.documentationFormat) && completion.completionItem.documentationFormat.indexOf(jsonLanguageTypes_1.MarkupKind.Markdown) !== -1;
920
+ }
921
+ return this.supportsMarkdown;
922
+ }
923
+ doesSupportsCommitCharacters() {
924
+ if (!(0, objects_1.isDefined)(this.supportsCommitCharacters)) {
925
+ const completion = this.clientCapabilities.textDocument && this.clientCapabilities.textDocument.completion;
926
+ this.supportsCommitCharacters = completion && completion.completionItem && !!completion.completionItem.commitCharactersSupport;
927
+ }
928
+ return this.supportsCommitCharacters;
929
+ }
930
+ }
931
+ exports.JSONCompletion = JSONCompletion;
932
+ });