Skip to content
This repository was archived by the owner on Sep 2, 2020. It is now read-only.

Commit afa4561

Browse files
committed
{interface,server,types}: support getOutline in lsp server
1 parent df06306 commit afa4561

File tree

5 files changed

+69
-0
lines changed

5 files changed

+69
-0
lines changed

packages/interface/src/GraphQLLanguageService.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import type {
2121
GraphQLCache,
2222
GraphQLConfig,
2323
GraphQLProjectConfig,
24+
Outline,
2425
Uri,
2526
} from 'graphql-language-service-types';
2627
import type {Position} from 'graphql-language-service-utils';
@@ -46,6 +47,7 @@ import {
4647
getDefinitionQueryResultForFragmentSpread,
4748
getDefinitionQueryResultForDefinitionNode,
4849
} from './getDefinition';
50+
import {getOutline} from './getOutline';
4951
import {getASTNodeAtPosition} from 'graphql-language-service-utils';
5052

5153
export class GraphQLLanguageService {
@@ -244,4 +246,8 @@ export class GraphQLLanguageService {
244246

245247
return result;
246248
}
249+
250+
async getOutline(query: string): Promise<?Outline> {
251+
return getOutline(query);
252+
}
247253
}

packages/interface/src/getOutline.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ function outlineTreeConverter(docText: string): OutlineTreeConverterType {
5656
representativeName: node.name,
5757
startPosition: offsetToPosition(docText, node.loc.start),
5858
endPosition: offsetToPosition(docText, node.loc.end),
59+
kind: node.kind,
5960
children: node.selectionSet || [],
6061
});
6162
return {

packages/server/src/MessageProcessor.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ import {
3535
InitializeResult,
3636
Location,
3737
PublishDiagnosticsParams,
38+
DocumentSymbolParams,
39+
SymbolInformation,
40+
SymbolKind,
3841
} from 'vscode-languageserver';
3942

4043
import {getGraphQLCache} from './GraphQLCache';
@@ -48,6 +51,13 @@ type CachedDocumentType = {
4851
contents: Array<CachedContent>,
4952
};
5053

54+
const KIND_TO_SYMBOL_KIND = {
55+
Field: SymbolKind.Field,
56+
OperationDefinition: SymbolKind.Class,
57+
FragmentDefinition: SymbolKind.Class,
58+
FragmentSpread: SymbolKind.Struct,
59+
};
60+
5161
export class MessageProcessor {
5262
_graphQLCache: GraphQLCache;
5363
_languageService: GraphQLLanguageService;
@@ -79,6 +89,7 @@ export class MessageProcessor {
7989
const serverCapabilities: ServerCapabilities = {
8090
capabilities: {
8191
completionProvider: {resolveProvider: true},
92+
documentSymbolProvider: true,
8293
definitionProvider: true,
8394
textDocumentSync: 1,
8495
},
@@ -416,6 +427,52 @@ export class MessageProcessor {
416427
return formatted;
417428
}
418429

430+
async handleDocumentSymbolRequest(
431+
params: DocumentSymbolParams.type,
432+
): Promise<Array<SymbolInformation>> {
433+
if (!this._isInitialized) {
434+
return [];
435+
}
436+
437+
if (!params || !params.textDocument) {
438+
throw new Error('`textDocument` argument is required.');
439+
}
440+
441+
const textDocument = params.textDocument;
442+
const cachedDocument = this._getCachedDocument(textDocument.uri);
443+
if (!cachedDocument) {
444+
throw new Error('A cached document cannot be found.');
445+
}
446+
447+
const outline = await this._languageService.getOutline(
448+
cachedDocument.contents[0].query,
449+
);
450+
if (!outline) {
451+
return [];
452+
}
453+
454+
const output: Array<SymbolInformation> = [];
455+
const input = outline.outlineTrees.map(tree => [null, tree]);
456+
while (input.length > 0) {
457+
const [parent, tree] = input.pop();
458+
output.push({
459+
name: tree.representativeName,
460+
kind: KIND_TO_SYMBOL_KIND[tree.kind],
461+
location: {
462+
uri: textDocument.uri,
463+
range: {
464+
start: tree.startPosition,
465+
end: tree.endPosition,
466+
},
467+
},
468+
containerName: parent ? parent.representativeName : undefined,
469+
});
470+
input.push(...tree.children.map(child => [tree, child]));
471+
}
472+
473+
return output;
474+
}
475+
419476
_isRelayCompatMode(query: string): boolean {
420477
return (
421478
query.indexOf('RelayCompat') !== -1 ||

packages/server/src/startServer.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
ExitNotification,
3535
InitializeRequest,
3636
PublishDiagnosticsNotification,
37+
DocumentSymbolRequest,
3738
ShutdownRequest,
3839
} from 'vscode-languageserver';
3940

@@ -168,4 +169,7 @@ function addHandlers(
168169
connection.onRequest(DefinitionRequest.type, params =>
169170
messageProcessor.handleDefinitionRequest(params),
170171
);
172+
connection.onRequest(DocumentSymbolRequest.type, (params, token) =>
173+
messageProcessor.handleDocumentSymbolRequest(params),
174+
);
171175
}

packages/types/src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ export type OutlineTree = {
259259
tokenizedText?: TokenizedText,
260260
representativeName?: string,
261261

262+
kind: string,
262263
startPosition: Position,
263264
endPosition?: Position,
264265
children: Array<OutlineTree>,

0 commit comments

Comments
 (0)