@nmarks/graphql-codegen-per-operation-file-preset 1.0.10 → 1.0.11

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.
package/cjs/index.js CHANGED
@@ -8,6 +8,7 @@ const add_1 = tslib_1.__importDefault(require("@graphql-codegen/add"));
8
8
  const visitor_plugin_common_1 = require("@graphql-codegen/visitor-plugin-common");
9
9
  const resolve_document_imports_js_1 = require("./resolve-document-imports.js");
10
10
  const utils_js_1 = require("./utils.js");
11
+ const persisted_documents_js_1 = require("./persisted-documents.js");
11
12
  /**
12
13
  * Extract operation and fragment names from a document
13
14
  */
@@ -530,6 +531,42 @@ exports.preset = {
530
531
  });
531
532
  }
532
533
  }
534
+ /**
535
+ * PERSISTED DOCUMENTS GENERATION
536
+ *
537
+ * If persistedDocuments is configured, generate a JSON file mapping
538
+ * operation hashes to their full query bodies (with __typename added).
539
+ * This happens in a single pass - no second document scan required.
540
+ */
541
+ const { persistedDocuments: persistedDocumentsConfig } = options.presetConfig;
542
+ if (persistedDocumentsConfig === null || persistedDocumentsConfig === void 0 ? void 0 : persistedDocumentsConfig.output) {
543
+ // Collect all source documents for persisted document generation
544
+ const allDocuments = options.documents;
545
+ // Generate the persisted documents map
546
+ const persistedDocsMap = (0, persisted_documents_js_1.generatePersistedDocuments)(allDocuments);
547
+ // Add artifact for the persisted documents JSON file
548
+ artifacts.push({
549
+ ...options,
550
+ filename: (0, path_1.join)(options.baseOutputDir, persistedDocumentsConfig.output),
551
+ plugins: [
552
+ {
553
+ [`persisted-documents`]: {},
554
+ },
555
+ ],
556
+ pluginMap: {
557
+ [`persisted-documents`]: {
558
+ plugin: () => ({
559
+ content: JSON.stringify(persistedDocsMap, null, 2),
560
+ }),
561
+ },
562
+ },
563
+ schema: options.schema,
564
+ schemaAst: schemaObject,
565
+ config: {},
566
+ documents: allDocuments,
567
+ skipDocumentsValidation: true,
568
+ });
569
+ }
533
570
  return artifacts;
534
571
  },
