Skip to content

Commit

Permalink
feat: Add support for the second argument to graphql.persisted (#188)
Browse files Browse the repository at this point in the history
Co-authored-by: Phil Pluckthun <phil@kitten.sh>
  • Loading branch information
JoviDeCroock and kitten committed Apr 15, 2024
1 parent 36adc75 commit c32bd40
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 38 deletions.
6 changes: 6 additions & 0 deletions .changeset/late-mice-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@gql.tada/cli-utils": minor
"gql.tada": minor
---

Support a second argument in `graphql.persisted` which accepts a `TadaDocumentNode` rather than passing a generic. This allows the document node to not be hidden, to still generate `documentId` via `gql.tada` without having to hide the document during runtime.
6 changes: 3 additions & 3 deletions packages/cli-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@
"wonka": "^6.3.4"
},
"dependencies": {
"@0no-co/graphqlsp": "^1.9.1",
"@gql.tada/internal": "workspace:*",
"graphql": "^16.8.1",
"ts-morph": "~22.0.0"
"@0no-co/graphqlsp": "^1.10.0",
"ts-morph": "~22.0.0",
"graphql": "^16.8.1"
},
"peerDependencies": {
"typescript": "^5.0.0"
Expand Down
51 changes: 30 additions & 21 deletions packages/cli-utils/src/commands/generate-persisted/thread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
init,
findAllPersistedCallExpressions,
getDocumentReferenceFromTypeQuery,
getDocumentReferenceFromDocumentNode,
unrollTadaFragments,
} from '@0no-co/graphqlsp/api';

Expand Down Expand Up @@ -50,8 +51,10 @@ async function* _runPersisted(params: PersistedParams): AsyncIterableIterator<Pe
const calls = findAllPersistedCallExpressions(sourceFile);
for (const call of calls) {
const position = getFilePosition(sourceFile, call.getStart());
const hash = call.arguments[0];
if (!hash || !ts.isStringLiteral(hash)) {
const hashArg = call.arguments[0];
const docArg = call.arguments[1];
const typeQuery = call.typeArguments && call.typeArguments[0];
if (!hashArg || !ts.isStringLiteral(hashArg)) {
warnings.push({
message:
'"graphql.persisted" must be called with a string literal as the first argument.',
Expand All @@ -60,27 +63,34 @@ async function* _runPersisted(params: PersistedParams): AsyncIterableIterator<Pe
col: position.col,
});
continue;
} else if (!call.typeArguments || !ts.isTypeQueryNode(call.typeArguments[0])) {
} else if (!docArg && !typeQuery) {
warnings.push({
message:
'"graphql.persisted" is missing a generic such as `graphql.persisted<typeof document>`.',
'"graphql.persisted" is missing a document.\n' +
'This may be passed as a generic such as `graphql.persisted<typeof document>` or as the second argument.',
file: filePath,
line: position.line,
col: position.col,
});
continue;
}

const typeQuery = call.typeArguments[0];
const { node: foundNode } = getDocumentReferenceFromTypeQuery(
typeQuery,
filePath,
pluginInfo
);
let foundNode: ts.CallExpression | null = null;
let referencingNode: ts.Node = call;
if (docArg && (ts.isCallExpression(docArg) || ts.isIdentifier(docArg))) {
const result = getDocumentReferenceFromDocumentNode(docArg, filePath, pluginInfo);
foundNode = result.node;
referencingNode = docArg;
} else if (typeQuery && ts.isTypeQueryNode(typeQuery)) {
const result = getDocumentReferenceFromTypeQuery(typeQuery, filePath, pluginInfo);
foundNode = result.node;
referencingNode = typeQuery;
}

if (!foundNode) {
warnings.push({
message:
`Could not find reference for "${typeQuery.getText()}".\n` +
`Could not find reference for "${referencingNode.getText()}".\n` +
'If this is unexpected, please file an issue describing your case.',
file: filePath,
line: position.line,
Expand All @@ -89,16 +99,15 @@ async function* _runPersisted(params: PersistedParams): AsyncIterableIterator<Pe
continue;
}

const { initializer } = foundNode;
if (
!initializer ||
!ts.isCallExpression(initializer) ||
(!ts.isNoSubstitutionTemplateLiteral(initializer.arguments[0]) &&
!ts.isStringLiteral(initializer.arguments[0]))
!foundNode ||
!ts.isCallExpression(foundNode) ||
(!ts.isNoSubstitutionTemplateLiteral(foundNode.arguments[0]) &&
!ts.isStringLiteral(foundNode.arguments[0]))
) {
warnings.push({
message:
`The referenced document of "${typeQuery.getText()}" contains no document string literal.\n` +
`The referenced document of "${referencingNode.getText()}" contains no document string literal.\n` +
'If this is unexpected, please file an issue describing your case.',
file: filePath,
line: position.line,
Expand All @@ -108,14 +117,14 @@ async function* _runPersisted(params: PersistedParams): AsyncIterableIterator<Pe
}

const fragments: FragmentDefinitionNode[] = [];
const operation = initializer.arguments[0].getText().slice(1, -1);
if (initializer.arguments[1] && ts.isArrayLiteralExpression(initializer.arguments[1])) {
unrollTadaFragments(initializer.arguments[1], fragments, pluginInfo);
const operation = foundNode.arguments[0].getText().slice(1, -1);
if (foundNode.arguments[1] && ts.isArrayLiteralExpression(foundNode.arguments[1])) {
unrollTadaFragments(foundNode.arguments[1], fragments, pluginInfo);
}

let document = operation;
for (const fragment of fragments) document += '\n\n' + print(fragment);
documents[JSON.parse(hash.getFullText())] = document;
documents[JSON.parse(hashArg.getFullText())] = document;
}

yield {
Expand Down
34 changes: 24 additions & 10 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 8 additions & 4 deletions src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,8 @@ interface GraphQLTadaAPI<Schema extends SchemaLike, Config extends AbstractConfi
* ```
*/
persisted<Document extends DocumentNodeLike = never>(
documentId: string
documentId: string,
document?: Document
): Document extends DocumentDecoration<infer Result, infer Variables>
? TadaPersistedDocumentNode<Result, Variables>
: never;
Expand Down Expand Up @@ -279,10 +280,13 @@ function initGraphQLTada<const Setup extends AbstractSetupSchema>() {
return value;
};

graphql.persisted = function persisted(documentId: string): TadaPersistedDocumentNode {
graphql.persisted = function persisted(
documentId: string,
document?: TadaDocumentNode
): TadaPersistedDocumentNode {
return {
kind: Kind.DOCUMENT,
definitions: [],
definitions: document ? document.definitions : [],
documentId,
};
};
Expand Down Expand Up @@ -354,7 +358,7 @@ interface TadaPersistedDocumentNode<
Variables = { [key: string]: any },
> extends DocumentNode,
DocumentDecoration<Result, Variables> {
definitions: readonly [];
definitions: readonly DefinitionNode[];
documentId: string;
}

Expand Down

0 comments on commit c32bd40

Please sign in to comment.