extensions/npm/src/features/jsonContributions.ts/JSONCompletionItemProvider/provideCompletionItems
class JSONCompletionItemProvider:	public provideCompletionItems(document: TextDocument, position: Position, _token: CancellationToken): Thenable<CompletionList | null> | null {
		this.lastResource = document.uri;


		const currentWord = this.getCurrentWord(document, position);
		let overwriteRange: Range;

		const items: CompletionItem[] = [];
		let isIncomplete = false;

		const offset = document.offsetAt(position);
		const location = getLocation(document.getText(), offset);

		const node = location.previousNode;
		if (node && node.offset <= offset && offset <= node.offset + node.length && (node.type === 'property' || node.type === 'string' || node.type === 'number' || node.type === 'boolean' || node.type === 'null')) {
			overwriteRange = new Range(document.positionAt(node.offset), document.positionAt(node.offset + node.length));
		} else {
			overwriteRange = new Range(document.positionAt(offset - currentWord.length), position);
		}

		const proposed: { [key: string]: boolean } = {};
		const collector: ISuggestionsCollector = {
			add: (suggestion: CompletionItem) => {
				const key = typeof suggestion.label === 'string'
					? suggestion.label
					: suggestion.label.label;
				if (!proposed[key]) {
					proposed[key] = true;
					suggestion.range = { replacing: overwriteRange, inserting: new Range(overwriteRange.start, overwriteRange.start) };
					items.push(suggestion);
				}
			},
			setAsIncomplete: () => isIncomplete = true,
			error: (message: string) => console.error(message),
			log: (message: string) => console.log(message)
		};

		let collectPromise: Thenable<any> | null = null;

		if (location.isAtPropertyKey) {
			const scanner = createScanner(document.getText(), true);
			const addValue = !location.previousNode || !this.hasColonAfter(scanner, location.previousNode.offset + location.previousNode.length);
			const isLast = this.isLast(scanner, document.offsetAt(position));
			collectPromise = this.jsonContribution.collectPropertySuggestions(document.uri, location, currentWord, addValue, isLast, collector);
		} else {
			if (location.path.length === 0) {
				collectPromise = this.jsonContribution.collectDefaultSuggestions(document.uri, collector);
			} else {
				collectPromise = this.jsonContribution.collectValueSuggestions(document.uri, location, collector);
			}
		}
		if (collectPromise) {
			return collectPromise.then(() => {
				if (items.length > 0 || isIncomplete) {
					return new CompletionList(items, isIncomplete);
				}
				return null;
			});
		}
		return null;
	}