massive update, probably broken
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-json / node_modules / vscode-json-languageservice / lib / esm / services / jsonCompletion.js
diff --git a/.config/coc/extensions/node_modules/coc-json/node_modules/vscode-json-languageservice/lib/esm/services/jsonCompletion.js b/.config/coc/extensions/node_modules/coc-json/node_modules/vscode-json-languageservice/lib/esm/services/jsonCompletion.js
new file mode 100644 (file)
index 0000000..c271c21
--- /dev/null
@@ -0,0 +1,934 @@
+/*---------------------------------------------------------------------------------------------
+ *  Copyright (c) Microsoft Corporation. All rights reserved.
+ *  Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+import * as Parser from '../parser/jsonParser';
+import * as Json from 'jsonc-parser';
+import { stringifyObject } from '../utils/json';
+import { endsWith, extendedRegExp } from '../utils/strings';
+import { isDefined } from '../utils/objects';
+import { CompletionItem, CompletionItemKind, Range, TextEdit, InsertTextFormat, MarkupKind } from '../jsonLanguageTypes';
+import * as nls from 'vscode-nls';
+var localize = nls.loadMessageBundle();
+var valueCommitCharacters = [',', '}', ']'];
+var propertyCommitCharacters = [':'];
+var JSONCompletion = /** @class */ (function () {
+    function JSONCompletion(schemaService, contributions, promiseConstructor, clientCapabilities) {
+        if (contributions === void 0) { contributions = []; }
+        if (promiseConstructor === void 0) { promiseConstructor = Promise; }
+        if (clientCapabilities === void 0) { clientCapabilities = {}; }
+        this.schemaService = schemaService;
+        this.contributions = contributions;
+        this.promiseConstructor = promiseConstructor;
+        this.clientCapabilities = clientCapabilities;
+    }
+    JSONCompletion.prototype.doResolve = function (item) {
+        for (var i = this.contributions.length - 1; i >= 0; i--) {
+            var resolveCompletion = this.contributions[i].resolveCompletion;
+            if (resolveCompletion) {
+                var resolver = resolveCompletion(item);
+                if (resolver) {
+                    return resolver;
+                }
+            }
+        }
+        return this.promiseConstructor.resolve(item);
+    };
+    JSONCompletion.prototype.doComplete = function (document, position, doc) {
+        var _this = this;
+        var result = {
+            items: [],
+            isIncomplete: false
+        };
+        var text = document.getText();
+        var offset = document.offsetAt(position);
+        var node = doc.getNodeFromOffset(offset, true);
+        if (this.isInComment(document, node ? node.offset : 0, offset)) {
+            return Promise.resolve(result);
+        }
+        if (node && (offset === node.offset + node.length) && offset > 0) {
+            var ch = text[offset - 1];
+            if (node.type === 'object' && ch === '}' || node.type === 'array' && ch === ']') {
+                // after ] or }
+                node = node.parent;
+            }
+        }
+        var currentWord = this.getCurrentWord(document, offset);
+        var overwriteRange;
+        if (node && (node.type === 'string' || node.type === 'number' || node.type === 'boolean' || node.type === 'null')) {
+            overwriteRange = Range.create(document.positionAt(node.offset), document.positionAt(node.offset + node.length));
+        }
+        else {
+            var overwriteStart = offset - currentWord.length;
+            if (overwriteStart > 0 && text[overwriteStart - 1] === '"') {
+                overwriteStart--;
+            }
+            overwriteRange = Range.create(document.positionAt(overwriteStart), position);
+        }
+        var supportsCommitCharacters = false; //this.doesSupportsCommitCharacters(); disabled for now, waiting for new API: https://github.com/microsoft/vscode/issues/42544
+        var proposed = {};
+        var collector = {
+            add: function (suggestion) {
+                var label = suggestion.label;
+                var existing = proposed[label];
+                if (!existing) {
+                    label = label.replace(/[\n]/g, '↵');
+                    if (label.length > 60) {
+                        var shortendedLabel = label.substr(0, 57).trim() + '...';
+                        if (!proposed[shortendedLabel]) {
+                            label = shortendedLabel;
+                        }
+                    }
+                    if (overwriteRange && suggestion.insertText !== undefined) {
+                        suggestion.textEdit = TextEdit.replace(overwriteRange, suggestion.insertText);
+                    }
+                    if (supportsCommitCharacters) {
+                        suggestion.commitCharacters = suggestion.kind === CompletionItemKind.Property ? propertyCommitCharacters : valueCommitCharacters;
+                    }
+                    suggestion.label = label;
+                    proposed[label] = suggestion;
+                    result.items.push(suggestion);
+                }
+                else {
+                    if (!existing.documentation) {
+                        existing.documentation = suggestion.documentation;
+                    }
+                    if (!existing.detail) {
+                        existing.detail = suggestion.detail;
+                    }
+                }
+            },
+            setAsIncomplete: function () {
+                result.isIncomplete = true;
+            },
+            error: function (message) {
+                console.error(message);
+            },
+            log: function (message) {
+                console.log(message);
+            },
+            getNumberOfProposals: function () {
+                return result.items.length;
+            }
+        };
+        return this.schemaService.getSchemaForResource(document.uri, doc).then(function (schema) {
+            var collectionPromises = [];
+            var addValue = true;
+            var currentKey = '';
+            var currentProperty = undefined;
+            if (node) {
+                if (node.type === 'string') {
+                    var parent = node.parent;
+                    if (parent && parent.type === 'property' && parent.keyNode === node) {
+                        addValue = !parent.valueNode;
+                        currentProperty = parent;
+                        currentKey = text.substr(node.offset + 1, node.length - 2);
+                        if (parent) {
+                            node = parent.parent;
+                        }
+                    }
+                }
+            }
+            // proposals for properties
+            if (node && node.type === 'object') {
+                // don't suggest keys when the cursor is just before the opening curly brace
+                if (node.offset === offset) {
+                    return result;
+                }
+                // don't suggest properties that are already present
+                var properties = node.properties;
+                properties.forEach(function (p) {
+                    if (!currentProperty || currentProperty !== p) {
+                        proposed[p.keyNode.value] = CompletionItem.create('__');
+                    }
+                });
+                var separatorAfter_1 = '';
+                if (addValue) {
+                    separatorAfter_1 = _this.evaluateSeparatorAfter(document, document.offsetAt(overwriteRange.end));
+                }
+                if (schema) {
+                    // property proposals with schema
+                    _this.getPropertyCompletions(schema, doc, node, addValue, separatorAfter_1, collector);
+                }
+                else {
+                    // property proposals without schema
+                    _this.getSchemaLessPropertyCompletions(doc, node, currentKey, collector);
+                }
+                var location_1 = Parser.getNodePath(node);
+                _this.contributions.forEach(function (contribution) {
+                    var collectPromise = contribution.collectPropertyCompletions(document.uri, location_1, currentWord, addValue, separatorAfter_1 === '', collector);
+                    if (collectPromise) {
+                        collectionPromises.push(collectPromise);
+                    }
+                });
+                if ((!schema && currentWord.length > 0 && text.charAt(offset - currentWord.length - 1) !== '"')) {
+                    collector.add({
+                        kind: CompletionItemKind.Property,
+                        label: _this.getLabelForValue(currentWord),
+                        insertText: _this.getInsertTextForProperty(currentWord, undefined, false, separatorAfter_1),
+                        insertTextFormat: InsertTextFormat.Snippet, documentation: '',
+                    });
+                    collector.setAsIncomplete();
+                }
+            }
+            // proposals for values
+            var types = {};
+            if (schema) {
+                // value proposals with schema
+                _this.getValueCompletions(schema, doc, node, offset, document, collector, types);
+            }
+            else {
+                // value proposals without schema
+                _this.getSchemaLessValueCompletions(doc, node, offset, document, collector);
+            }
+            if (_this.contributions.length > 0) {
+                _this.getContributedValueCompletions(doc, node, offset, document, collector, collectionPromises);
+            }
+            return _this.promiseConstructor.all(collectionPromises).then(function () {
+                if (collector.getNumberOfProposals() === 0) {
+                    var offsetForSeparator = offset;
+                    if (node && (node.type === 'string' || node.type === 'number' || node.type === 'boolean' || node.type === 'null')) {
+                        offsetForSeparator = node.offset + node.length;
+                    }
+                    var separatorAfter = _this.evaluateSeparatorAfter(document, offsetForSeparator);
+                    _this.addFillerValueCompletions(types, separatorAfter, collector);
+                }
+                return result;
+            });
+        });
+    };
+    JSONCompletion.prototype.getPropertyCompletions = function (schema, doc, node, addValue, separatorAfter, collector) {
+        var _this = this;
+        var matchingSchemas = doc.getMatchingSchemas(schema.schema, node.offset);
+        matchingSchemas.forEach(function (s) {
+            if (s.node === node && !s.inverted) {
+                var schemaProperties_1 = s.schema.properties;
+                if (schemaProperties_1) {
+                    Object.keys(schemaProperties_1).forEach(function (key) {
+                        var propertySchema = schemaProperties_1[key];
+                        if (typeof propertySchema === 'object' && !propertySchema.deprecationMessage && !propertySchema.doNotSuggest) {
+                            var proposal = {
+                                kind: CompletionItemKind.Property,
+                                label: key,
+                                insertText: _this.getInsertTextForProperty(key, propertySchema, addValue, separatorAfter),
+                                insertTextFormat: InsertTextFormat.Snippet,
+                                filterText: _this.getFilterTextForValue(key),
+                                documentation: _this.fromMarkup(propertySchema.markdownDescription) || propertySchema.description || '',
+                            };
+                            if (propertySchema.suggestSortText !== undefined) {
+                                proposal.sortText = propertySchema.suggestSortText;
+                            }
+                            if (proposal.insertText && endsWith(proposal.insertText, "$1" + separatorAfter)) {
+                                proposal.command = {
+                                    title: 'Suggest',
+                                    command: 'editor.action.triggerSuggest'
+                                };
+                            }
+                            collector.add(proposal);
+                        }
+                    });
+                }
+                var schemaPropertyNames_1 = s.schema.propertyNames;
+                if (typeof schemaPropertyNames_1 === 'object' && !schemaPropertyNames_1.deprecationMessage && !schemaPropertyNames_1.doNotSuggest) {
+                    var propertyNameCompletionItem = function (name, enumDescription) {
+                        if (enumDescription === void 0) { enumDescription = undefined; }
+                        var proposal = {
+                            kind: CompletionItemKind.Property,
+                            label: name,
+                            insertText: _this.getInsertTextForProperty(name, undefined, addValue, separatorAfter),
+                            insertTextFormat: InsertTextFormat.Snippet,
+                            filterText: _this.getFilterTextForValue(name),
+                            documentation: enumDescription || _this.fromMarkup(schemaPropertyNames_1.markdownDescription) || schemaPropertyNames_1.description || '',
+                        };
+                        if (schemaPropertyNames_1.suggestSortText !== undefined) {
+                            proposal.sortText = schemaPropertyNames_1.suggestSortText;
+                        }
+                        if (proposal.insertText && endsWith(proposal.insertText, "$1" + separatorAfter)) {
+                            proposal.command = {
+                                title: 'Suggest',
+                                command: 'editor.action.triggerSuggest'
+                            };
+                        }
+                        collector.add(proposal);
+                    };
+                    if (schemaPropertyNames_1.enum) {
+                        for (var i = 0; i < schemaPropertyNames_1.enum.length; i++) {
+                            var enumDescription = undefined;
+                            if (schemaPropertyNames_1.markdownEnumDescriptions && i < schemaPropertyNames_1.markdownEnumDescriptions.length) {
+                                enumDescription = _this.fromMarkup(schemaPropertyNames_1.markdownEnumDescriptions[i]);
+                            }
+                            else if (schemaPropertyNames_1.enumDescriptions && i < schemaPropertyNames_1.enumDescriptions.length) {
+                                enumDescription = schemaPropertyNames_1.enumDescriptions[i];
+                            }
+                            propertyNameCompletionItem(schemaPropertyNames_1.enum[i], enumDescription);
+                        }
+                    }
+                    if (schemaPropertyNames_1.const) {
+                        propertyNameCompletionItem(schemaPropertyNames_1.const);
+                    }
+                }
+            }
+        });
+    };
+    JSONCompletion.prototype.getSchemaLessPropertyCompletions = function (doc, node, currentKey, collector) {
+        var _this = this;
+        var collectCompletionsForSimilarObject = function (obj) {
+            obj.properties.forEach(function (p) {
+                var key = p.keyNode.value;
+                collector.add({
+                    kind: CompletionItemKind.Property,
+                    label: key,
+                    insertText: _this.getInsertTextForValue(key, ''),
+                    insertTextFormat: InsertTextFormat.Snippet,
+                    filterText: _this.getFilterTextForValue(key),
+                    documentation: ''
+                });
+            });
+        };
+        if (node.parent) {
+            if (node.parent.type === 'property') {
+                // if the object is a property value, check the tree for other objects that hang under a property of the same name
+                var parentKey_1 = node.parent.keyNode.value;
+                doc.visit(function (n) {
+                    if (n.type === 'property' && n !== node.parent && n.keyNode.value === parentKey_1 && n.valueNode && n.valueNode.type === 'object') {
+                        collectCompletionsForSimilarObject(n.valueNode);
+                    }
+                    return true;
+                });
+            }
+            else if (node.parent.type === 'array') {
+                // if the object is in an array, use all other array elements as similar objects
+                node.parent.items.forEach(function (n) {
+                    if (n.type === 'object' && n !== node) {
+                        collectCompletionsForSimilarObject(n);
+                    }
+                });
+            }
+        }
+        else if (node.type === 'object') {
+            collector.add({
+                kind: CompletionItemKind.Property,
+                label: '$schema',
+                insertText: this.getInsertTextForProperty('$schema', undefined, true, ''),
+                insertTextFormat: InsertTextFormat.Snippet, documentation: '',
+                filterText: this.getFilterTextForValue("$schema")
+            });
+        }
+    };
+    JSONCompletion.prototype.getSchemaLessValueCompletions = function (doc, node, offset, document, collector) {
+        var _this = this;
+        var offsetForSeparator = offset;
+        if (node && (node.type === 'string' || node.type === 'number' || node.type === 'boolean' || node.type === 'null')) {
+            offsetForSeparator = node.offset + node.length;
+            node = node.parent;
+        }
+        if (!node) {
+            collector.add({
+                kind: this.getSuggestionKind('object'),
+                label: 'Empty object',
+                insertText: this.getInsertTextForValue({}, ''),
+                insertTextFormat: InsertTextFormat.Snippet,
+                documentation: ''
+            });
+            collector.add({
+                kind: this.getSuggestionKind('array'),
+                label: 'Empty array',
+                insertText: this.getInsertTextForValue([], ''),
+                insertTextFormat: InsertTextFormat.Snippet,
+                documentation: ''
+            });
+            return;
+        }
+        var separatorAfter = this.evaluateSeparatorAfter(document, offsetForSeparator);
+        var collectSuggestionsForValues = function (value) {
+            if (value.parent && !Parser.contains(value.parent, offset, true)) {
+                collector.add({
+                    kind: _this.getSuggestionKind(value.type),
+                    label: _this.getLabelTextForMatchingNode(value, document),
+                    insertText: _this.getInsertTextForMatchingNode(value, document, separatorAfter),
+                    insertTextFormat: InsertTextFormat.Snippet, documentation: ''
+                });
+            }
+            if (value.type === 'boolean') {
+                _this.addBooleanValueCompletion(!value.value, separatorAfter, collector);
+            }
+        };
+        if (node.type === 'property') {
+            if (offset > (node.colonOffset || 0)) {
+                var valueNode = node.valueNode;
+                if (valueNode && (offset > (valueNode.offset + valueNode.length) || valueNode.type === 'object' || valueNode.type === 'array')) {
+                    return;
+                }
+                // suggest values at the same key
+                var parentKey_2 = node.keyNode.value;
+                doc.visit(function (n) {
+                    if (n.type === 'property' && n.keyNode.value === parentKey_2 && n.valueNode) {
+                        collectSuggestionsForValues(n.valueNode);
+                    }
+                    return true;
+                });
+                if (parentKey_2 === '$schema' && node.parent && !node.parent.parent) {
+                    this.addDollarSchemaCompletions(separatorAfter, collector);
+                }
+            }
+        }
+        if (node.type === 'array') {
+            if (node.parent && node.parent.type === 'property') {
+                // suggest items of an array at the same key
+                var parentKey_3 = node.parent.keyNode.value;
+                doc.visit(function (n) {
+                    if (n.type === 'property' && n.keyNode.value === parentKey_3 && n.valueNode && n.valueNode.type === 'array') {
+                        n.valueNode.items.forEach(collectSuggestionsForValues);
+                    }
+                    return true;
+                });
+            }
+            else {
+                // suggest items in the same array
+                node.items.forEach(collectSuggestionsForValues);
+            }
+        }
+    };
+    JSONCompletion.prototype.getValueCompletions = function (schema, doc, node, offset, document, collector, types) {
+        var offsetForSeparator = offset;
+        var parentKey = undefined;
+        var valueNode = undefined;
+        if (node && (node.type === 'string' || node.type === 'number' || node.type === 'boolean' || node.type === 'null')) {
+            offsetForSeparator = node.offset + node.length;
+            valueNode = node;
+            node = node.parent;
+        }
+        if (!node) {
+            this.addSchemaValueCompletions(schema.schema, '', collector, types);
+            return;
+        }
+        if ((node.type === 'property') && offset > (node.colonOffset || 0)) {
+            var valueNode_1 = node.valueNode;
+            if (valueNode_1 && offset > (valueNode_1.offset + valueNode_1.length)) {
+                return; // we are past the value node
+            }
+            parentKey = node.keyNode.value;
+            node = node.parent;
+        }
+        if (node && (parentKey !== undefined || node.type === 'array')) {
+            var separatorAfter = this.evaluateSeparatorAfter(document, offsetForSeparator);
+            var matchingSchemas = doc.getMatchingSchemas(schema.schema, node.offset, valueNode);
+            for (var _i = 0, matchingSchemas_1 = matchingSchemas; _i < matchingSchemas_1.length; _i++) {
+                var s = matchingSchemas_1[_i];
+                if (s.node === node && !s.inverted && s.schema) {
+                    if (node.type === 'array' && s.schema.items) {
+                        if (Array.isArray(s.schema.items)) {
+                            var index = this.findItemAtOffset(node, document, offset);
+                            if (index < s.schema.items.length) {
+                                this.addSchemaValueCompletions(s.schema.items[index], separatorAfter, collector, types);
+                            }
+                        }
+                        else {
+                            this.addSchemaValueCompletions(s.schema.items, separatorAfter, collector, types);
+                        }
+                    }
+                    if (parentKey !== undefined) {
+                        var propertyMatched = false;
+                        if (s.schema.properties) {
+                            var propertySchema = s.schema.properties[parentKey];
+                            if (propertySchema) {
+                                propertyMatched = true;
+                                this.addSchemaValueCompletions(propertySchema, separatorAfter, collector, types);
+                            }
+                        }
+                        if (s.schema.patternProperties && !propertyMatched) {
+                            for (var _a = 0, _b = Object.keys(s.schema.patternProperties); _a < _b.length; _a++) {
+                                var pattern = _b[_a];
+                                var regex = extendedRegExp(pattern);
+                                if (regex.test(parentKey)) {
+                                    propertyMatched = true;
+                                    var propertySchema = s.schema.patternProperties[pattern];
+                                    this.addSchemaValueCompletions(propertySchema, separatorAfter, collector, types);
+                                }
+                            }
+                        }
+                        if (s.schema.additionalProperties && !propertyMatched) {
+                            var propertySchema = s.schema.additionalProperties;
+                            this.addSchemaValueCompletions(propertySchema, separatorAfter, collector, types);
+                        }
+                    }
+                }
+            }
+            if (parentKey === '$schema' && !node.parent) {
+                this.addDollarSchemaCompletions(separatorAfter, collector);
+            }
+            if (types['boolean']) {
+                this.addBooleanValueCompletion(true, separatorAfter, collector);
+                this.addBooleanValueCompletion(false, separatorAfter, collector);
+            }
+            if (types['null']) {
+                this.addNullValueCompletion(separatorAfter, collector);
+            }
+        }
+    };
+    JSONCompletion.prototype.getContributedValueCompletions = function (doc, node, offset, document, collector, collectionPromises) {
+        if (!node) {
+            this.contributions.forEach(function (contribution) {
+                var collectPromise = contribution.collectDefaultCompletions(document.uri, collector);
+                if (collectPromise) {
+                    collectionPromises.push(collectPromise);
+                }
+            });
+        }
+        else {
+            if (node.type === 'string' || node.type === 'number' || node.type === 'boolean' || node.type === 'null') {
+                node = node.parent;
+            }
+            if (node && (node.type === 'property') && offset > (node.colonOffset || 0)) {
+                var parentKey_4 = node.keyNode.value;
+                var valueNode = node.valueNode;
+                if ((!valueNode || offset <= (valueNode.offset + valueNode.length)) && node.parent) {
+                    var location_2 = Parser.getNodePath(node.parent);
+                    this.contributions.forEach(function (contribution) {
+                        var collectPromise = contribution.collectValueCompletions(document.uri, location_2, parentKey_4, collector);
+                        if (collectPromise) {
+                            collectionPromises.push(collectPromise);
+                        }
+                    });
+                }
+            }
+        }
+    };
+    JSONCompletion.prototype.addSchemaValueCompletions = function (schema, separatorAfter, collector, types) {
+        var _this = this;
+        if (typeof schema === 'object') {
+            this.addEnumValueCompletions(schema, separatorAfter, collector);
+            this.addDefaultValueCompletions(schema, separatorAfter, collector);
+            this.collectTypes(schema, types);
+            if (Array.isArray(schema.allOf)) {
+                schema.allOf.forEach(function (s) { return _this.addSchemaValueCompletions(s, separatorAfter, collector, types); });
+            }
+            if (Array.isArray(schema.anyOf)) {
+                schema.anyOf.forEach(function (s) { return _this.addSchemaValueCompletions(s, separatorAfter, collector, types); });
+            }
+            if (Array.isArray(schema.oneOf)) {
+                schema.oneOf.forEach(function (s) { return _this.addSchemaValueCompletions(s, separatorAfter, collector, types); });
+            }
+        }
+    };
+    JSONCompletion.prototype.addDefaultValueCompletions = function (schema, separatorAfter, collector, arrayDepth) {
+        var _this = this;
+        if (arrayDepth === void 0) { arrayDepth = 0; }
+        var hasProposals = false;
+        if (isDefined(schema.default)) {
+            var type = schema.type;
+            var value = schema.default;
+            for (var i = arrayDepth; i > 0; i--) {
+                value = [value];
+                type = 'array';
+            }
+            collector.add({
+                kind: this.getSuggestionKind(type),
+                label: this.getLabelForValue(value),
+                insertText: this.getInsertTextForValue(value, separatorAfter),
+                insertTextFormat: InsertTextFormat.Snippet,
+                detail: localize('json.suggest.default', 'Default value')
+            });
+            hasProposals = true;
+        }
+        if (Array.isArray(schema.examples)) {
+            schema.examples.forEach(function (example) {
+                var type = schema.type;
+                var value = example;
+                for (var i = arrayDepth; i > 0; i--) {
+                    value = [value];
+                    type = 'array';
+                }
+                collector.add({
+                    kind: _this.getSuggestionKind(type),
+                    label: _this.getLabelForValue(value),
+                    insertText: _this.getInsertTextForValue(value, separatorAfter),
+                    insertTextFormat: InsertTextFormat.Snippet
+                });
+                hasProposals = true;
+            });
+        }
+        if (Array.isArray(schema.defaultSnippets)) {
+            schema.defaultSnippets.forEach(function (s) {
+                var type = schema.type;
+                var value = s.body;
+                var label = s.label;
+                var insertText;
+                var filterText;
+                if (isDefined(value)) {
+                    var type_1 = schema.type;
+                    for (var i = arrayDepth; i > 0; i--) {
+                        value = [value];
+                        type_1 = 'array';
+                    }
+                    insertText = _this.getInsertTextForSnippetValue(value, separatorAfter);
+                    filterText = _this.getFilterTextForSnippetValue(value);
+                    label = label || _this.getLabelForSnippetValue(value);
+                }
+                else if (typeof s.bodyText === 'string') {
+                    var prefix = '', suffix = '', indent = '';
+                    for (var i = arrayDepth; i > 0; i--) {
+                        prefix = prefix + indent + '[\n';
+                        suffix = suffix + '\n' + indent + ']';
+                        indent += '\t';
+                        type = 'array';
+                    }
+                    insertText = prefix + indent + s.bodyText.split('\n').join('\n' + indent) + suffix + separatorAfter;
+                    label = label || insertText,
+                        filterText = insertText.replace(/[\n]/g, ''); // remove new lines
+                }
+                else {
+                    return;
+                }
+                collector.add({
+                    kind: _this.getSuggestionKind(type),
+                    label: label,
+                    documentation: _this.fromMarkup(s.markdownDescription) || s.description,
+                    insertText: insertText,
+                    insertTextFormat: InsertTextFormat.Snippet,
+                    filterText: filterText
+                });
+                hasProposals = true;
+            });
+        }
+        if (!hasProposals && typeof schema.items === 'object' && !Array.isArray(schema.items) && arrayDepth < 5 /* beware of recursion */) {
+            this.addDefaultValueCompletions(schema.items, separatorAfter, collector, arrayDepth + 1);
+        }
+    };
+    JSONCompletion.prototype.addEnumValueCompletions = function (schema, separatorAfter, collector) {
+        if (isDefined(schema.const)) {
+            collector.add({
+                kind: this.getSuggestionKind(schema.type),
+                label: this.getLabelForValue(schema.const),
+                insertText: this.getInsertTextForValue(schema.const, separatorAfter),
+                insertTextFormat: InsertTextFormat.Snippet,
+                documentation: this.fromMarkup(schema.markdownDescription) || schema.description
+            });
+        }
+        if (Array.isArray(schema.enum)) {
+            for (var i = 0, length = schema.enum.length; i < length; i++) {
+                var enm = schema.enum[i];
+                var documentation = this.fromMarkup(schema.markdownDescription) || schema.description;
+                if (schema.markdownEnumDescriptions && i < schema.markdownEnumDescriptions.length && this.doesSupportMarkdown()) {
+                    documentation = this.fromMarkup(schema.markdownEnumDescriptions[i]);
+                }
+                else if (schema.enumDescriptions && i < schema.enumDescriptions.length) {
+                    documentation = schema.enumDescriptions[i];
+                }
+                collector.add({
+                    kind: this.getSuggestionKind(schema.type),
+                    label: this.getLabelForValue(enm),
+                    insertText: this.getInsertTextForValue(enm, separatorAfter),
+                    insertTextFormat: InsertTextFormat.Snippet,
+                    documentation: documentation
+                });
+            }
+        }
+    };
+    JSONCompletion.prototype.collectTypes = function (schema, types) {
+        if (Array.isArray(schema.enum) || isDefined(schema.const)) {
+            return;
+        }
+        var type = schema.type;
+        if (Array.isArray(type)) {
+            type.forEach(function (t) { return types[t] = true; });
+        }
+        else if (type) {
+            types[type] = true;
+        }
+    };
+    JSONCompletion.prototype.addFillerValueCompletions = function (types, separatorAfter, collector) {
+        if (types['object']) {
+            collector.add({
+                kind: this.getSuggestionKind('object'),
+                label: '{}',
+                insertText: this.getInsertTextForGuessedValue({}, separatorAfter),
+                insertTextFormat: InsertTextFormat.Snippet,
+                detail: localize('defaults.object', 'New object'),
+                documentation: ''
+            });
+        }
+        if (types['array']) {
+            collector.add({
+                kind: this.getSuggestionKind('array'),
+                label: '[]',
+                insertText: this.getInsertTextForGuessedValue([], separatorAfter),
+                insertTextFormat: InsertTextFormat.Snippet,
+                detail: localize('defaults.array', 'New array'),
+                documentation: ''
+            });
+        }
+    };
+    JSONCompletion.prototype.addBooleanValueCompletion = function (value, separatorAfter, collector) {
+        collector.add({
+            kind: this.getSuggestionKind('boolean'),
+            label: value ? 'true' : 'false',
+            insertText: this.getInsertTextForValue(value, separatorAfter),
+            insertTextFormat: InsertTextFormat.Snippet,
+            documentation: ''
+        });
+    };
+    JSONCompletion.prototype.addNullValueCompletion = function (separatorAfter, collector) {
+        collector.add({
+            kind: this.getSuggestionKind('null'),
+            label: 'null',
+            insertText: 'null' + separatorAfter,
+            insertTextFormat: InsertTextFormat.Snippet,
+            documentation: ''
+        });
+    };
+    JSONCompletion.prototype.addDollarSchemaCompletions = function (separatorAfter, collector) {
+        var _this = this;
+        var schemaIds = this.schemaService.getRegisteredSchemaIds(function (schema) { return schema === 'http' || schema === 'https'; });
+        schemaIds.forEach(function (schemaId) { return collector.add({
+            kind: CompletionItemKind.Module,
+            label: _this.getLabelForValue(schemaId),
+            filterText: _this.getFilterTextForValue(schemaId),
+            insertText: _this.getInsertTextForValue(schemaId, separatorAfter),
+            insertTextFormat: InsertTextFormat.Snippet, documentation: ''
+        }); });
+    };
+    JSONCompletion.prototype.getLabelForValue = function (value) {
+        return JSON.stringify(value);
+    };
+    JSONCompletion.prototype.getFilterTextForValue = function (value) {
+        return JSON.stringify(value);
+    };
+    JSONCompletion.prototype.getFilterTextForSnippetValue = function (value) {
+        return JSON.stringify(value).replace(/\$\{\d+:([^}]+)\}|\$\d+/g, '$1');
+    };
+    JSONCompletion.prototype.getLabelForSnippetValue = function (value) {
+        var label = JSON.stringify(value);
+        return label.replace(/\$\{\d+:([^}]+)\}|\$\d+/g, '$1');
+    };
+    JSONCompletion.prototype.getInsertTextForPlainText = function (text) {
+        return text.replace(/[\\\$\}]/g, '\\$&'); // escape $, \ and } 
+    };
+    JSONCompletion.prototype.getInsertTextForValue = function (value, separatorAfter) {
+        var text = JSON.stringify(value, null, '\t');
+        if (text === '{}') {
+            return '{$1}' + separatorAfter;
+        }
+        else if (text === '[]') {
+            return '[$1]' + separatorAfter;
+        }
+        return this.getInsertTextForPlainText(text + separatorAfter);
+    };
+    JSONCompletion.prototype.getInsertTextForSnippetValue = function (value, separatorAfter) {
+        var replacer = function (value) {
+            if (typeof value === 'string') {
+                if (value[0] === '^') {
+                    return value.substr(1);
+                }
+            }
+            return JSON.stringify(value);
+        };
+        return stringifyObject(value, '', replacer) + separatorAfter;
+    };
+    JSONCompletion.prototype.getInsertTextForGuessedValue = function (value, separatorAfter) {
+        switch (typeof value) {
+            case 'object':
+                if (value === null) {
+                    return '${1:null}' + separatorAfter;
+                }
+                return this.getInsertTextForValue(value, separatorAfter);
+            case 'string':
+                var snippetValue = JSON.stringify(value);
+                snippetValue = snippetValue.substr(1, snippetValue.length - 2); // remove quotes
+                snippetValue = this.getInsertTextForPlainText(snippetValue); // escape \ and }
+                return '"${1:' + snippetValue + '}"' + separatorAfter;
+            case 'number':
+            case 'boolean':
+                return '${1:' + JSON.stringify(value) + '}' + separatorAfter;
+        }
+        return this.getInsertTextForValue(value, separatorAfter);
+    };
+    JSONCompletion.prototype.getSuggestionKind = function (type) {
+        if (Array.isArray(type)) {
+            var array = type;
+            type = array.length > 0 ? array[0] : undefined;
+        }
+        if (!type) {
+            return CompletionItemKind.Value;
+        }
+        switch (type) {
+            case 'string': return CompletionItemKind.Value;
+            case 'object': return CompletionItemKind.Module;
+            case 'property': return CompletionItemKind.Property;
+            default: return CompletionItemKind.Value;
+        }
+    };
+    JSONCompletion.prototype.getLabelTextForMatchingNode = function (node, document) {
+        switch (node.type) {
+            case 'array':
+                return '[]';
+            case 'object':
+                return '{}';
+            default:
+                var content = document.getText().substr(node.offset, node.length);
+                return content;
+        }
+    };
+    JSONCompletion.prototype.getInsertTextForMatchingNode = function (node, document, separatorAfter) {
+        switch (node.type) {
+            case 'array':
+                return this.getInsertTextForValue([], separatorAfter);
+            case 'object':
+                return this.getInsertTextForValue({}, separatorAfter);
+            default:
+                var content = document.getText().substr(node.offset, node.length) + separatorAfter;
+                return this.getInsertTextForPlainText(content);
+        }
+    };
+    JSONCompletion.prototype.getInsertTextForProperty = function (key, propertySchema, addValue, separatorAfter) {
+        var propertyText = this.getInsertTextForValue(key, '');
+        if (!addValue) {
+            return propertyText;
+        }
+        var resultText = propertyText + ': ';
+        var value;
+        var nValueProposals = 0;
+        if (propertySchema) {
+            if (Array.isArray(propertySchema.defaultSnippets)) {
+                if (propertySchema.defaultSnippets.length === 1) {
+                    var body = propertySchema.defaultSnippets[0].body;
+                    if (isDefined(body)) {
+                        value = this.getInsertTextForSnippetValue(body, '');
+                    }
+                }
+                nValueProposals += propertySchema.defaultSnippets.length;
+            }
+            if (propertySchema.enum) {
+                if (!value && propertySchema.enum.length === 1) {
+                    value = this.getInsertTextForGuessedValue(propertySchema.enum[0], '');
+                }
+                nValueProposals += propertySchema.enum.length;
+            }
+            if (isDefined(propertySchema.default)) {
+                if (!value) {
+                    value = this.getInsertTextForGuessedValue(propertySchema.default, '');
+                }
+                nValueProposals++;
+            }
+            if (Array.isArray(propertySchema.examples) && propertySchema.examples.length) {
+                if (!value) {
+                    value = this.getInsertTextForGuessedValue(propertySchema.examples[0], '');
+                }
+                nValueProposals += propertySchema.examples.length;
+            }
+            if (nValueProposals === 0) {
+                var type = Array.isArray(propertySchema.type) ? propertySchema.type[0] : propertySchema.type;
+                if (!type) {
+                    if (propertySchema.properties) {
+                        type = 'object';
+                    }
+                    else if (propertySchema.items) {
+                        type = 'array';
+                    }
+                }
+                switch (type) {
+                    case 'boolean':
+                        value = '$1';
+                        break;
+                    case 'string':
+                        value = '"$1"';
+                        break;
+                    case 'object':
+                        value = '{$1}';
+                        break;
+                    case 'array':
+                        value = '[$1]';
+                        break;
+                    case 'number':
+                    case 'integer':
+                        value = '${1:0}';
+                        break;
+                    case 'null':
+                        value = '${1:null}';
+                        break;
+                    default:
+                        return propertyText;
+                }
+            }
+        }
+        if (!value || nValueProposals > 1) {
+            value = '$1';
+        }
+        return resultText + value + separatorAfter;
+    };
+    JSONCompletion.prototype.getCurrentWord = function (document, offset) {
+        var i = offset - 1;
+        var text = document.getText();
+        while (i >= 0 && ' \t\n\r\v":{[,]}'.indexOf(text.charAt(i)) === -1) {
+            i--;
+        }
+        return text.substring(i + 1, offset);
+    };
+    JSONCompletion.prototype.evaluateSeparatorAfter = function (document, offset) {
+        var scanner = Json.createScanner(document.getText(), true);
+        scanner.setPosition(offset);
+        var token = scanner.scan();
+        switch (token) {
+            case 5 /* CommaToken */:
+            case 2 /* CloseBraceToken */:
+            case 4 /* CloseBracketToken */:
+            case 17 /* EOF */:
+                return '';
+            default:
+                return ',';
+        }
+    };
+    JSONCompletion.prototype.findItemAtOffset = function (node, document, offset) {
+        var scanner = Json.createScanner(document.getText(), true);
+        var children = node.items;
+        for (var i = children.length - 1; i >= 0; i--) {
+            var child = children[i];
+            if (offset > child.offset + child.length) {
+                scanner.setPosition(child.offset + child.length);
+                var token = scanner.scan();
+                if (token === 5 /* CommaToken */ && offset >= scanner.getTokenOffset() + scanner.getTokenLength()) {
+                    return i + 1;
+                }
+                return i;
+            }
+            else if (offset >= child.offset) {
+                return i;
+            }
+        }
+        return 0;
+    };
+    JSONCompletion.prototype.isInComment = function (document, start, offset) {
+        var scanner = Json.createScanner(document.getText(), false);
+        scanner.setPosition(start);
+        var token = scanner.scan();
+        while (token !== 17 /* EOF */ && (scanner.getTokenOffset() + scanner.getTokenLength() < offset)) {
+            token = scanner.scan();
+        }
+        return (token === 12 /* LineCommentTrivia */ || token === 13 /* BlockCommentTrivia */) && scanner.getTokenOffset() <= offset;
+    };
+    JSONCompletion.prototype.fromMarkup = function (markupString) {
+        if (markupString && this.doesSupportMarkdown()) {
+            return {
+                kind: MarkupKind.Markdown,
+                value: markupString
+            };
+        }
+        return undefined;
+    };
+    JSONCompletion.prototype.doesSupportMarkdown = function () {
+        if (!isDefined(this.supportsMarkdown)) {
+            var completion = this.clientCapabilities.textDocument && this.clientCapabilities.textDocument.completion;
+            this.supportsMarkdown = completion && completion.completionItem && Array.isArray(completion.completionItem.documentationFormat) && completion.completionItem.documentationFormat.indexOf(MarkupKind.Markdown) !== -1;
+        }
+        return this.supportsMarkdown;
+    };
+    JSONCompletion.prototype.doesSupportsCommitCharacters = function () {
+        if (!isDefined(this.supportsCommitCharacters)) {
+            var completion = this.clientCapabilities.textDocument && this.clientCapabilities.textDocument.completion;
+            this.supportsCommitCharacters = completion && completion.completionItem && !!completion.completionItem.commitCharactersSupport;
+        }
+        return this.supportsCommitCharacters;
+    };
+    return JSONCompletion;
+}());
+export { JSONCompletion };