public findDocumentSymbols()

in src/services/jsonDocumentSymbols.ts [22:100]


	public findDocumentSymbols(document: TextDocument, doc: Parser.JSONDocument, context: DocumentSymbolsContext = { resultLimit: Number.MAX_VALUE }): SymbolInformation[] {

		const root = doc.root;
		if (!root) {
			return [];
		}

		let limit = context.resultLimit || Number.MAX_VALUE;

		// special handling for key bindings
		const resourceString = document.uri;
		if ((resourceString === 'vscode://defaultsettings/keybindings.json') || Strings.endsWith(resourceString.toLowerCase(), '/user/keybindings.json')) {
			if (root.type === 'array') {
				const result: SymbolInformation[] = [];
				for (const item of root.items) {
					if (item.type === 'object') {
						for (const property of item.properties) {
							if (property.keyNode.value === 'key' && property.valueNode) {
								const location = Location.create(document.uri, getRange(document, item));
								result.push({ name: Parser.getNodeValue(property.valueNode), kind: SymbolKind.Function, location: location });
								limit--;
								if (limit <= 0) {
									if (context && context.onResultLimitExceeded) {
										context.onResultLimitExceeded(resourceString);
									}
									return result;
								}
							}
						}
					}
				}
				return result;
			}
		}

		const toVisit: { node: ASTNode, containerName: string }[] = [
			{ node: root, containerName: '' }
		];
		let nextToVisit = 0;
		let limitExceeded = false;

		const result: SymbolInformation[] = [];

		const collectOutlineEntries = (node: ASTNode, containerName: string): void => {
			if (node.type === 'array') {
				node.items.forEach(node => {
					if (node) {
						toVisit.push({ node, containerName });
					}
				});
			} else if (node.type === 'object') {
				node.properties.forEach((property: PropertyASTNode) => {
					const valueNode = property.valueNode;
					if (valueNode) {
						if (limit > 0) {
							limit--;
							const location = Location.create(document.uri, getRange(document, property));
							const childContainerName = containerName ? containerName + '.' + property.keyNode.value : property.keyNode.value;
							result.push({ name: this.getKeyLabel(property), kind: this.getSymbolKind(valueNode.type), location: location, containerName: containerName });
							toVisit.push({ node: valueNode, containerName: childContainerName });
						} else {
							limitExceeded = true;
						}
					}
				});
			}
		};

		// breath first traversal
		while (nextToVisit < toVisit.length) {
			const next = toVisit[nextToVisit++];
			collectOutlineEntries(next.node, next.containerName);
		}

		if (limitExceeded && context && context.onResultLimitExceeded) {
			context.onResultLimitExceeded(resourceString);
		}
		return result;
	}