public findDocumentSymbols2()

in src/services/jsonDocumentSymbols.ts [102:192]


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

		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: DocumentSymbol[] = [];
				for (const item of root.items) {
					if (item.type === 'object') {
						for (const property of item.properties) {
							if (property.keyNode.value === 'key' && property.valueNode) {
								const range = getRange(document, item);
								const selectionRange = getRange(document, property.keyNode);
								result.push({ name: Parser.getNodeValue(property.valueNode), kind: SymbolKind.Function, range, selectionRange });
								limit--;
								if (limit <= 0) {
									if (context && context.onResultLimitExceeded) {
										context.onResultLimitExceeded(resourceString);
									}
									return result;
								}
							}
						}
					}
				}
				return result;
			}
		}

		const result: DocumentSymbol[] = [];
		const toVisit: { node: ASTNode, result: DocumentSymbol[] }[] = [
			{ node: root, result }
		];
		let nextToVisit = 0;
		let limitExceeded = false;

		const collectOutlineEntries = (node: ASTNode, result: DocumentSymbol[]) => {
			if (node.type === 'array') {
				node.items.forEach((node, index) => {
					if (node) {
						if (limit > 0) {
							limit--;
							const range = getRange(document, node);
							const selectionRange = range;
							const name = String(index);
							const symbol = { name, kind: this.getSymbolKind(node.type), range, selectionRange, children: [] };
							result.push(symbol);
							toVisit.push({ result: symbol.children, node });
						} else {
							limitExceeded = true;
						}
					}
				});
			} else if (node.type === 'object') {
				node.properties.forEach((property: PropertyASTNode) => {
					const valueNode = property.valueNode;
					if (valueNode) {
						if (limit > 0) {
							limit--;
							const range = getRange(document, property);
							const selectionRange = getRange(document, property.keyNode);
							const children: DocumentSymbol[] = [];
							const symbol: DocumentSymbol = { name: this.getKeyLabel(property), kind: this.getSymbolKind(valueNode.type), range, selectionRange, children, detail: this.getDetail(valueNode) };
							result.push(symbol);
							toVisit.push({ result: children, node: valueNode });
						} else {
							limitExceeded = true;
						}
					}
				});
			}
		};

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

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