diff --git a/dev-test/codegen.ts b/dev-test/codegen.ts index 608648b8520..b3ff3eab2c2 100644 --- a/dev-test/codegen.ts +++ b/dev-test/codegen.ts @@ -265,6 +265,19 @@ const config: CodegenConfig = { }, }, }, + // #region documentsReadOnly + './dev-test/documents-readonly/app/types.generated.ts': { + schema: './dev-test/documents-readonly/schema.graphqls', + documents: ['./dev-test/documents-readonly/app/*.graphql.ts'], + documentsReadOnly: ['./dev-test/documents-readonly/lib/*.graphql.ts'], + plugins: ['typescript-operations'], + }, + './dev-test/documents-readonly/lib/types.generated.ts': { + schema: './dev-test/documents-readonly/schema.graphqls', + documents: ['./dev-test/documents-readonly/lib/*.graphql.ts'], + plugins: ['typescript-operations'], + }, + // #endregion }, }; diff --git a/dev-test/documents-readonly/app/User.graphql.ts b/dev-test/documents-readonly/app/User.graphql.ts new file mode 100644 index 00000000000..12fd4c7a9c3 --- /dev/null +++ b/dev-test/documents-readonly/app/User.graphql.ts @@ -0,0 +1,8 @@ +/* GraphQL */ ` + query User($id: ID!) { + user(id: $id) { + id + ...UserFragment + } + } +`; diff --git a/dev-test/documents-readonly/app/types.generated.ts b/dev-test/documents-readonly/app/types.generated.ts new file mode 100644 index 00000000000..fc9a2a812b2 --- /dev/null +++ b/dev-test/documents-readonly/app/types.generated.ts @@ -0,0 +1,8 @@ +export type UserQueryVariables = Exact<{ + id: Scalars['ID']['input']; +}>; + +export type UserQuery = { + __typename?: 'Query'; + user?: { __typename?: 'User'; id: string; name: string; role: UserRole } | null; +}; diff --git a/dev-test/documents-readonly/lib/UserFragment.graphql.ts b/dev-test/documents-readonly/lib/UserFragment.graphql.ts new file mode 100644 index 00000000000..a57919b561b --- /dev/null +++ b/dev-test/documents-readonly/lib/UserFragment.graphql.ts @@ -0,0 +1,7 @@ +/* GraphQL */ ` + fragment UserFragment on User { + id + name + role + } +`; diff --git a/dev-test/documents-readonly/lib/types.generated.ts b/dev-test/documents-readonly/lib/types.generated.ts new file mode 100644 index 00000000000..f113b4c5be0 --- /dev/null +++ b/dev-test/documents-readonly/lib/types.generated.ts @@ -0,0 +1 @@ +export type UserFragmentFragment = { __typename?: 'User'; id: string; name: string; role: UserRole }; diff --git a/dev-test/documents-readonly/schema.graphqls b/dev-test/documents-readonly/schema.graphqls new file mode 100644 index 00000000000..e2df2efded1 --- /dev/null +++ b/dev-test/documents-readonly/schema.graphqls @@ -0,0 +1,14 @@ +type Query { + user(id: ID!): User +} + +type User { + id: ID! + name: String! + role: UserRole! +} + +enum UserRole { + ADMIN + CUSTOMER +} diff --git a/packages/graphql-codegen-cli/src/codegen.ts b/packages/graphql-codegen-cli/src/codegen.ts index a839ced2f7a..463f7714648 100644 --- a/packages/graphql-codegen-cli/src/codegen.ts +++ b/packages/graphql-codegen-cli/src/codegen.ts @@ -14,7 +14,7 @@ import { normalizeOutputParam, Types, } from '@graphql-codegen/plugin-helpers'; -import { NoTypeDefinitionsFound } from '@graphql-tools/load'; +import { NoTypeDefinitionsFound, type UnnormalizedTypeDefPointer } from '@graphql-tools/load'; import { mergeTypeDefs } from '@graphql-tools/merge'; import { CodegenContext, ensureContext } from './config.js'; import { getDocumentTransform } from './documentTransforms.js'; @@ -86,6 +86,7 @@ export async function executeCodegen( let rootConfig: { [key: string]: any } = {}; let rootSchemas: Types.Schema[]; let rootDocuments: Types.OperationDocument[]; + let rootDocumentsReadOnly: Types.OperationDocument[]; const generates: { [filename: string]: Types.ConfiguredOutput } = {}; const cache = createCache(); @@ -136,6 +137,11 @@ export async function executeCodegen( /* Normalize root "documents" field */ rootDocuments = normalizeInstanceOrArray(config.documents); + /* Normalize root "documentsReadOnly" field */ + rootDocumentsReadOnly = normalizeInstanceOrArray( + config.documentsReadOnly, + ); + /* Normalize "generators" field */ const generateKeys = Object.keys(config.generates || {}); @@ -228,13 +234,15 @@ export async function executeCodegen( let outputSchemaAst: GraphQLSchema; let outputSchema: DocumentNode; const outputFileTemplateConfig = outputConfig.config || {}; - let outputDocuments: Types.DocumentFile[] = []; + const outputDocuments: Types.DocumentFile[] = []; const outputSpecificSchemas = normalizeInstanceOrArray( outputConfig.schema, ); let outputSpecificDocuments = normalizeInstanceOrArray( outputConfig.documents, ); + let outputSpecificDocumentsReadOnly = + normalizeInstanceOrArray(outputConfig.documentsReadOnly); const preset: Types.OutputPreset | null = hasPreset ? typeof outputConfig.preset === 'string' @@ -247,6 +255,10 @@ export async function executeCodegen( filename, outputSpecificDocuments, ); + outputSpecificDocumentsReadOnly = await preset.prepareDocuments( + filename, + outputSpecificDocumentsReadOnly, + ); } return subTask.newListr( @@ -308,41 +320,97 @@ export async function executeCodegen( task: wrapTask( async () => { debugLog(`[CLI] Loading Documents`); - const documentPointerMap: any = {}; + + const populateDocumentPointerMap = ( + allDocumentsDenormalizedPointers: Types.OperationDocument[], + ): UnnormalizedTypeDefPointer => { + const pointer: UnnormalizedTypeDefPointer = {}; + for (const denormalizedPtr of allDocumentsDenormalizedPointers) { + if (typeof denormalizedPtr === 'string') { + pointer[denormalizedPtr] = {}; + } else if (typeof denormalizedPtr === 'object') { + Object.assign(pointer, denormalizedPtr); + } + } + return pointer; + }; + const allDocumentsDenormalizedPointers = [ ...rootDocuments, ...outputSpecificDocuments, ]; - for (const denormalizedPtr of allDocumentsDenormalizedPointers) { - if (typeof denormalizedPtr === 'string') { - documentPointerMap[denormalizedPtr] = {}; - } else if (typeof denormalizedPtr === 'object') { - Object.assign(documentPointerMap, denormalizedPtr); - } - } + const documentPointerMap = populateDocumentPointerMap( + allDocumentsDenormalizedPointers, + ); const hash = JSON.stringify(documentPointerMap); - const result = await cache('documents', hash, async () => { - try { - const documents = await context.loadDocuments(documentPointerMap); - return { - documents, - }; - } catch (error) { - if ( - error instanceof NoTypeDefinitionsFound && - config.ignoreNoDocuments - ) { - return { - documents: [], - }; + const outputDocumentsStandard = await cache( + 'documents', + hash, + async (): Promise => { + try { + const documents = await context.loadDocuments( + documentPointerMap, + 'standard', + ); + return documents; + } catch (error) { + if ( + error instanceof NoTypeDefinitionsFound && + config.ignoreNoDocuments + ) { + return []; + } + throw error; } + }, + ); + + const allReadOnlyDenormalizedPointers = [ + ...rootDocumentsReadOnly, + ...outputSpecificDocumentsReadOnly, + ]; + + const readOnlyPointerMap = populateDocumentPointerMap( + allReadOnlyDenormalizedPointers, + ); - throw error; + const readOnlyHash = JSON.stringify(readOnlyPointerMap); + const outputDocumentsReadOnly = await cache( + 'documents', + readOnlyHash, + async (): Promise => { + try { + const documents = await context.loadDocuments( + readOnlyPointerMap, + 'read-only', + ); + return documents; + } catch (error) { + if ( + error instanceof NoTypeDefinitionsFound && + config.ignoreNoDocuments + ) { + return []; + } + throw error; + } + }, + ); + + const processedFile: Record = {}; + [...outputDocumentsStandard, ...outputDocumentsReadOnly].reduce< + Types.DocumentFile[] + >((prev, file) => { + if (processedFile[file.hash]) { + return prev; } - }); - outputDocuments = result.documents; + outputDocuments.push(file); + processedFile[file.hash] = true; + + return prev; + }, []); }, filename, `Load GraphQL documents: ${filename}`, @@ -437,7 +505,7 @@ export async function executeCodegen( pluginContext, profiler: context.profiler, documentTransforms, - }, + } satisfies Types.GenerateOptions, ]; const process = async (outputArgs: Types.GenerateOptions) => { @@ -519,9 +587,7 @@ export async function executeCodegen( const errors = executedContext.errors.map(subErr => subErr.message || subErr.toString()); error = new AggregateError(executedContext.errors, String(errors.join('\n\n'))); // Best-effort to all stack traces for debugging - error.stack = `${error.stack}\n\n${executedContext.errors - .map(subErr => subErr.stack) - .join('\n\n')}`; + error.stack = `${error.stack}\n\n${executedContext.errors.map(subErr => subErr.stack).join('\n\n')}`; } return { result, error }; diff --git a/packages/graphql-codegen-cli/src/config.ts b/packages/graphql-codegen-cli/src/config.ts index bbd58022f74..4f25afccc3d 100644 --- a/packages/graphql-codegen-cli/src/config.ts +++ b/packages/graphql-codegen-cli/src/config.ts @@ -4,7 +4,7 @@ import { createRequire } from 'module'; import { resolve } from 'path'; import { cosmiconfig, defaultLoaders } from 'cosmiconfig'; import { GraphQLSchema, GraphQLSchemaExtensions, print } from 'graphql'; -import { GraphQLConfig } from 'graphql-config'; +import { GraphQLConfig, type Source } from 'graphql-config'; import { createJiti } from 'jiti'; import { env } from 'string-env-interpolation'; import yaml from 'yaml'; @@ -16,6 +16,7 @@ import { Profiler, Types, } from '@graphql-codegen/plugin-helpers'; +import type { UnnormalizedTypeDefPointer } from '@graphql-tools/load'; import { findAndLoadGraphQLConfig } from './graphql-config.js'; import { defaultDocumentsLoadOptions, @@ -464,7 +465,10 @@ export class CodegenContext { return addHashToSchema(loadSchema(pointer, config)); } - async loadDocuments(pointer: Types.OperationDocument[]): Promise { + async loadDocuments( + pointer: UnnormalizedTypeDefPointer, + type: 'standard' | 'read-only', + ): Promise { const config = this.getConfig(defaultDocumentsLoadOptions); if (this._graphqlConfig) { // TODO: pointer won't work here @@ -472,10 +476,11 @@ export class CodegenContext { this._graphqlConfig .getProject(this._project) .loadDocuments(pointer, { ...config, ...config.config }), + type, ); } - return addHashToDocumentFiles(loadDocuments(pointer, config)); + return addHashToDocumentFiles(loadDocuments(pointer, config), type); } } @@ -502,24 +507,27 @@ function addHashToSchema(schemaPromise: Promise): Promise, + type: 'standard' | 'read-only', +): Promise { + function hashDocument(doc: Source) { + if (doc.rawSDL) { + return hashContent(doc.rawSDL); + } - if (doc.document) { - return hashContent(print(doc.document)); - } + if (doc.document) { + return hashContent(print(doc.document)); + } - return null; -} + return null; + } -function addHashToDocumentFiles( - documentFilesPromise: Promise, -): Promise { return documentFilesPromise.then(documentFiles => - documentFiles.map(doc => { + // Note: `doc` here is technically `Source`, but by the end of the funciton it's `Types.DocumentFile`. This re-declaration makes TypeScript happy. + documentFiles.map((doc: Types.DocumentFile): Types.DocumentFile => { doc.hash = hashDocument(doc); + doc.type = type; return doc; }), diff --git a/packages/graphql-codegen-cli/src/load.ts b/packages/graphql-codegen-cli/src/load.ts index de4e568e17e..3347ab49723 100644 --- a/packages/graphql-codegen-cli/src/load.ts +++ b/packages/graphql-codegen-cli/src/load.ts @@ -1,5 +1,6 @@ import { extname, join } from 'path'; import { GraphQLError, GraphQLSchema } from 'graphql'; +import type { Source } from 'graphql-config'; import { Types } from '@graphql-codegen/plugin-helpers'; import { ApolloEngineLoader } from '@graphql-tools/apollo-engine-loader'; import { CodeFileLoader } from '@graphql-tools/code-file-loader'; @@ -69,7 +70,7 @@ export async function loadSchema( export async function loadDocuments( documentPointers: UnnormalizedTypeDefPointer | UnnormalizedTypeDefPointer[], config: Types.Config, -): Promise { +): Promise { const loaders = [ new CodeFileLoader({ pluckConfig: { diff --git a/packages/graphql-codegen-cli/tests/codegen.spec.ts b/packages/graphql-codegen-cli/tests/codegen.spec.ts index 5fb7e8bb00f..9b3be904223 100644 --- a/packages/graphql-codegen-cli/tests/codegen.spec.ts +++ b/packages/graphql-codegen-cli/tests/codegen.spec.ts @@ -1486,6 +1486,167 @@ describe('Codegen Executor', () => { }); }); + describe('documentsReadOnly', () => { + it('should pass documentsReadOnly to preset buildGeneratesSection', async () => { + let capturedDocumentsReadOnly: Types.DocumentFile[] | undefined; + + const capturePreset: Types.OutputPreset = { + buildGeneratesSection: options => { + capturedDocumentsReadOnly = options.documentsReadOnly; + return [ + { + filename: 'out1/result.ts', + pluginMap: { typescript: require('@graphql-codegen/typescript') }, + plugins: [{ typescript: {} }], + schema: options.schema, + documents: options.documents, + config: options.config, + }, + ]; + }, + }; + + await executeCodegen({ + schema: SIMPLE_TEST_SCHEMA, + documents: `query root { f }`, + documentsReadOnly: `fragment Frag on MyType { f }`, + generates: { + 'out1/': { preset: capturePreset }, + }, + }); + + expect(capturedDocumentsReadOnly).toBeDefined(); + expect(capturedDocumentsReadOnly).toHaveLength(1); + }); + + it('should not include documentsReadOnly content in regular documents', async () => { + let capturedDocuments: Types.DocumentFile[] | undefined; + let capturedDocumentsReadOnly: Types.DocumentFile[] | undefined; + + const capturePreset: Types.OutputPreset = { + buildGeneratesSection: options => { + capturedDocuments = options.documents; + capturedDocumentsReadOnly = options.documentsReadOnly; + return [ + { + filename: 'out1/result.ts', + pluginMap: { typescript: require('@graphql-codegen/typescript') }, + plugins: [{ typescript: {} }], + schema: options.schema, + documents: options.documents, + config: options.config, + }, + ]; + }, + }; + + await executeCodegen({ + schema: SIMPLE_TEST_SCHEMA, + documents: `query root { f }`, + documentsReadOnly: `query readOnlyQuery { f }`, + generates: { + 'out1/': { preset: capturePreset }, + }, + }); + + expect(capturedDocuments).toHaveLength(1); + expect(capturedDocumentsReadOnly).toHaveLength(1); + + const documentNames = capturedDocuments.flatMap( + d => d.document?.definitions.map((def: any) => def.name?.value) ?? [], + ); + const readOnlyNames = capturedDocumentsReadOnly.flatMap( + d => d.document?.definitions.map((def: any) => def.name?.value) ?? [], + ); + + expect(documentNames).toContain('root'); + expect(documentNames).not.toContain('readOnlyQuery'); + expect(readOnlyNames).toContain('readOnlyQuery'); + expect(readOnlyNames).not.toContain('root'); + }); + + it('should not include documentsReadOnly operations in non-preset plugin output', async () => { + const { result } = await executeCodegen({ + schema: SIMPLE_TEST_SCHEMA, + documents: `query root { f }`, + documentsReadOnly: `query readOnlyQuery { f }`, + generates: { + 'out1.ts': { plugins: ['typescript-operations'] }, + }, + }); + + expect(result).toHaveLength(1); + // Only the regular document operation should be generated + expect(result[0].content).toContain('RootQuery'); + expect(result[0].content).not.toContain('ReadOnlyQuery'); + }); + + it('should support output-level documentsReadOnly', async () => { + let capturedDocumentsReadOnly: Types.DocumentFile[] | undefined; + + const capturePreset: Types.OutputPreset = { + buildGeneratesSection: options => { + capturedDocumentsReadOnly = options.documentsReadOnly; + return [ + { + filename: 'out1/result.ts', + pluginMap: { typescript: require('@graphql-codegen/typescript') }, + plugins: [{ typescript: {} }], + schema: options.schema, + documents: options.documents, + config: options.config, + }, + ]; + }, + }; + + await executeCodegen({ + schema: SIMPLE_TEST_SCHEMA, + generates: { + 'out1/': { + preset: capturePreset, + documentsReadOnly: `fragment Frag on MyType { f }`, + }, + }, + }); + + expect(capturedDocumentsReadOnly).toHaveLength(1); + }); + + it('should merge root and output-level documentsReadOnly', async () => { + let capturedDocumentsReadOnly: Types.DocumentFile[] | undefined; + + const capturePreset: Types.OutputPreset = { + buildGeneratesSection: options => { + capturedDocumentsReadOnly = options.documentsReadOnly; + return [ + { + filename: 'out1/result.ts', + pluginMap: { typescript: require('@graphql-codegen/typescript') }, + plugins: [{ typescript: {} }], + schema: options.schema, + documents: options.documents, + config: options.config, + }, + ]; + }, + }; + + await executeCodegen({ + schema: SIMPLE_TEST_SCHEMA, + documentsReadOnly: `fragment RootFrag on MyType { f }`, + generates: { + 'out1/': { + preset: capturePreset, + documentsReadOnly: `fragment OutputFrag on MyType { f }`, + }, + }, + }); + + expect(capturedDocumentsReadOnly).toHaveLength(2); + }); + }); + it('should not run out of memory when generating very complex types (issue #7720)', async () => { const { result } = await executeCodegen({ schema: ['../../dev-test/gatsby/schema.graphql'], diff --git a/packages/plugins/other/visitor-plugin-common/src/optimize-operations.ts b/packages/plugins/other/visitor-plugin-common/src/optimize-operations.ts index 42c15ad01aa..e4c6f8b0066 100644 --- a/packages/plugins/other/visitor-plugin-common/src/optimize-operations.ts +++ b/packages/plugins/other/visitor-plugin-common/src/optimize-operations.ts @@ -14,6 +14,7 @@ export function optimizeOperations( ); return newDocuments.map((document, index) => ({ + ...documents[index], location: documents[index]?.location || 'optimized by relay', document, })); diff --git a/packages/plugins/typescript/gql-tag-operations/src/index.ts b/packages/plugins/typescript/gql-tag-operations/src/index.ts index d9ecc9e3b33..d50f7a873f5 100644 --- a/packages/plugins/typescript/gql-tag-operations/src/index.ts +++ b/packages/plugins/typescript/gql-tag-operations/src/index.ts @@ -1,7 +1,7 @@ import { FragmentDefinitionNode, OperationDefinitionNode } from 'graphql'; import { normalizeImportExtension, PluginFunction } from '@graphql-codegen/plugin-helpers'; +import type { Types } from '@graphql-codegen/plugin-helpers'; import { DocumentMode } from '@graphql-codegen/visitor-plugin-common'; -import { Source } from '@graphql-tools/utils'; export type OperationOrFragment = { initialName: string; @@ -9,7 +9,7 @@ export type OperationOrFragment = { }; export type SourceWithOperations = { - source: Source; + source: Types.DocumentFile; operations: Array; }; diff --git a/packages/plugins/typescript/operations/src/index.ts b/packages/plugins/typescript/operations/src/index.ts index 34d5d0529ca..1c4d1559443 100644 --- a/packages/plugins/typescript/operations/src/index.ts +++ b/packages/plugins/typescript/operations/src/index.ts @@ -1,4 +1,4 @@ -import { concatAST, FragmentDefinitionNode, GraphQLSchema, Kind } from 'graphql'; +import { concatAST, FragmentDefinitionNode, GraphQLSchema, Kind, type DocumentNode } from 'graphql'; import { oldVisit, PluginFunction, Types } from '@graphql-codegen/plugin-helpers'; import { LoadedFragment, optimizeOperations } from '@graphql-codegen/visitor-plugin-common'; import { TypeScriptDocumentsPluginConfig } from './config.js'; @@ -23,11 +23,40 @@ export const plugin: PluginFunction< includeFragments: config.flattenGeneratedTypesIncludeFragments, }) : rawDocuments; - const allAst = concatAST(documents.map(v => v.document)); + const parsedDocuments = documents.reduce<{ + all: { + documentFiles: Types.DocumentFile[]; + documentNodes: DocumentNode[]; + }; + standard: { + documentFiles: Types.DocumentFile[]; + documentNodes: DocumentNode[]; + }; + }>( + (prev, document) => { + prev.all.documentFiles.push(document); + prev.all.documentNodes.push(document.document); + + if (document.type === 'standard') { + prev.standard.documentFiles.push(document); + prev.standard.documentNodes.push(document.document); + } + + return prev; + }, + { + all: { documentFiles: [], documentNodes: [] }, + standard: { documentFiles: [], documentNodes: [] }, + }, + ); + + // For Fragment types to resolve correctly, we must get read all docs (`standard` and `read-only`) + // Fragment types are usually (but not always) in `read-only` files in certain setup, like a monorepo. + const allDocumentsAST = concatAST(parsedDocuments.all.documentNodes); const allFragments: LoadedFragment[] = [ ...( - allAst.definitions.filter( + allDocumentsAST.definitions.filter( d => d.kind === Kind.FRAGMENT_DEFINITION, ) as FragmentDefinitionNode[] ).map(fragmentDef => ({ @@ -41,7 +70,10 @@ export const plugin: PluginFunction< const visitor = new TypeScriptDocumentsVisitor(schema, config, allFragments); - const visitorResult = oldVisit(allAst, { + // We only visit `standard` documents to generate types. + // `read-only` documents are included as references for typechecking and completeness i.e. only used for reading purposes, no writing. + const documentsToVisitAST = concatAST(parsedDocuments.standard.documentNodes); + const visitorResult = oldVisit(documentsToVisitAST, { leave: visitor, }); @@ -50,7 +82,7 @@ export const plugin: PluginFunction< if (config.addOperationExport) { const exportConsts = []; - for (const d of allAst.definitions) { + for (const d of allDocumentsAST.definitions) { if ('name' in d) { exportConsts.push(`export declare const ${d.name.value}: import("graphql").DocumentNode;`); } diff --git a/packages/presets/client/src/process-sources.ts b/packages/presets/client/src/process-sources.ts index 9a86af3e16f..c9b8e41b792 100644 --- a/packages/presets/client/src/process-sources.ts +++ b/packages/presets/client/src/process-sources.ts @@ -1,10 +1,13 @@ import { FragmentDefinitionNode, OperationDefinitionNode } from 'graphql'; import { OperationOrFragment, SourceWithOperations } from '@graphql-codegen/gql-tag-operations'; -import { Source } from '@graphql-tools/utils'; +import type { Types } from '@graphql-codegen/plugin-helpers'; export type BuildNameFunction = (type: OperationDefinitionNode | FragmentDefinitionNode) => string; -export function processSources(sources: Array, buildName: BuildNameFunction) { +export function processSources( + sources: Array, + buildName: BuildNameFunction, +): Array { const sourcesWithOperations: Array = []; for (const originalSource of sources) { @@ -86,7 +89,7 @@ export function processSources(sources: Array, buildName: BuildNameFunct * * @param source */ -function fixLinebreaks(source: Source) { +function fixLinebreaks(source: Types.DocumentFile) { const fixedSource = { ...source }; fixedSource.rawSDL = source.rawSDL.replace(/\r\n/g, '\n'); diff --git a/packages/utils/plugins-helpers/src/types.ts b/packages/utils/plugins-helpers/src/types.ts index f1d5fb0c8fd..b4e964a504f 100644 --- a/packages/utils/plugins-helpers/src/types.ts +++ b/packages/utils/plugins-helpers/src/types.ts @@ -34,7 +34,8 @@ export namespace Types { }; export interface DocumentFile extends Source { - hash?: string; + hash: string; + type: 'standard' | 'read-only'; } /* Utils */ @@ -303,6 +304,12 @@ export namespace Types { * For more details: https://graphql-code-generator.com/docs/config-reference/documents-field */ documents?: InstanceOrArray; + /** + * @description A pointer(s) to your GraphQL documents that will be read but will not have type files generated for them. + * These documents are available to plugins for type resolution (e.g. fragment types), but no output files will be generated based on them. + * Accepts the same formats as `documents`. + */ + documentsReadOnly?: InstanceOrArray; /** * @description A pointer(s) to your GraphQL schema. This schema will be available only for this specific `generates` record. * You can use one of the following: @@ -434,6 +441,12 @@ export namespace Types { * For more details: https://graphql-code-generator.com/docs/config-reference/documents-field */ documents?: InstanceOrArray; + /** + * @description A pointer(s) to your GraphQL documents that will be read but will not have type files generated for them. + * These documents are available to plugins for type resolution (e.g. fragment types), but no output files will be generated based on them. + * Accepts the same formats as `documents`. + */ + documentsReadOnly?: InstanceOrArray; /** * @type object * @additionalProperties true