Skip to content

feat: implement documentSymbol support for JSON objects and arrays - #64

Open
Suyog241005 wants to merge 4 commits into
hyperjump-io:mainfrom
Suyog241005:feat/document-symbols
Open

feat: implement documentSymbol support for JSON objects and arrays#64
Suyog241005 wants to merge 4 commits into
hyperjump-io:mainfrom
Suyog241005:feat/document-symbols

Conversation

@Suyog241005

Copy link
Copy Markdown
Contributor

Implements LSP Document Symbol support to provide a hierarchical document outline for JSON files in VS Code's Outline panel and top breadcrumb navigation.

Fixes #49

Changes

  • DocumentSymbols.ts: Recursively builds symbol trees for JSON objects, arrays, properties, and primitive values, mapping SymbolKind by value type.
  • DocumentSymbols.test.ts: Tests covering flat objects, nested objects, arrays, and empty

@Suyog241005
Suyog241005 force-pushed the feat/document-symbols branch 2 times, most recently from 79fca58 to 1acd7ab Compare August 2, 2026 17:12

@jdesrosiers jdesrosiers left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not 100% sure how this feature is supposed to work, but this is not what I expected for object properties. I expect that each property in an object would have two entries. The first would be the key and a SymbolKind.Property. The second would be the value and have a SymbolKind reflecting the type of the value.

Comment on lines +26 to +29
const jsonDocument = this.jsonDocuments.get(params.textDocument.uri);
if (!jsonDocument) {
return [];
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can assume that if the client send us this request, it's for a document that exists.

Comment on lines +35 to +42
private getDocumentSymbols(jsonDocument: JsonDocument): DocumentSymbol[] {
const ast = jsonDocument.findNodeAtPointer("");
if (!ast) {
return [];
}

return this.collectDocumentSymbols(jsonDocument, ast);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's inline this. There's no reason for this to be a function.

Comment thread language-server/src/features/DocumentSymbols.ts
private collectDocumentSymbols(jsonDocument: JsonDocument, node: Node): DocumentSymbol[] {
const symbols: DocumentSymbol[] = [];

if (node.type === "object" && node.children) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Objects always have children.


if (node.type === "object" && node.children) {
for (const child of node.children) {
if (child.type === "property" && child.children) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The children of object nodes are always property nodes and property nodes always have children.

Comment on lines +53 to +55
if (!keyNode) {
continue;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There will always be a key node.

symbols.push(symbol);
}
}
} else if (node.type === "array" && node.children) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Array nodes will always have children.

Comment on lines +128 to +129
default:
return SymbolKind.Property;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This technically works because the only other possible result you could get is "property", but it's not very intentional.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will add explicit case "property": return SymbolKind.Property; to make all switch branches intentional

@Suyog241005
Suyog241005 force-pushed the feat/document-symbols branch from 1acd7ab to d4ce8e8 Compare August 4, 2026 13:41
@Suyog241005

Suyog241005 commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

Hi @jdesrosiers! Updated the PR to address all comments.

Regarding object properties: I double-checked standard LSP and VS Code JSON Language Service (vscode-json-languageservice) behavior for Document Symbols. In VS Code, each JSON property ("key": value) is represented as one DocumentSymbol where:

  • name: "key" (the property name)
  • kind: SymbolKind matching the value type (Object, Array, String, Number, Boolean, Null).
  • selectionRange: range of "key" (so clicking the symbol in the Outline panel jumps directly to the key).
  • range: full span of "key": value.
  • children: nested symbols if value is an Object or Array.

On walkNodes: since LSP DocumentSymbol requires a hierarchical tree, recursive collection lets us construct those nested child arrays directly as we traverse. Let me know what you think about this, or if you have any suggestions

@Suyog241005
Suyog241005 requested a review from jdesrosiers August 4, 2026 13:46

@jdesrosiers jdesrosiers left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You still haven't addressed,

I'm not 100% sure how this feature is supposed to work, but this is not what I expected for object properties. I expect that each property in an object would have two entries. The first would be the key and a SymbolKind.Property. The second would be the value and have a SymbolKind reflecting the type of the value.

Comment thread language-server/src/features/DocumentSymbols.ts
@Suyog241005
Suyog241005 force-pushed the feat/document-symbols branch from d066393 to baa0afb Compare August 5, 2026 12:09
@Suyog241005

Copy link
Copy Markdown
Contributor Author

Hi @jdesrosiers! Updated DocumentSymbols to produce two entries per property (Key symbol + Value symbol) as per your preference.

@Suyog241005
Suyog241005 requested a review from jdesrosiers August 5, 2026 12:13
@jdesrosiers

Copy link
Copy Markdown
Collaborator

Updated DocumentSymbols to produce two entries per property (Key symbol + Value symbol) as per your preference.

Preference has nothing to do with it. Like I said, I'm not confident that I know how it's supposed to work. I expect you to do the research and tell me what you learned. I need to know that you actually thought about this and you're not just doing what you think I want.

@Suyog241005

Copy link
Copy Markdown
Contributor Author

Hi @jdesrosiers! Apologies for the confusion, when I said "as per your preference", I shouldn't have temporarily switched the code to 2 entries just because you brought it up!

My original research stands: 1 entry per property (name = key, kind = valueType) is indeed the official standard in vscode-json-languageservice and yaml-language-server.

My primary approach from the start (which I mentioned in my previous comment below) remains based on this standard:

Regarding object properties: I double-checked standard LSP and VS Code JSON Language Service (vscode-json-languageservice) behavior for Document Symbols. In VS Code, each JSON property ("key": value) is represented as one DocumentSymbol where:

  • name: "key" (the property name)
  • kind: SymbolKind matching the value type (Object, Array, String, Number, Boolean, Null)
  • selectionRange: range of "key" (so clicking the symbol in the Outline panel jumps directly to the key)
  • range: full span of "key": value
  • children: nested symbols if value is an Object or Array

This provides the cleanest UX by giving clear breadcrumbs (a.json > server > port) with matching type icons without cluttering the outline with extra primitive value nodes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

implement documentSymbol support

2 participants