@nmarks/graphql-codegen-per-operation-file-preset 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,146 @@
1
+ import { Kind, print } from 'graphql';
2
+ import { BaseVisitor, buildScalarsFromConfig, getConfigValue, getPossibleTypes, } from '@graphql-codegen/visitor-plugin-common';
3
+ import { analyzeFragmentUsage, generateOperationFilePath } from './utils.js';
4
+ /**
5
+ * Creates fragment imports based on possible types and usage
6
+ */
7
+ function createFragmentImports(baseVisitor, fragmentName, possibleTypes, usedTypes) {
8
+ const fragmentImports = [];
9
+ // Always include the document import
10
+ fragmentImports.push({
11
+ name: baseVisitor.getFragmentVariableName(fragmentName),
12
+ kind: 'document',
13
+ });
14
+ const fragmentSuffix = baseVisitor.getFragmentSuffix(fragmentName);
15
+ if (possibleTypes.length === 1) {
16
+ fragmentImports.push({
17
+ name: baseVisitor.convertName(fragmentName, {
18
+ useTypesPrefix: true,
19
+ suffix: fragmentSuffix,
20
+ }),
21
+ kind: 'type',
22
+ });
23
+ }
24
+ else if (possibleTypes.length > 0) {
25
+ const typesToImport = usedTypes && usedTypes.length > 0 ? usedTypes : possibleTypes;
26
+ typesToImport.forEach(typeName => {
27
+ fragmentImports.push({
28
+ name: baseVisitor.convertName(fragmentName, {
29
+ useTypesPrefix: true,
30
+ suffix: `_${typeName}` + (fragmentSuffix.length > 0 ? `_${fragmentSuffix}` : ''),
31
+ }),
32
+ kind: 'type',
33
+ });
34
+ });
35
+ }
36
+ return fragmentImports;
37
+ }
38
+ /**
39
+ * Used by `buildFragmentResolver` to build a mapping of fragmentNames to paths, importNames, and other useful info
40
+ *
41
+ * KEY DIFFERENCE from near-operation-file:
42
+ * The filePath is generated based on the fragment NAME, not the source file location
43
+ */
44
+ function buildFragmentRegistry(baseVisitor, { folder, extension }, { documents }, schemaObject) {
45
+ const duplicateFragmentNames = [];
46
+ const registry = documents.reduce((prev, documentRecord) => {
47
+ const fragments = documentRecord.document.definitions.filter(d => d.kind === Kind.FRAGMENT_DEFINITION);
48
+ for (const fragment of fragments) {
49
+ const schemaType = schemaObject.getType(fragment.typeCondition.name.value);
50
+ if (!schemaType) {
51
+ throw new Error(`Fragment "${fragment.name.value}" is set on non-existing type "${fragment.typeCondition.name.value}"!`);
52
+ }
53
+ const fragmentName = fragment.name.value;
54
+ // KEY CHANGE: Generate path based on fragment name, not source file
55
+ const filePath = generateOperationFilePath(documentRecord.location, fragmentName, folder, extension);
56
+ const possibleTypes = getPossibleTypes(schemaObject, schemaType);
57
+ const possibleTypeNames = possibleTypes.map(t => t.name);
58
+ const imports = createFragmentImports(baseVisitor, fragment.name.value, possibleTypeNames);
59
+ if (prev[fragmentName] && print(fragment) !== print(prev[fragmentName].node)) {
60
+ duplicateFragmentNames.push(fragmentName);
61
+ }
62
+ prev[fragmentName] = {
63
+ filePath,
64
+ imports,
65
+ onType: fragment.typeCondition.name.value,
66
+ node: fragment,
67
+ possibleTypes: possibleTypeNames,
68
+ };
69
+ }
70
+ return prev;
71
+ }, {});
72
+ if (duplicateFragmentNames.length) {
73
+ throw new Error(`Multiple fragments with the name(s) "${duplicateFragmentNames.join(', ')}" were found.`);
74
+ }
75
+ return registry;
76
+ }
77
+ /**
78
+ * Creates a BaseVisitor with standard configuration
79
+ */
80
+ function createBaseVisitor(config, schemaObject) {
81
+ return new BaseVisitor(config, {
82
+ scalars: buildScalarsFromConfig(schemaObject, config),
83
+ dedupeOperationSuffix: getConfigValue(config.dedupeOperationSuffix, false),
84
+ omitOperationSuffix: getConfigValue(config.omitOperationSuffix, false),
85
+ fragmentVariablePrefix: getConfigValue(config.fragmentVariablePrefix, ''),
86
+ fragmentVariableSuffix: getConfigValue(config.fragmentVariableSuffix, 'FragmentDoc'),
87
+ });
88
+ }
89
+ /**
90
+ * Builds a fragment "resolver" that collects `externalFragments` definitions and `fragmentImportStatements`
91
+ */
92
+ export default function buildFragmentResolver(collectorOptions, presetOptions, schemaObject, dedupeFragments = false) {
93
+ const { config } = presetOptions;
94
+ const baseVisitor = createBaseVisitor(config, schemaObject);
95
+ const fragmentRegistry = buildFragmentRegistry(baseVisitor, collectorOptions, presetOptions, schemaObject);
96
+ const { baseOutputDir } = presetOptions;
97
+ const { baseDir, typesImport } = collectorOptions;
98
+ function resolveFragments(generatedFilePath, documentFileContent) {
99
+ const { fragmentsInUse, usedFragmentTypes } = analyzeFragmentUsage(documentFileContent, fragmentRegistry, schemaObject);
100
+ const externalFragments = [];
101
+ const fragmentFileImports = {};
102
+ for (const [fragmentName, level] of Object.entries(fragmentsInUse)) {
103
+ const fragmentDetails = fragmentRegistry[fragmentName];
104
+ if (!fragmentDetails)
105
+ continue;
106
+ // add top level references to the import object
107
+ // we don't check or global namespace because the calling config can do so
108
+ if (level === 0 ||
109
+ (dedupeFragments &&
110
+ ['OperationDefinition', 'FragmentDefinition'].includes(documentFileContent.definitions[0].kind))) {
111
+ if (fragmentDetails.filePath !== generatedFilePath) {
112
+ // don't emit imports to same location
113
+ const usedTypesForFragment = usedFragmentTypes[fragmentName] || [];
114
+ const filteredImports = createFragmentImports(baseVisitor, fragmentName, fragmentDetails.possibleTypes, usedTypesForFragment);
115
+ if (!fragmentFileImports[fragmentDetails.filePath]) {
116
+ fragmentFileImports[fragmentDetails.filePath] = [];
117
+ }
118
+ fragmentFileImports[fragmentDetails.filePath].push(...filteredImports);
119
+ }
120
+ }
121
+ externalFragments.push({
122
+ level,
123
+ isExternal: true,
124
+ name: fragmentName,
125
+ onType: fragmentDetails.onType,
126
+ node: fragmentDetails.node,
127
+ });
128
+ }
129
+ return {
130
+ externalFragments,
131
+ fragmentImports: Object.entries(fragmentFileImports).map(([fragmentsFilePath, identifiers]) => ({
132
+ baseDir,
133
+ baseOutputDir,
134
+ outputPath: generatedFilePath,
135
+ importSource: {
136
+ path: fragmentsFilePath,
137
+ identifiers,
138
+ },
139
+ emitLegacyCommonJSImports: presetOptions.config.emitLegacyCommonJSImports,
140
+ importExtension: presetOptions.config.importExtension,
141
+ typesImport,
142
+ })),
143
+ };
144
+ }
145
+ return resolveFragments;
146
+ }
package/esm/index.js ADDED
@@ -0,0 +1,107 @@
1
+ import { join } from 'path';
2
+ import { buildASTSchema, Kind } from 'graphql';
3
+ import addPlugin from '@graphql-codegen/add';
4
+ import { getConfigValue, } from '@graphql-codegen/visitor-plugin-common';
5
+ import { resolveDocumentImports } from './resolve-document-imports.js';
6
+ import { generateOperationFilePath } from './utils.js';
7
+ /**
8
+ * Extract operation and fragment names from a document
9
+ */
10
+ function extractDefinitions(document) {
11
+ const definitions = [];
12
+ for (const def of document.definitions) {
13
+ if (def.kind === Kind.OPERATION_DEFINITION && def.name) {
14
+ definitions.push({ name: def.name.value, definition: def });
15
+ }
16
+ else if (def.kind === Kind.FRAGMENT_DEFINITION) {
17
+ definitions.push({ name: def.name.value, definition: def });
18
+ }
19
+ }
20
+ return definitions;
21
+ }
22
+ export const preset = {
23
+ buildGeneratesSection: options => {
24
+ var _a;
25
+ const schemaObject = options.schemaAst
26
+ ? options.schemaAst
27
+ : buildASTSchema(options.schema, options.config);
28
+ const baseDir = options.presetConfig.cwd || process.cwd();
29
+ const extension = options.presetConfig.extension || '.ts';
30
+ const folder = options.presetConfig.folder || '__generated__';
31
+ const importTypesNamespace = options.presetConfig.importTypesNamespace || 'Types';
32
+ const { baseTypesPath } = options.presetConfig;
33
+ if (!baseTypesPath) {
34
+ throw new Error(`Preset "per-operation-file" requires you to specify "baseTypesPath" configuration!`);
35
+ }
36
+ const shouldAbsolute = !baseTypesPath.startsWith('~');
37
+ const pluginMap = {
38
+ ...options.pluginMap,
39
+ add: addPlugin,
40
+ };
41
+ // Resolve fragment dependencies using our adapted fragment resolver
42
+ // Fragment paths will be generated based on fragment names
43
+ const sources = resolveDocumentImports(options, schemaObject, {
44
+ baseDir,
45
+ folder,
46
+ extension,
47
+ schemaTypesSource: {
48
+ path: shouldAbsolute ? join(options.baseOutputDir, baseTypesPath) : baseTypesPath,
49
+ namespace: importTypesNamespace,
50
+ },
51
+ typesImport: (_a = options.config.useTypeImports) !== null && _a !== void 0 ? _a : false,
52
+ }, getConfigValue(options.config.dedupeFragments, false));
53
+ const artifacts = [];
54
+ // Now split each source into separate files per operation/fragment
55
+ for (const source of sources) {
56
+ const definitions = extractDefinitions(source.documents[0].document);
57
+ for (const { name, definition } of definitions) {
58
+ const filename = generateOperationFilePath(source.documents[0].location, name, folder, extension);
59
+ // Create a document with just this operation/fragment
60
+ const singleDefDocument = {
61
+ kind: Kind.DOCUMENT,
62
+ definitions: [definition],
63
+ };
64
+ const singleDefSource = {
65
+ rawSDL: source.documents[0].rawSDL, // TODO: might need to filter this
66
+ document: singleDefDocument,
67
+ location: source.documents[0].location,
68
+ };
69
+ // Update fragment imports to use the correct output path for this operation
70
+ const updatedFragmentImports = source.fragmentImports.map(fragmentImport => ({
71
+ ...fragmentImport,
72
+ outputPath: filename, // Update to actual output path
73
+ }));
74
+ const plugins = [
75
+ ...(options.config.globalNamespace
76
+ ? []
77
+ : source.importStatements.map(importStatement => ({
78
+ add: { content: importStatement },
79
+ }))),
80
+ ...options.plugins,
81
+ ];
82
+ const config = {
83
+ ...options.config,
84
+ exportFragmentSpreadSubTypes: true,
85
+ namespacedImportName: importTypesNamespace,
86
+ externalFragments: source.externalFragments,
87
+ fragmentImports: updatedFragmentImports,
88
+ };
89
+ artifacts.push({
90
+ ...options,
91
+ filename,
92
+ documents: [singleDefSource],
93
+ plugins,
94
+ pluginMap,
95
+ config,
96
+ schema: options.schema,
97
+ schemaAst: schemaObject,
98
+ skipDocumentsValidation: typeof options.config.skipDocumentsValidation === 'undefined'
99
+ ? { skipDuplicateValidation: true }
100
+ : options.config.skipDocumentsValidation,
101
+ });
102
+ }
103
+ }
104
+ return artifacts;
105
+ },
106
+ };
107
+ export default preset;
@@ -0,0 +1,54 @@
1
+ import { isUsingTypes } from '@graphql-codegen/plugin-helpers';
2
+ import { generateImportStatement, resolveImportSource, } from '@graphql-codegen/visitor-plugin-common';
3
+ import buildFragmentResolver from './fragment-resolver.js';
4
+ /**
5
+ * Transform the preset's provided documents into single-file generator sources, while resolving fragment and user-defined imports
6
+ *
7
+ * Resolves user provided imports and fragment imports using the `DocumentImportResolverOptions`.
8
+ * Does not define specific plugins, but rather returns a string[] of `importStatements` for the calling plugin to make use of
9
+ */
10
+ export function resolveDocumentImports(presetOptions, schemaObject, importResolverOptions, dedupeFragments = false) {
11
+ const resolveFragments = buildFragmentResolver(importResolverOptions, presetOptions, schemaObject, dedupeFragments);
12
+ const { baseOutputDir, documents } = presetOptions;
13
+ const { schemaTypesSource, baseDir, typesImport } = importResolverOptions;
14
+ return documents.map(documentFile => {
15
+ try {
16
+ // NOTE: We pass a placeholder filename here since we'll generate proper filenames per-operation later
17
+ // The important part is that fragment resolution will use the correct paths from the registry
18
+ const placeholderFilePath = documentFile.location;
19
+ const importStatements = [];
20
+ const { externalFragments, fragmentImports } = resolveFragments(placeholderFilePath, documentFile.document);
21
+ const externalFragmentsInjectedDocument = {
22
+ ...documentFile.document,
23
+ definitions: [
24
+ ...documentFile.document.definitions,
25
+ ...externalFragments.map(fragment => fragment.node),
26
+ ],
27
+ };
28
+ if (isUsingTypes(externalFragmentsInjectedDocument, [], schemaObject)) {
29
+ const schemaTypesImportStatement = generateImportStatement({
30
+ baseDir,
31
+ emitLegacyCommonJSImports: presetOptions.config.emitLegacyCommonJSImports,
32
+ importExtension: presetOptions.config.importExtension,
33
+ importSource: resolveImportSource(schemaTypesSource),
34
+ baseOutputDir,
35
+ outputPath: placeholderFilePath,
36
+ typesImport,
37
+ });
38
+ importStatements.unshift(schemaTypesImportStatement);
39
+ }
40
+ return {
41
+ filename: placeholderFilePath,
42
+ documents: [documentFile],
43
+ importStatements,
44
+ fragmentImports,
45
+ externalFragments,
46
+ };
47
+ }
48
+ catch (e) {
49
+ throw new Error(`Unable to validate GraphQL document! \n
50
+ File ${documentFile.location} caused error:
51
+ ${e.message || e.toString()}`);
52
+ }
53
+ });
54
+ }
package/esm/utils.js ADDED
@@ -0,0 +1,115 @@
1
+ import { join, dirname } from 'path';
2
+ import { isInterfaceType, isObjectType, isUnionType, TypeInfo, visit, visitWithTypeInfo, } from 'graphql';
3
+ import { getPossibleTypes, separateSelectionSet } from '@graphql-codegen/visitor-plugin-common';
4
+ /**
5
+ * Generate output file path for a specific operation/fragment
6
+ */
7
+ export function generateOperationFilePath(sourceLocation, operationName, folder, extension) {
8
+ const dir = dirname(sourceLocation);
9
+ return join(dir, folder, `${operationName}${extension}`).replace(/\\/g, '/');
10
+ }
11
+ /**
12
+ * Analyzes fragment usage in a GraphQL document.
13
+ * Returns information about which fragments are used and which specific types they're used with.
14
+ */
15
+ export function analyzeFragmentUsage(documentNode, fragmentRegistry, schema) {
16
+ const localFragments = getLocalFragments(documentNode);
17
+ const fragmentsInUse = extractExternalFragmentsInUse(documentNode, fragmentRegistry, localFragments);
18
+ const usedFragmentTypes = analyzeFragmentTypeUsage(documentNode, fragmentRegistry, schema, localFragments, fragmentsInUse);
19
+ return { fragmentsInUse, usedFragmentTypes };
20
+ }
21
+ /**
22
+ * Get all fragment definitions that are local to this document
23
+ */
24
+ function getLocalFragments(documentNode) {
25
+ const localFragments = new Set();
26
+ visit(documentNode, {
27
+ FragmentDefinition: node => {
28
+ localFragments.add(node.name.value);
29
+ },
30
+ });
31
+ return localFragments;
32
+ }
33
+ export function extractExternalFragmentsInUse(documentNode, fragmentNameToFile, localFragment, result = {}, level = 0) {
34
+ // Then, look for all used fragments in this document
35
+ visit(documentNode, {
36
+ FragmentSpread: node => {
37
+ if (!localFragment.has(node.name.value) &&
38
+ (result[node.name.value] === undefined || level < result[node.name.value])) {
39
+ result[node.name.value] = level;
40
+ if (fragmentNameToFile[node.name.value]) {
41
+ extractExternalFragmentsInUse(fragmentNameToFile[node.name.value].node, fragmentNameToFile, localFragment, result, level + 1);
42
+ }
43
+ }
44
+ },
45
+ });
46
+ return result;
47
+ }
48
+ /**
49
+ * Analyze which specific types each fragment is used with (for polymorphic fragments)
50
+ */
51
+ function analyzeFragmentTypeUsage(documentNode, fragmentRegistry, schema, localFragments, fragmentsInUse) {
52
+ const usedFragmentTypes = {};
53
+ const typeInfo = new TypeInfo(schema);
54
+ visit(documentNode, visitWithTypeInfo(typeInfo, {
55
+ Field: (node) => {
56
+ if (!node.selectionSet)
57
+ return;
58
+ const fieldType = typeInfo.getType();
59
+ if (!fieldType)
60
+ return;
61
+ const baseType = getBaseType(fieldType);
62
+ if (isObjectType(baseType) || isInterfaceType(baseType) || isUnionType(baseType)) {
63
+ analyzeSelectionSetTypeContext(node.selectionSet, baseType.name, usedFragmentTypes, fragmentRegistry, schema, localFragments);
64
+ }
65
+ },
66
+ }));
67
+ const result = {};
68
+ // Fill in missing types for multi-type fragments
69
+ for (const fragmentName in fragmentsInUse) {
70
+ const fragment = fragmentRegistry[fragmentName];
71
+ if (!fragment || fragment.possibleTypes.length <= 1)
72
+ continue;
73
+ const usedTypes = usedFragmentTypes[fragmentName];
74
+ result[fragmentName] = (usedTypes === null || usedTypes === void 0 ? void 0 : usedTypes.size) > 0 ? Array.from(usedTypes) : fragment.possibleTypes;
75
+ }
76
+ return result;
77
+ }
78
+ /**
79
+ * Analyze fragment usage within a specific selection set and type context
80
+ */
81
+ function analyzeSelectionSetTypeContext(selectionSet, currentTypeName, usedFragmentTypes, fragmentRegistry, schema, localFragments) {
82
+ var _a, _b;
83
+ var _c;
84
+ const { spreads, inlines } = separateSelectionSet(selectionSet.selections);
85
+ // Process fragment spreads in this type context
86
+ for (const spread of spreads) {
87
+ if (localFragments.has(spread.name.value))
88
+ continue;
89
+ const fragment = fragmentRegistry[spread.name.value];
90
+ if (!fragment || fragment.possibleTypes.length <= 1)
91
+ continue;
92
+ const currentType = schema.getType(currentTypeName);
93
+ if (!currentType)
94
+ continue;
95
+ const possibleTypes = getPossibleTypes(schema, currentType).map(t => t.name);
96
+ const matchingTypes = possibleTypes.filter(type => fragment.possibleTypes.includes(type));
97
+ if (matchingTypes.length > 0) {
98
+ const typeSet = ((_a = usedFragmentTypes[_c = spread.name.value]) !== null && _a !== void 0 ? _a : (usedFragmentTypes[_c] = new Set()));
99
+ matchingTypes.forEach(type => typeSet.add(type));
100
+ }
101
+ }
102
+ // Process inline fragments
103
+ for (const inline of inlines) {
104
+ if (((_b = inline.typeCondition) === null || _b === void 0 ? void 0 : _b.name.value) && inline.selectionSet) {
105
+ analyzeSelectionSetTypeContext(inline.selectionSet, inline.typeCondition.name.value, usedFragmentTypes, fragmentRegistry, schema, localFragments);
106
+ }
107
+ }
108
+ }
109
+ function getBaseType(type) {
110
+ let baseType = type;
111
+ while ('ofType' in baseType && baseType.ofType) {
112
+ baseType = baseType.ofType;
113
+ }
114
+ return baseType;
115
+ }
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@nmarks/graphql-codegen-per-operation-file-preset",
3
+ "version": "1.0.0",
4
+ "description": "GraphQL Code Generator preset for generating one file per operation/fragment",
5
+ "peerDependencies": {
6
+ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
7
+ },
8
+ "dependencies": {
9
+ "@graphql-codegen/add": "^6.0.0",
10
+ "@graphql-codegen/plugin-helpers": "^6.1.0",
11
+ "@graphql-codegen/visitor-plugin-common": "^6.2.1",
12
+ "@graphql-tools/utils": "^10.0.0",
13
+ "tslib": "^2.8.1"
14
+ },
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/dotansimha/graphql-code-generator-community.git",
18
+ "directory": "packages/presets/per-operation-file"
19
+ },
20
+ "license": "MIT",
21
+ "engines": {
22
+ "node": ">= 16.0.0"
23
+ },
24
+ "main": "cjs/index.js",
25
+ "module": "esm/index.js",
26
+ "typings": "typings/index.d.ts",
27
+ "typescript": {
28
+ "definition": "typings/index.d.ts"
29
+ },
30
+ "type": "module",
31
+ "exports": {
32
+ ".": {
33
+ "require": {
34
+ "types": "./typings/index.d.cts",
35
+ "default": "./cjs/index.js"
36
+ },
37
+ "import": {
38
+ "types": "./typings/index.d.ts",
39
+ "default": "./esm/index.js"
40
+ },
41
+ "default": {
42
+ "types": "./typings/index.d.ts",
43
+ "default": "./esm/index.js"
44
+ }
45
+ },
46
+ "./package.json": "./package.json"
47
+ }
48
+ }
@@ -0,0 +1,29 @@
1
+ import { DocumentNode, FragmentDefinitionNode, GraphQLSchema } from 'graphql';
2
+ import { Types } from '@graphql-codegen/plugin-helpers';
3
+ import { FragmentImport, ImportDeclaration, LoadedFragment, ParsedConfig } from '@graphql-codegen/visitor-plugin-common';
4
+ import { DocumentImportResolverOptions } from './resolve-document-imports.cjs';
5
+ export interface PerOperationFileParsedConfig extends ParsedConfig {
6
+ importTypesNamespace?: string;
7
+ dedupeOperationSuffix: boolean;
8
+ omitOperationSuffix: boolean;
9
+ fragmentVariablePrefix: string;
10
+ fragmentVariableSuffix: string;
11
+ }
12
+ export type FragmentRegistry = {
13
+ [fragmentName: string]: {
14
+ filePath: string;
15
+ onType: string;
16
+ node: FragmentDefinitionNode;
17
+ imports: Array<FragmentImport>;
18
+ possibleTypes: string[];
19
+ };
20
+ };
21
+ /**
22
+ * Builds a fragment "resolver" that collects `externalFragments` definitions and `fragmentImportStatements`
23
+ */
24
+ export default function buildFragmentResolver<T>(collectorOptions: DocumentImportResolverOptions, presetOptions: Types.PresetFnArgs<T>, schemaObject: GraphQLSchema, dedupeFragments?: boolean): (generatedFilePath: string, documentFileContent: DocumentNode) => {
25
+ externalFragments: LoadedFragment<{
26
+ level: number;
27
+ }>[];
28
+ fragmentImports: ImportDeclaration<FragmentImport>[];
29
+ };
@@ -0,0 +1,29 @@
1
+ import { DocumentNode, FragmentDefinitionNode, GraphQLSchema } from 'graphql';
2
+ import { Types } from '@graphql-codegen/plugin-helpers';
3
+ import { FragmentImport, ImportDeclaration, LoadedFragment, ParsedConfig } from '@graphql-codegen/visitor-plugin-common';
4
+ import { DocumentImportResolverOptions } from './resolve-document-imports.js';
5
+ export interface PerOperationFileParsedConfig extends ParsedConfig {
6
+ importTypesNamespace?: string;
7
+ dedupeOperationSuffix: boolean;
8
+ omitOperationSuffix: boolean;
9
+ fragmentVariablePrefix: string;
10
+ fragmentVariableSuffix: string;
11
+ }
12
+ export type FragmentRegistry = {
13
+ [fragmentName: string]: {
14
+ filePath: string;
15
+ onType: string;
16
+ node: FragmentDefinitionNode;
17
+ imports: Array<FragmentImport>;
18
+ possibleTypes: string[];
19
+ };
20
+ };
21
+ /**
22
+ * Builds a fragment "resolver" that collects `externalFragments` definitions and `fragmentImportStatements`
23
+ */
24
+ export default function buildFragmentResolver<T>(collectorOptions: DocumentImportResolverOptions, presetOptions: Types.PresetFnArgs<T>, schemaObject: GraphQLSchema, dedupeFragments?: boolean): (generatedFilePath: string, documentFileContent: DocumentNode) => {
25
+ externalFragments: LoadedFragment<{
26
+ level: number;
27
+ }>[];
28
+ fragmentImports: ImportDeclaration<FragmentImport>[];
29
+ };
@@ -0,0 +1,131 @@
1
+ import { Types } from '@graphql-codegen/plugin-helpers';
2
+ export type PerOperationFileConfig = {
3
+ /**
4
+ * @description Required, should point to the base schema types file.
5
+ * The key of the output is used a the base path for this file.
6
+ *
7
+ * If you wish to use an NPM package or a local workspace package, make sure to prefix the package name with `~`.
8
+ *
9
+ * @exampleMarkdown
10
+ * ```ts filename="codegen.ts"
11
+ * import type { CodegenConfig } from '@graphql-codegen/cli';
12
+ *
13
+ * const config: CodegenConfig = {
14
+ * // ...
15
+ * generates: {
16
+ * 'path/to/file.ts': {
17
+ * preset: 'per-operation-file',
18
+ * plugins: ['typescript-operations'],
19
+ * presetConfig: {
20
+ * baseTypesPath: 'types.ts'
21
+ * },
22
+ * },
23
+ * },
24
+ * };
25
+ * export default config;
26
+ * ```
27
+ */
28
+ baseTypesPath: string;
29
+ /**
30
+ * @description Optional, sets the extension for the generated files.
31
+ * @default .ts
32
+ *
33
+ * @exampleMarkdown
34
+ * ```ts filename="codegen.ts"
35
+ * import type { CodegenConfig } from '@graphql-codegen/cli';
36
+ *
37
+ * const config: CodegenConfig = {
38
+ * // ...
39
+ * generates: {
40
+ * 'path/to/file.ts': {
41
+ * preset: 'per-operation-file',
42
+ * plugins: ['typescript-operations'],
43
+ * presetConfig: {
44
+ * baseTypesPath: 'types.ts',
45
+ * extension: '.generated.ts',
46
+ * },
47
+ * },
48
+ * },
49
+ * };
50
+ * export default config;
51
+ * ```
52
+ */
53
+ extension?: string;
54
+ /**
55
+ * @description Optional, override the `cwd` of the execution.
56
+ * @default process.cwd()
57
+ *
58
+ * @exampleMarkdown
59
+ * ```ts filename="codegen.ts"
60
+ * import type { CodegenConfig } from '@graphql-codegen/cli';
61
+ *
62
+ * const config: CodegenConfig = {
63
+ * // ...
64
+ * generates: {
65
+ * 'path/to/file.ts': {
66
+ * preset: 'per-operation-file',
67
+ * plugins: ['typescript-operations'],
68
+ * presetConfig: {
69
+ * baseTypesPath: 'types.ts',
70
+ * cwd: '/some/path'
71
+ * },
72
+ * },
73
+ * },
74
+ * };
75
+ * export default config;
76
+ * ```
77
+ */
78
+ cwd?: string;
79
+ /**
80
+ * @description Optional, defines a folder where the generated files will be created.
81
+ * @default '__generated__'
82
+ *
83
+ * @exampleMarkdown
84
+ * ```ts filename="codegen.ts"
85
+ * import type { CodegenConfig } from '@graphql-codegen/cli';
86
+ *
87
+ * const config: CodegenConfig = {
88
+ * // ...
89
+ * generates: {
90
+ * 'path/to/file.ts': {
91
+ * preset: 'per-operation-file',
92
+ * plugins: ['typescript-operations'],
93
+ * presetConfig: {
94
+ * baseTypesPath: 'types.ts',
95
+ * folder: '__generated__'
96
+ * },
97
+ * },
98
+ * },
99
+ * };
100
+ * export default config;
101
+ * ```
102
+ */
103
+ folder?: string;
104
+ /**
105
+ * @description Optional, override the name of the import namespace used to import from the `baseTypesPath` file.
106
+ * @default Types
107
+ *
108
+ * @exampleMarkdown
109
+ * ```ts filename="codegen.ts"
110
+ * import type { CodegenConfig } from '@graphql-codegen/cli';
111
+ *
112
+ * const config: CodegenConfig = {
113
+ * // ...
114
+ * generates: {
115
+ * 'path/to/file.ts': {
116
+ * preset: 'per-operation-file',
117
+ * plugins: ['typescript-operations'],
118
+ * presetConfig: {
119
+ * baseTypesPath: 'types.ts',
120
+ * importTypesNamespace: 'SchemaTypes'
121
+ * },
122
+ * },
123
+ * },
124
+ * };
125
+ * export default config;
126
+ * ```
127
+ */
128
+ importTypesNamespace?: string;
129
+ };
130
+ export declare const preset: Types.OutputPreset<PerOperationFileConfig>;
131
+ export default preset;