535
572
  };
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addTypenameToDocument = addTypenameToDocument;
4
+ exports.collectFragmentReferences = collectFragmentReferences;
5
+ exports.collectAllFragmentDeps = collectAllFragmentDeps;
6
+ exports.sortTopLevelDefinitions = sortTopLevelDefinitions;
7
+ exports.generatePersistedDocuments = generatePersistedDocuments;
8
+ const crypto_1 = require("crypto");
9
+ const graphql_1 = require("graphql");
10
+ /**
11
+ * Adds __typename field to all selection sets matching Apollo Client's InMemoryCache behavior.
12
+ *
13
+ * Rules:
14
+ * - Add __typename at the END of selection sets
15
+ * - Skip root selection set of operations (query/mutation/subscription)
16
+ * - DO add __typename to fragment root selection sets
17
+ */
18
+ function addTypenameToDocument(doc) {
19
+ return (0, graphql_1.visit)(doc, {
20
+ SelectionSet(node, _key, parent) {
21
+ // Skip root selection set of operations (parent is OperationDefinition)
22
+ // But DON'T skip root selection set of fragments (they should get __typename)
23
+ if (parent && parent.kind === graphql_1.Kind.OPERATION_DEFINITION) {
24
+ return node;
25
+ }
26
+ // Check if __typename already exists
27
+ const hasTypename = node.selections.some(selection => selection.kind === graphql_1.Kind.FIELD && selection.name.value === '__typename');
28
+ if (hasTypename) {
29
+ return node;
30
+ }
31
+ // Add __typename at the END (matching Apollo Client behavior)
32
+ return {
33
+ ...node,
34
+ selections: [
35
+ ...node.selections,
36
+ {
37
+ kind: graphql_1.Kind.FIELD,
38
+ name: { kind: graphql_1.Kind.NAME, value: '__typename' },
39
+ },
40
+ ],
41
+ };
42
+ },
43
+ });
44
+ }
45
+ /**
46
+ * Collects all fragment names referenced in a document via FragmentSpread nodes
47
+ */
48
+ function collectFragmentReferences(doc) {
49
+ const refs = new Set();
50
+ (0, graphql_1.visit)(doc, {
51
+ FragmentSpread(node) {
52
+ refs.add(node.name.value);
53
+ },
54
+ });
55
+ return refs;
56
+ }
57
+ /**
58
+ * Recursively collects all fragment dependencies (including nested)
59
+ */
60
+ function collectAllFragmentDeps(fragmentName, fragmentMap, collected = new Set()) {
61
+ if (collected.has(fragmentName))
62
+ return collected;
63
+ collected.add(fragmentName);
64
+ const fragment = fragmentMap.get(fragmentName);
65
+ if (fragment) {
66
+ const refs = collectFragmentReferences(fragment);
67
+ for (const ref of refs) {
68
+ collectAllFragmentDeps(ref, fragmentMap, collected);
69
+ }
70
+ }
71
+ return collected;
72
+ }
73
+ /**
74
+ * Sort the definitions in a document so that operations come before fragments,
75
+ * and so that each kind of definition is sorted by name.
76
+ *
77
+ * This is a direct implementation of the sorting logic from @apollo/persisted-query-lists
78
+ * to avoid an external dependency.
79
+ */
80
+ function sortTopLevelDefinitions(query) {
81
+ const definitions = [...query.definitions];
82
+ definitions.sort((a, b) => {
83
+ var _a, _b, _c, _d;
84
+ // This is a reverse sort by kind, so that OperationDefinition precedes FragmentDefinition.
85
+ if (a.kind > b.kind) {
86
+ return -1;
87
+ }
88
+ if (a.kind < b.kind) {
89
+ return 1;
90
+ }
91
+ // Extract the name from each definition
92
+ const aName = a.kind === graphql_1.Kind.OPERATION_DEFINITION || a.kind === graphql_1.Kind.FRAGMENT_DEFINITION
93
+ ? ((_b = (_a = a.name) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '')
94
+ : '';
95
+ const bName = b.kind === graphql_1.Kind.OPERATION_DEFINITION || b.kind === graphql_1.Kind.FRAGMENT_DEFINITION
96
+ ? ((_d = (_c = b.name) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : '')
97
+ : '';
98
+ // Sort by name ascending.
99
+ if (aName < bName) {
100
+ return -1;
101
+ }
102
+ if (aName > bName) {
103
+ return 1;
104
+ }
105
+ return 0;
106
+ });
107
+ return {
108
+ ...query,
109
+ definitions,
110
+ };
111
+ }
112
+ /**
113
+ * Generates persisted documents map from all documents.
114
+ *
115
+ * Returns a map of hash -> query body for all operations (not standalone fragments).
116
+ * Each operation includes its fragment dependencies inline.
117
+ */
118
+ function generatePersistedDocuments(documents) {
119
+ // Build fragment registry from all documents
120
+ const fragmentMap = new Map();
121
+ for (const doc of documents) {
122
+ if (!doc.document)
123
+ continue;
124
+ for (const def of doc.document.definitions) {
125
+ if (def.kind === graphql_1.Kind.FRAGMENT_DEFINITION) {
126
+ fragmentMap.set(def.name.value, def);
127
+ }
128
+ }
129
+ }
130
+ const result = {};
131
+ for (const doc of documents) {
132
+ if (!doc.document)
133
+ continue;
134
+ // Find operations in this document
135
+ const operations = doc.document.definitions.filter((def) => def.kind === graphql_1.Kind.OPERATION_DEFINITION);
136
+ // Skip documents with no operations (fragment-only files)
137
+ if (operations.length === 0)
138
+ continue;
139
+ for (const operation of operations) {
140
+ // Create a document with just this operation
141
+ let operationDoc = {
142
+ kind: graphql_1.Kind.DOCUMENT,
143
+ definitions: [operation],
144
+ };
145
+ // Collect all required fragments (recursively)
146
+ const directRefs = collectFragmentReferences(operationDoc);
147
+ const allFragments = new Set();
148
+ for (const ref of directRefs) {
149
+ collectAllFragmentDeps(ref, fragmentMap, allFragments);
150
+ }
151
+ // Add fragment definitions to the document
152
+ const fragmentDefs = [];
153
+ for (const fragName of allFragments) {
154
+ const frag = fragmentMap.get(fragName);
155
+ if (frag)
156
+ fragmentDefs.push(frag);
157
+ }
158
+ if (fragmentDefs.length > 0) {
159
+ operationDoc = {
160
+ ...operationDoc,
161
+ definitions: [...operationDoc.definitions, ...fragmentDefs],
162
+ };
163
+ }
164
+ // Add __typename to all selection sets (matching Apollo Client behavior)
165
+ const docWithTypename = addTypenameToDocument(operationDoc);
166
+ // Sort definitions (operation first, then fragments alphabetically)
167
+ const sortedDoc = sortTopLevelDefinitions(docWithTypename);
168
+ // Print the document
169
+ const body = (0, graphql_1.print)(sortedDoc);
170
+ // Skip empty documents
171
+ if (!body || body.trim() === '')
172
+ continue;
173
+ // Hash is just for the JSON key - gets re-computed by generate-persisted-query-manifest
174
+ const hash = (0, crypto_1.createHash)('sha256').update(body).digest('hex');
175
+ result[hash] = body;
176
+ }
177
+ }
178
+ return result;
179
+ }
package/esm/index.js CHANGED
@@ -4,6 +4,7 @@ import addPlugin from '@graphql-codegen/add';
4
4
  import { generateImportStatement, getConfigValue, resolveImportSource, } from '@graphql-codegen/visitor-plugin-common';
5
5
  import { resolveDocumentImports } from './resolve-document-imports.js';
6
6
  import { generateOperationFilePath } from './utils.js';
7
+ import { generatePersistedDocuments } from './persisted-documents.js';
7
8
  /**
8
9
  * Extract operation and fragment names from a document
9
10
  */
@@ -526,6 +527,42 @@ export const preset = {
526
527
  });
527
528
  }
