Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[typed-document-node] allow documentMode: graphqlTag #4518

Merged
merged 2 commits into from
Aug 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/rotten-steaks-nail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@graphql-codegen/visitor-plugin-common': patch
---

Allow getDocumentNodeSignature to control the entire generation flow of the typed documents
7 changes: 7 additions & 0 deletions .changeset/wet-news-juggle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@graphql-codegen/typed-document-node': patch
---

Allow this plugin to work with `documentMode: graphqlTag` correctly.

Added validation for preventing `documentMode: string` because it's not supported in this plugin.
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ export class ClientSideBaseVisitor<
protected _collectedOperations: OperationDefinitionNode[] = [];
protected _documents: Types.DocumentFile[] = [];
protected _additionalImports: string[] = [];
protected _imports = new Set<string>();

constructor(
protected _schema: GraphQLSchema,
Expand Down Expand Up @@ -306,16 +307,13 @@ export class ClientSideBaseVisitor<

protected _generateFragment(fragmentDocument: FragmentDefinitionNode): string | void {
const name = this.getFragmentVariableName(fragmentDocument);
const isDocumentNode =
this.config.documentMode === DocumentMode.documentNode ||
this.config.documentMode === DocumentMode.documentNodeImportFragments;
const fragmentResultType = this.convertName(fragmentDocument.name.value, {
useTypesPrefix: true,
suffix: this.getFragmentSuffix(fragmentDocument),
});
return `export const ${name}${
isDocumentNode ? `: ${this.getDocumentNodeSignature(fragmentResultType, 'unknown', fragmentDocument)}` : ''
} =${this.config.pureMagicComment ? ' /*#__PURE__*/' : ''} ${this._gql(fragmentDocument)};`;
return `export const ${name}${this.getDocumentNodeSignature(fragmentResultType, 'unknown', fragmentDocument)} =${
this.config.pureMagicComment ? ' /*#__PURE__*/' : ''
} ${this._gql(fragmentDocument)};`;
}

private get fragmentsGraph(): DepGraph<LoadedFragment> {
Expand Down Expand Up @@ -414,7 +412,7 @@ export class ClientSideBaseVisitor<
}

public getImports(options: { excludeFragments?: boolean } = {}): string[] {
const imports = [...this._additionalImports];
(this._additionalImports || []).forEach(i => this._imports.add(i));

switch (this.config.documentMode) {
case DocumentMode.documentNode:
Expand All @@ -423,7 +421,7 @@ export class ClientSideBaseVisitor<
const tagImport = this._generateImport(documentNodeImport, 'DocumentNode', true);

if (tagImport) {
imports.push(tagImport);
this._imports.add(tagImport);
}

break;
Expand All @@ -433,19 +431,19 @@ export class ClientSideBaseVisitor<
const tagImport = this._generateImport(gqlImport, 'gql', false);

if (tagImport) {
imports.push(tagImport);
this._imports.add(tagImport);
}

break;
}
case DocumentMode.external: {
if (this._collectedOperations.length > 0) {
if (this.config.importDocumentNodeExternallyFrom === 'near-operation-file' && this._documents.length === 1) {
imports.push(
this._imports.add(
`import * as Operations from './${this.clearExtension(basename(this._documents[0].location))}';`
);
} else {
imports.push(
this._imports.add(
`import * as Operations from '${this.clearExtension(this.config.importDocumentNodeExternallyFrom)}';`
);
}
Expand All @@ -463,13 +461,13 @@ export class ClientSideBaseVisitor<
documentMode === DocumentMode.string ||
documentMode === DocumentMode.documentNodeImportFragments
) {
imports.push(
...fragmentImports.map(fragmentImport => generateFragmentImportStatement(fragmentImport, 'document'))
);
fragmentImports.forEach(fragmentImport => {
this._imports.add(generateFragmentImportStatement(fragmentImport, 'document'));
});
}
}

return imports;
return Array.from(this._imports);
}

protected buildOperation(
Expand All @@ -486,8 +484,15 @@ export class ClientSideBaseVisitor<
resultType: string,
variablesTypes: string,
node: FragmentDefinitionNode | OperationDefinitionNode
) {
return `DocumentNode`;
): string {
if (
this.config.documentMode === DocumentMode.documentNode ||
this.config.documentMode === DocumentMode.documentNodeImportFragments
) {
return `: DocumentNode`;
}

return '';
}

public OperationDefinition(node: OperationDefinitionNode): string {
Expand Down Expand Up @@ -515,12 +520,13 @@ export class ClientSideBaseVisitor<

let documentString = '';
if (this.config.documentMode !== DocumentMode.external) {
const isDocumentNode =
this.config.documentMode === DocumentMode.documentNode ||
this.config.documentMode === DocumentMode.documentNodeImportFragments;
documentString = `${this.config.noExport ? '' : 'export'} const ${documentVariableName}${
isDocumentNode ? `: ${this.getDocumentNodeSignature(operationResultType, operationVariablesTypes, node)}` : ''
} =${this.config.pureMagicComment ? ' /*#__PURE__*/' : ''} ${this._gql(node)};`;
documentString = `${
this.config.noExport ? '' : 'export'
} const ${documentVariableName}${this.getDocumentNodeSignature(
operationResultType,
operationVariablesTypes,
node
)} =${this.config.pureMagicComment ? ' /*#__PURE__*/' : ''} ${this._gql(node)};`;
}

const additional = this.buildOperation(
Expand Down
8 changes: 6 additions & 2 deletions packages/plugins/typescript/typed-document-node/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Types, PluginValidateFn, PluginFunction } from '@graphql-codegen/plugin-helpers';
import { visit, concatAST, GraphQLSchema, Kind, FragmentDefinitionNode } from 'graphql';
import { extname } from 'path';
import { LoadedFragment, RawClientSideBasePluginConfig } from '@graphql-codegen/visitor-plugin-common';
import { LoadedFragment, RawClientSideBasePluginConfig, DocumentMode } from '@graphql-codegen/visitor-plugin-common';
import { TypeScriptDocumentNodesVisitor } from './visitor';

export const plugin: PluginFunction<RawClientSideBasePluginConfig> = (
Expand Down Expand Up @@ -32,12 +32,16 @@ export const plugin: PluginFunction<RawClientSideBasePluginConfig> = (
};
};

export const validate: PluginValidateFn<any> = async (
export const validate: PluginValidateFn<RawClientSideBasePluginConfig> = async (
schema: GraphQLSchema,
documents: Types.DocumentFile[],
config,
outputFile: string
) => {
if (config && config.documentMode === DocumentMode.string) {
throw new Error(`Plugin "typed-document-node" does not allow using 'documentMode: string' configuration!`);
}

if (extname(outputFile) !== '.ts' && extname(outputFile) !== '.tsx') {
throw new Error(`Plugin "typed-document-node" requires extension to be ".ts" or ".tsx"!`);
}
Expand Down
19 changes: 17 additions & 2 deletions packages/plugins/typescript/typed-document-node/src/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,24 @@ export class TypeScriptDocumentNodesVisitor extends ClientSideBaseVisitor<
);

autoBind(this);

// We need to make sure it's there because in this mode, the base plugin doesn't add the import
if (this.config.documentMode === DocumentMode.graphQLTag) {
const documentNodeImport = this._parseImport(this.config.documentNodeImport || 'graphql#DocumentNode');
const tagImport = this._generateImport(documentNodeImport, 'DocumentNode', true);
this._imports.add(tagImport);
}
}

protected getDocumentNodeSignature(resultType: string, variablesTypes: string) {
return `DocumentNode<${resultType}, ${variablesTypes}>`;
protected getDocumentNodeSignature(resultType: string, variablesTypes: string, node) {
if (
this.config.documentMode === DocumentMode.documentNode ||
this.config.documentMode === DocumentMode.documentNodeImportFragments ||
this.config.documentMode === DocumentMode.graphQLTag
) {
return `: DocumentNode<${resultType}, ${variablesTypes}>`;
}

return super.getDocumentNodeSignature(resultType, variablesTypes, node);
}
}