···
+
function resolveIdentifierToGraphQLCall(
info: ts.server.PluginCreateInfo,
+
checker: ts.TypeChecker | undefined
+
): checks.GraphQLCallNode | null {
+
let prevElement: ts.Node | undefined;
+
let element: ts.Node | undefined = input;
+
// NOTE: Under certain circumstances, resolving an identifier can loop
+
while (ts.isIdentifier(element) && element !== prevElement) {
+
const definitions = info.languageService.getDefinitionAtPosition(
+
element.getSourceFile().fileName,
+
const fragment = definitions && definitions[0];
+
const externalSource = fragment && getSource(info, fragment.fileName);
+
if (!fragment || !externalSource) return null;
+
element = findNode(externalSource, fragment.textSpan.start);
+
if (!element) return null;
+
while (ts.isPropertyAccessExpression(element.parent))
+
element = element.parent;
+
ts.isVariableDeclaration(element.parent) &&
+
element.parent.initializer &&
+
ts.isCallExpression(element.parent.initializer)
+
element = element.parent.initializer;
+
} else if (ts.isPropertyAssignment(element.parent)) {
+
element = element.parent.initializer;
+
} else if (ts.isBinaryExpression(element.parent)) {
+
element = ts.isPropertyAccessExpression(element.parent.right)
+
? element.parent.right.name
+
: element.parent.right;
+
// If we find another Identifier, we continue resolving it
// Check whether we've got a `graphql()` or `gql()` call, by the
// call expression's identifier
+
return checks.isGraphQLCall(element, checker) ? element : null;
+
function unrollFragment(
+
element: ts.Identifier,
+
info: ts.server.PluginCreateInfo,
+
checker: ts.TypeChecker | undefined
+
): Array<FragmentDefinitionNode> {
+
const fragments: FragmentDefinitionNode[] = [];
+
const elements: ts.Identifier[] = [element];
+
const seen = new WeakSet<ts.Identifier>();
+
const _unrollElement = (element: ts.Identifier): void => {
+
if (seen.has(element)) return;
+
const node = resolveIdentifierToGraphQLCall(element, info, checker);
+
const fragmentRefs = resolveTadaFragmentArray(node.arguments[1]);
+
if (fragmentRefs) elements.push(...fragmentRefs);
+
const text = node.arguments[0];
+
const parsed = parse(text.getText().slice(1, -1), { noLocation: true });
+
parsed.definitions.forEach(definition => {
+
if (definition.kind === 'FragmentDefinition') {
+
fragments.push(definition);
+
// NOTE: Assume graphql.parse errors can be ignored
+
let nextElement: ts.Identifier | undefined;
+
while ((nextElement = elements.shift()) !== undefined)
+
_unrollElement(nextElement);