Mirror: TypeScript LSP plugin that finds GraphQL documents in your code and provides diagnostics, auto-complete and hover-information.

bring implementations closer together

Changed files
+64 -116
packages
+44 -79
packages/graphqlsp/src/autoComplete.ts
···
? bubbleUpCallExpression(node)
: bubbleUpTemplate(node);
if (
ts.isCallExpression(node) &&
isCallExpression &&
···
const queryText = node.arguments[0].getText();
const fragments = getAllFragments(filename, node, info);
-
const cursor = new Cursor(foundToken.line, foundToken.start - 1);
-
const text = `${queryText}\m${fragments.map(x => print(x)).join('\n')}`;
-
const [suggestions, spreadSuggestions] = getSuggestionsInternal(
-
schema.current,
-
text,
-
cursor
-
);
-
-
return {
-
isGlobalCompletion: false,
-
isMemberCompletion: false,
-
isNewIdentifierLocation: false,
-
entries: [
-
...suggestions.map(suggestion => ({
-
...suggestion,
-
kind: ts.ScriptElementKind.variableElement,
-
name: suggestion.label,
-
kindModifiers: 'declare',
-
sortText: suggestion.sortText || '0',
-
labelDetails: {
-
detail: suggestion.type
-
? ' ' + suggestion.type?.toString()
-
: undefined,
-
description: suggestion.documentation,
-
},
-
})),
-
...spreadSuggestions.map(suggestion => ({
-
...suggestion,
-
kind: ts.ScriptElementKind.variableElement,
-
name: suggestion.label,
-
insertText: '...' + suggestion.label,
-
kindModifiers: 'declare',
-
sortText: '0',
-
labelDetails: {
-
description: suggestion.documentation,
-
},
-
})),
-
],
-
};
} else if (ts.isTaggedTemplateExpression(node)) {
const { template, tag } = node;
···
const foundToken = getToken(template, cursorPosition);
if (!foundToken || !schema.current) return undefined;
-
const { combinedText: text, resolvedSpans } = resolveTemplate(
node,
filename,
info
···
foundToken.line = foundToken.line + amountOfLines;
-
const cursor = new Cursor(foundToken.line, foundToken.start - 1);
-
-
const [suggestions, spreadSuggestions] = getSuggestionsInternal(
-
schema.current,
-
text,
-
cursor
-
);
-
-
return {
-
isGlobalCompletion: false,
-
isMemberCompletion: false,
-
isNewIdentifierLocation: false,
-
entries: [
-
...suggestions.map(suggestion => ({
-
...suggestion,
-
kind: ts.ScriptElementKind.variableElement,
-
name: suggestion.label,
-
kindModifiers: 'declare',
-
sortText: suggestion.sortText || '0',
-
labelDetails: {
-
detail: suggestion.type
-
? ' ' + suggestion.type?.toString()
-
: undefined,
-
description: suggestion.documentation,
-
},
-
})),
-
...spreadSuggestions.map(suggestion => ({
-
...suggestion,
-
kind: ts.ScriptElementKind.variableElement,
-
name: suggestion.label,
-
insertText: '...' + suggestion.label,
-
kindModifiers: 'declare',
-
sortText: '0',
-
labelDetails: {
-
description: suggestion.documentation,
-
},
-
})),
-
],
-
};
} else {
return undefined;
}
}
export function getSuggestionsInternal(
···
? bubbleUpCallExpression(node)
: bubbleUpTemplate(node);
+
let text, cursor;
if (
ts.isCallExpression(node) &&
isCallExpression &&
···
const queryText = node.arguments[0].getText();
const fragments = getAllFragments(filename, node, info);
+
text = `${queryText}\m${fragments.map(x => print(x)).join('\n')}`;
+
cursor = new Cursor(foundToken.line, foundToken.start - 1);
} else if (ts.isTaggedTemplateExpression(node)) {
const { template, tag } = node;
···
const foundToken = getToken(template, cursorPosition);
if (!foundToken || !schema.current) return undefined;
+
const { combinedText, resolvedSpans } = resolveTemplate(
node,
filename,
info
···
foundToken.line = foundToken.line + amountOfLines;
+
text = combinedText;
+
cursor = new Cursor(foundToken.line, foundToken.start - 1);
} else {
return undefined;
}
+
+
const [suggestions, spreadSuggestions] = getSuggestionsInternal(
+
schema.current,
+
text,
+
cursor
+
);
+
+
return {
+
isGlobalCompletion: false,
+
isMemberCompletion: false,
+
isNewIdentifierLocation: false,
+
entries: [
+
...suggestions.map(suggestion => ({
+
...suggestion,
+
kind: ts.ScriptElementKind.variableElement,
+
name: suggestion.label,
+
kindModifiers: 'declare',
+
sortText: suggestion.sortText || '0',
+
labelDetails: {
+
detail: suggestion.type
+
? ' ' + suggestion.type?.toString()
+
: undefined,
+
description: suggestion.documentation,
+
},
+
})),
+
...spreadSuggestions.map(suggestion => ({
+
...suggestion,
+
kind: ts.ScriptElementKind.variableElement,
+
name: suggestion.label,
+
insertText: '...' + suggestion.label,
+
kindModifiers: 'declare',
+
sortText: '0',
+
labelDetails: {
+
description: suggestion.documentation,
+
},
+
})),
+
],
+
};
}
export function getSuggestionsInternal(
+20 -37
packages/graphqlsp/src/quickInfo.ts
···
import { resolveTemplate } from './ast/resolve';
import { getToken } from './ast/token';
import { Cursor } from './ast/cursor';
-
import { Logger } from '.';
export function getGraphQLQuickInfo(
filename: string,
···
schema: { current: GraphQLSchema | null },
info: ts.server.PluginCreateInfo
): ts.QuickInfo | undefined {
-
const logger: Logger = (msg: string) =>
-
info.project.projectService.logger.info(`[GraphQLSP] ${msg}`);
const tagTemplate = info.config.template || 'gql';
const isCallExpression = info.config.templateIsCallExpression ?? false;
···
? bubbleUpCallExpression(node)
: bubbleUpTemplate(node);
if (
ts.isCallExpression(node) &&
isCallExpression &&
···
const foundToken = getToken(node.arguments[0], cursorPosition);
if (!schema.current || !foundToken) return undefined;
-
const queryText = node.arguments[0].getText();
-
const cursor = new Cursor(foundToken.line, foundToken.start - 1);
-
const hoverInfo = getHoverInformation(schema.current, queryText, cursor);
-
-
return {
-
kind: ts.ScriptElementKind.string,
-
textSpan: {
-
start: cursorPosition,
-
length: 1,
-
},
-
kindModifiers: 'text',
-
documentation: Array.isArray(hoverInfo)
-
? hoverInfo.map(item => ({ kind: 'text', text: item as string }))
-
: [{ kind: 'text', text: hoverInfo as string }],
-
};
} else if (ts.isTaggedTemplateExpression(node)) {
const { template, tag } = node;
if (!ts.isIdentifier(tag) || tag.text !== tagTemplate) return undefined;
···
if (!foundToken || !schema.current) return undefined;
-
const { combinedText: text, resolvedSpans } = resolveTemplate(
node,
filename,
info
···
.reduce((acc, span) => acc + (span.lines - 1), 0);
foundToken.line = foundToken.line + amountOfLines;
-
-
const hoverInfo = getHoverInformation(
-
schema.current,
-
text,
-
new Cursor(foundToken.line, foundToken.start - 1)
-
);
-
-
return {
-
kind: ts.ScriptElementKind.label,
-
textSpan: {
-
start: cursorPosition,
-
length: 1,
-
},
-
kindModifiers: 'text',
-
documentation: Array.isArray(hoverInfo)
-
? hoverInfo.map(item => ({ kind: 'text', text: item as string }))
-
: [{ kind: 'text', text: hoverInfo as string }],
-
} as ts.QuickInfo;
} else {
return undefined;
}
}
···
import { resolveTemplate } from './ast/resolve';
import { getToken } from './ast/token';
import { Cursor } from './ast/cursor';
export function getGraphQLQuickInfo(
filename: string,
···
schema: { current: GraphQLSchema | null },
info: ts.server.PluginCreateInfo
): ts.QuickInfo | undefined {
const tagTemplate = info.config.template || 'gql';
const isCallExpression = info.config.templateIsCallExpression ?? false;
···
? bubbleUpCallExpression(node)
: bubbleUpTemplate(node);
+
let cursor, text;
if (
ts.isCallExpression(node) &&
isCallExpression &&
···
const foundToken = getToken(node.arguments[0], cursorPosition);
if (!schema.current || !foundToken) return undefined;
+
text = node.arguments[0].getText();
+
cursor = new Cursor(foundToken.line, foundToken.start - 1);
} else if (ts.isTaggedTemplateExpression(node)) {
const { template, tag } = node;
if (!ts.isIdentifier(tag) || tag.text !== tagTemplate) return undefined;
···
if (!foundToken || !schema.current) return undefined;
+
const { combinedText, resolvedSpans } = resolveTemplate(
node,
filename,
info
···
.reduce((acc, span) => acc + (span.lines - 1), 0);
foundToken.line = foundToken.line + amountOfLines;
+
text = combinedText;
+
cursor = new Cursor(foundToken.line, foundToken.start - 1);
} else {
return undefined;
}
+
+
const hoverInfo = getHoverInformation(schema.current, text, cursor);
+
+
return {
+
kind: ts.ScriptElementKind.label,
+
textSpan: {
+
start: cursorPosition,
+
length: 1,
+
},
+
kindModifiers: 'text',
+
documentation: Array.isArray(hoverInfo)
+
? hoverInfo.map(item => ({ kind: 'text', text: item as string }))
+
: [{ kind: 'text', text: hoverInfo as string }],
+
} as ts.QuickInfo;
}