528
529
  }
530
+ /**
531
+ * PERSISTED DOCUMENTS GENERATION
532
+ *
533
+ * If persistedDocuments is configured, generate a JSON file mapping
534
+ * operation hashes to their full query bodies (with __typename added).
535
+ * This happens in a single pass - no second document scan required.
536
+ */
537
+ const { persistedDocuments: persistedDocumentsConfig } = options.presetConfig;
538
+ if (persistedDocumentsConfig === null || persistedDocumentsConfig === void 0 ? void 0 : persistedDocumentsConfig.output) {
539
+ // Collect all source documents for persisted document generation
540
+ const allDocuments = options.documents;
541
+ // Generate the persisted documents map
542
+ const persistedDocsMap = generatePersistedDocuments(allDocuments);
543
+ // Add artifact for the persisted documents JSON file
544
+ artifacts.push({
545
+ ...options,
546
+ filename: join(options.baseOutputDir, persistedDocumentsConfig.output),
547
+ plugins: [
548
+ {
549
+ [`persisted-documents`]: {},
550
+ },
551
+ ],
552
+ pluginMap: {
553
+ [`persisted-documents`]: {
554
+ plugin: () => ({
555
+ content: JSON.stringify(persistedDocsMap, null, 2),
556
+ }),
557
+ },
558
+ },
559
+ schema: options.schema,
560
+ schemaAst: schemaObject,
561
+ config: {},
562
+ documents: allDocuments,
563
+ skipDocumentsValidation: true,
564
+ });
565
+ }
529
566
  return artifacts;
530
567
  },
531
568
  };
