Skip to content

Commit

Permalink
fix(persisted): nested persisted operation resolution (#330)
Browse files Browse the repository at this point in the history
  • Loading branch information
JoviDeCroock committed Jun 7, 2024
1 parent adfa3ce commit 7768286
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 30 deletions.
5 changes: 5 additions & 0 deletions .changeset/fifty-mangos-doubt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@0no-co/graphqlsp': patch
---

Fix nested fragment resolution during persisted traversal
5 changes: 4 additions & 1 deletion packages/graphqlsp/src/diagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,10 @@ export function getGraphQLDiagnostics(
const generatedHash = generateHashForDocument(
info,
initializer.arguments[0],
foundFilename
foundFilename,
ts.isArrayLiteralExpression(initializer.arguments[1])
? initializer.arguments[1]
: undefined
);
if (!generatedHash) return null;

Expand Down
101 changes: 72 additions & 29 deletions packages/graphqlsp/src/persisted.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,19 @@ import { ts } from './ts';
import { createHash } from 'crypto';

import * as checks from './ast/checks';
import { findAllCallExpressions, findNode, getSource } from './ast';
import {
findAllCallExpressions,
findNode,
getSource,
unrollTadaFragments,
} from './ast';
import { resolveTemplate } from './ast/resolve';
import { parse, print, visit } from '@0no-co/graphql.web';
import {
FragmentDefinitionNode,
parse,
print,
visit,
} from '@0no-co/graphql.web';

type PersistedAction = {
span: {
Expand Down Expand Up @@ -113,7 +123,10 @@ export function getPersistedCodeFixAtPosition(
const hash = generateHashForDocument(
info,
initializer.arguments[0],
foundFilename
foundFilename,
ts.isArrayLiteralExpression(initializer.arguments[1])
? initializer.arguments[1]
: undefined
);
const existingHash = callExpression.arguments[0];
// We assume for now that this is either undefined or an existing string literal
Expand Down Expand Up @@ -156,38 +169,68 @@ export function getPersistedCodeFixAtPosition(
export const generateHashForDocument = (
info: ts.server.PluginCreateInfo,
templateLiteral: ts.StringLiteralLike | ts.TaggedTemplateExpression,
foundFilename: string
foundFilename: string,
referencedFragments: ts.ArrayLiteralExpression | undefined
): string | undefined => {
const externalSource = getSource(info, foundFilename)!;
const { fragments } = findAllCallExpressions(externalSource, info);
if (referencedFragments) {
const fragments: Array<FragmentDefinitionNode> = [];
unrollTadaFragments(referencedFragments, fragments, info);
let text = resolveTemplate(
templateLiteral,
foundFilename,
info
).combinedText;
fragments.forEach(fragmentDefinition => {
text = `${text}\n\n${print(fragmentDefinition)}`;
});
return createHash('sha256').update(print(parse(text))).digest('hex');
} else {
const externalSource = getSource(info, foundFilename)!;
const { fragments } = findAllCallExpressions(externalSource, info);

const text = resolveTemplate(
templateLiteral,
foundFilename,
info
).combinedText;
const parsed = parse(text);
const spreads = new Set();
visit(parsed, {
FragmentSpread: node => {
spreads.add(node.name.value);
},
});
const text = resolveTemplate(
templateLiteral,
foundFilename,
info
).combinedText;

const parsed = parse(text);
const spreads = new Set<string>();
visit(parsed, {
FragmentSpread: node => {
spreads.add(node.name.value);
},
});

let resolvedText = text;
[...spreads].forEach(spreadName => {
const fragmentDefinition = fragments.find(x => x.name.value === spreadName);
if (!fragmentDefinition) {
info.project.projectService.logger.info(
`[GraphQLSP] could not find fragment for spread ${spreadName}!`
let resolvedText = text;
const visited = new Set();
const traversedSpreads = [...spreads];

let spreadName: string | undefined;
while ((spreadName = traversedSpreads.shift())) {
visited.add(spreadName);
const fragmentDefinition = fragments.find(
x => x.name.value === spreadName
);
return;
}
if (!fragmentDefinition) {
info.project.projectService.logger.info(
`[GraphQLSP] could not find fragment for spread ${spreadName}!`
);
return;
}

resolvedText = `${resolvedText}\n\n${print(fragmentDefinition)}`;
});
visit(fragmentDefinition, {
FragmentSpread: node => {
if (!visited.has(node.name.value))
traversedSpreads.push(node.name.value);
},
});

resolvedText = `${resolvedText}\n\n${print(fragmentDefinition)}`;
}

return createHash('sha256').update(resolvedText).digest('hex');
return createHash('sha256').update(print(parse(resolvedText))).digest('hex');
}
};

export const getDocumentReferenceFromTypeQuery = (
Expand Down

0 comments on commit 7768286

Please sign in to comment.