@@ -0,0 +1,172 @@
1
+ import { createHash } from 'crypto';
2
+ import { Kind, print, visit, } from 'graphql';
3
+ /**
4
+ * Adds __typename field to all selection sets matching Apollo Client's InMemoryCache behavior.
5
+ *
6
+ * Rules:
7
+ * - Add __typename at the END of selection sets
8
+ * - Skip root selection set of operations (query/mutation/subscription)
9
+ * - DO add __typename to fragment root selection sets
10
+ */
11
+ export function addTypenameToDocument(doc) {
12
+ return visit(doc, {
13
+ SelectionSet(node, _key, parent) {
14
+ // Skip root selection set of operations (parent is OperationDefinition)
15
+ // But DON'T skip root selection set of fragments (they should get __typename)
16
+ if (parent && parent.kind === Kind.OPERATION_DEFINITION) {
17
+ return node;
18
+ }
19
+ // Check if __typename already exists
20
+ const hasTypename = node.selections.some(selection => selection.kind === Kind.FIELD && selection.name.value === '__typename');
21
+ if (hasTypename) {
22
+ return node;
23
+ }
24
+ // Add __typename at the END (matching Apollo Client behavior)
25
+ return {
26
+ ...node,
27
+ selections: [
28
+ ...node.selections,
29
+ {
30
+ kind: Kind.FIELD,
31
+ name: { kind: Kind.NAME, value: '__typename' },
32
+ },
33
+ ],
34
+ };
35
+ },
36
+ });
37
+ }
38
+ /**
39
+ * Collects all fragment names referenced in a document via FragmentSpread nodes
40
+ */
41
+ export function collectFragmentReferences(doc) {
42
+ const refs = new Set();
43
+ visit(doc, {
44
+ FragmentSpread(node) {
45
+ refs.add(node.name.value);
46
+ },
47
+ });
48
+ return refs;
49
+ }
50
+ /**
51
+ * Recursively collects all fragment dependencies (including nested)
52
+ */
53
+ export function collectAllFragmentDeps(fragmentName, fragmentMap, collected = new Set()) {
54
+ if (collected.has(fragmentName))
55
+ return collected;
56
+ collected.add(fragmentName);
57
+ const fragment = fragmentMap.get(fragmentName);
58
+ if (fragment) {
59
+ const refs = collectFragmentReferences(fragment);
60
+ for (const ref of refs) {
61
+ collectAllFragmentDeps(ref, fragmentMap, collected);
62
+ }
63
+ }
64
+ return collected;
65
+ }
66
+ /**
67
+ * Sort the definitions in a document so that operations come before fragments,
68
+ * and so that each kind of definition is sorted by name.
69
+ *
70
+ * This is a direct implementation of the sorting logic from @apollo/persisted-query-lists
71
+ * to avoid an external dependency.
72
+ */
73
+ export function sortTopLevelDefinitions(query) {
74
+ const definitions = [...query.definitions];
75
+ definitions.sort((a, b) => {
76
+ var _a, _b, _c, _d;
77
+ // This is a reverse sort by kind, so that OperationDefinition precedes FragmentDefinition.
78
+ if (a.kind > b.kind) {
79
+ return -1;
80
+ }
81
+ if (a.kind < b.kind) {
82
+ return 1;
83
+ }
84
+ // Extract the name from each definition
85
+ const aName = a.kind === Kind.OPERATION_DEFINITION || a.kind === Kind.FRAGMENT_DEFINITION
86
+ ? ((_b = (_a = a.name) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '')
87
+ : '';
88
+ const bName = b.kind === Kind.OPERATION_DEFINITION || b.kind === Kind.FRAGMENT_DEFINITION
89
+ ? ((_d = (_c = b.name) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : '')
90
+ : '';
91
+ // Sort by name ascending.
92
+ if (aName < bName) {
93
+ return -1;
94
+ }
95
+ if (aName > bName) {
96
+ return 1;
97
+ }
98
+ return 0;
99
+ });
100
+ return {
101
+ ...query,
102
+ definitions,
103
+ };
104
+ }
105
+ /**
106
+ * Generates persisted documents map from all documents.
107
+ *
108
+ * Returns a map of hash -> query body for all operations (not standalone fragments).
109
+ * Each operation includes its fragment dependencies inline.
110
+ */
111
+ export function generatePersistedDocuments(documents) {
112
+ // Build fragment registry from all documents
113
+ const fragmentMap = new Map();
114
+ for (const doc of documents) {
115
+ if (!doc.document)
116
+ continue;
117
+ for (const def of doc.document.definitions) {
118
+ if (def.kind === Kind.FRAGMENT_DEFINITION) {
119
+ fragmentMap.set(def.name.value, def);
120
+ }
121
+ }
122
+ }
123
+ const result = {};
124
+ for (const doc of documents) {
125
+ if (!doc.document)
126
+ continue;
127
+ // Find operations in this document
128
+ const operations = doc.document.definitions.filter((def) => def.kind === Kind.OPERATION_DEFINITION);
129
+ // Skip documents with no operations (fragment-only files)
130
+ if (operations.length === 0)
131
+ continue;
132
+ for (const operation of operations) {
133
+ // Create a document with just this operation
134
+ let operationDoc = {
135
+ kind: Kind.DOCUMENT,
136
+ definitions: [operation],
137
+ };
138
+ // Collect all required fragments (recursively)
139
+ const directRefs = collectFragmentReferences(operationDoc);
140
+ const allFragments = new Set();
141
+ for (const ref of directRefs) {
142
+ collectAllFragmentDeps(ref, fragmentMap, allFragments);
143
+ }
144
+ // Add fragment definitions to the document
145
+ const fragmentDefs = [];
146
+ for (const fragName of allFragments) {
147
+ const frag = fragmentMap.get(fragName);
148
+ if (frag)
149
+ fragmentDefs.push(frag);
150
+ }
151
+ if (fragmentDefs.length > 0) {
152
+ operationDoc = {
153
+ ...operationDoc,
154
+ definitions: [...operationDoc.definitions, ...fragmentDefs],
155
+ };
156
+ }
157
+ // Add __typename to all selection sets (matching Apollo Client behavior)
158
+ const docWithTypename = addTypenameToDocument(operationDoc);
159
+ // Sort definitions (operation first, then fragments alphabetically)
160
+ const sortedDoc = sortTopLevelDefinitions(docWithTypename);
161
+ // Print the document
162
+ const body = print(sortedDoc);
163
+ // Skip empty documents
164
+ if (!body || body.trim() === '')
165
+ continue;
166
+ // Hash is just for the JSON key - gets re-computed by generate-persisted-query-manifest
167
+ const hash = createHash('sha256').update(body).digest('hex');
168
+ result[hash] = body;
169
+ }
170
+ }
171
+ return result;
172
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nmarks/graphql-codegen-per-operation-file-preset",
3
- "version": "1.0.10",
3
+ "version": "1.0.11",
4
4
  "description": "GraphQL Code Generator preset for generating one file per operation/fragment",
5
5
  "peerDependencies": {
6
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"
@@ -1,4 +1,5 @@
1
1
  import { Types } from '@graphql-codegen/plugin-helpers';
2
+ import { PersistedDocumentsConfig } from './persisted-documents.cjs';
2
3
  export type PerOperationFileConfig = {
3
4
  /**
4
5
  * @description Required, should point to the base schema types file.
@@ -126,6 +127,34 @@ export type PerOperationFileConfig = {
126
127
  * ```
127
128
  */
128
129
  importTypesNamespace?: string;
130
+ /**
131
+ * @description Optional, enables generation of a persisted-documents.json file
132
+ * that maps operation hashes to their full query bodies (with __typename added).
133
+ * Compatible with Apollo Client's persisted queries.
134
+ *
135
+ * @exampleMarkdown
136
+ * ```ts filename="codegen.ts"
137
+ * import type { CodegenConfig } from '@graphql-codegen/cli';
138
+ *
139
+ * const config: CodegenConfig = {
140
+ * // ...
141
+ * generates: {
142
+ * 'path/to/file.ts': {
143
+ * preset: 'per-operation-file',
144
+ * plugins: ['typescript-operations'],
145
+ * presetConfig: {
146
+ * baseTypesPath: 'types.ts',
147
+ * persistedDocuments: {
148
+ * output: 'build/persisted-documents.json'
149
+ * }
150
+ * },
151
+ * },
152
+ * },
153
+ * };
154
+ * export default config;
155
+ * ```
156
+ */
157
+ persistedDocuments?: PersistedDocumentsConfig;
129
158
  };
130
159
  /**
131
160
  * PER-OPERATION-FILE PRESET
@@ -1,4 +1,5 @@
1
1
  import { Types } from '@graphql-codegen/plugin-helpers';
2
+ import { PersistedDocumentsConfig } from './persisted-documents.js';
2
3
  export type PerOperationFileConfig = {
3
4
  /**
4
5
  * @description Required, should point to the base schema types file.
@@ -126,6 +127,34 @@ export type PerOperationFileConfig = {
126
127
  * ```
127
128
  */
128
129
  importTypesNamespace?: string;
130
+ /**
131
+ * @description Optional, enables generation of a persisted-documents.json file
132
+ * that maps operation hashes to their full query bodies (with __typename added).
133
+ * Compatible with Apollo Client's persisted queries.
134
+ *
135
+ * @exampleMarkdown
136
+ * ```ts filename="codegen.ts"
137
+ * import type { CodegenConfig } from '@graphql-codegen/cli';
138
+ *
139
+ * const config: CodegenConfig = {
140
+ * // ...
141
+ * generates: {
142
+ * 'path/to/file.ts': {
143
+ * preset: 'per-operation-file',
144
+ * plugins: ['typescript-operations'],
145
+ * presetConfig: {
146
+ * baseTypesPath: 'types.ts',
147
+ * persistedDocuments: {
148
+ * output: 'build/persisted-documents.json'
149
+ * }
150
+ * },
151
+ * },
152
+ * },
153
+ * };
154
+ * export default config;
155
+ * ```
156
+ */
157
+ persistedDocuments?: PersistedDocumentsConfig;
129
158
  };
130
159
  /**
131
160
  * PER-OPERATION-FILE PRESET
@@ -0,0 +1,44 @@
1
+ import { DocumentNode, FragmentDefinitionNode } from 'graphql';
2
+ import type { Source } from '@graphql-tools/utils';
3
+ /**
4
+ * Configuration for persisted documents output
5
+ */
6
+ export interface PersistedDocumentsConfig {
7
+ /**
8
+ * Output path for the persisted-documents.json file
9
+ * (relative to the baseOutputDir or absolute)
10
+ */
11
+ output: string;
12
+ }
13
+ /**
14
+ * Adds __typename field to all selection sets matching Apollo Client's InMemoryCache behavior.
15
+ *
16
+ * Rules:
17
+ * - Add __typename at the END of selection sets
18
+ * - Skip root selection set of operations (query/mutation/subscription)
19
+ * - DO add __typename to fragment root selection sets
20
+ */
21
+ export declare function addTypenameToDocument(doc: DocumentNode): DocumentNode;
22
+ /**
23
+ * Collects all fragment names referenced in a document via FragmentSpread nodes
24
+ */
25
+ export declare function collectFragmentReferences(doc: DocumentNode | FragmentDefinitionNode): Set<string>;
26
+ /**
27
+ * Recursively collects all fragment dependencies (including nested)
28
+ */
29
+ export declare function collectAllFragmentDeps(fragmentName: string, fragmentMap: Map<string, FragmentDefinitionNode>, collected?: Set<string>): Set<string>;
30
+ /**
31
+ * Sort the definitions in a document so that operations come before fragments,
32
+ * and so that each kind of definition is sorted by name.
33
+ *
34
+ * This is a direct implementation of the sorting logic from @apollo/persisted-query-lists
35
+ * to avoid an external dependency.
36
+ */
37
+ export declare function sortTopLevelDefinitions(query: DocumentNode): DocumentNode;
38
+ /**
39
+ * Generates persisted documents map from all documents.
40
+ *
41
+ * Returns a map of hash -> query body for all operations (not standalone fragments).
42
+ * Each operation includes its fragment dependencies inline.
43
+ */
44
+ export declare function generatePersistedDocuments(documents: Source[]): Record<string, string>;
@@ -0,0 +1,44 @@
1
+ import { DocumentNode, FragmentDefinitionNode } from 'graphql';
2
+ import type { Source } from '@graphql-tools/utils';
3
+ /**
4
+ * Configuration for persisted documents output
5
+ */
6
+ export interface PersistedDocumentsConfig {
7
+ /**
8
+ * Output path for the persisted-documents.json file
9
+ * (relative to the baseOutputDir or absolute)
10
+ */
11
+ output: string;
12
+ }
13
+ /**
14
+ * Adds __typename field to all selection sets matching Apollo Client's InMemoryCache behavior.
15
+ *
16
+ * Rules:
17
+ * - Add __typename at the END of selection sets
18
+ * - Skip root selection set of operations (query/mutation/subscription)
19
+ * - DO add __typename to fragment root selection sets
20
+ */
21
+ export declare function addTypenameToDocument(doc: DocumentNode): DocumentNode;
22
+ /**
23
+ * Collects all fragment names referenced in a document via FragmentSpread nodes
24
+ */
25
+ export declare function collectFragmentReferences(doc: DocumentNode | FragmentDefinitionNode): Set<string>;
26
+ /**
27
+ * Recursively collects all fragment dependencies (including nested)
28
+ */
29
+ export declare function collectAllFragmentDeps(fragmentName: string, fragmentMap: Map<string, FragmentDefinitionNode>, collected?: Set<string>): Set<string>;
30
+ /**
31
+ * Sort the definitions in a document so that operations come before fragments,
32
+ * and so that each kind of definition is sorted by name.
33
+ *
34
+ * This is a direct implementation of the sorting logic from @apollo/persisted-query-lists
35
+ * to avoid an external dependency.
36
+ */
37
+ export declare function sortTopLevelDefinitions(query: DocumentNode): DocumentNode;
38
+ /**
39
+ * Generates persisted documents map from all documents.
40
+ *
41
+ * Returns a map of hash -> query body for all operations (not standalone fragments).
42
+ * Each operation includes its fragment dependencies inline.
43
+ */
44
+ export declare function generatePersistedDocuments(documents: Source[]): Record<string, string>;