UNPKG

10.2 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.sortPrependValues = exports.codegen = void 0;
4const plugin_helpers_1 = require("@graphql-codegen/plugin-helpers");
5const schema_1 = require("@graphql-tools/schema");
6const utils_1 = require("@graphql-tools/utils");
7const graphql_1 = require("graphql");
8const execute_plugin_js_1 = require("./execute-plugin.js");
9const utils_js_1 = require("./utils.js");
10const transform_document_js_1 = require("./transform-document.js");
11async function codegen(options) {
12 var _a;
13 const documents = options.documents || [];
14 const profiler = (_a = options.profiler) !== null && _a !== void 0 ? _a : (0, plugin_helpers_1.createNoopProfiler)();
15 const skipDocumentsValidation = (0, utils_js_1.getSkipDocumentsValidationOption)(options);
16 if (documents.length > 0 && (0, utils_js_1.shouldValidateDuplicateDocuments)(skipDocumentsValidation)) {
17 await profiler.run(async () => validateDuplicateDocuments(documents), 'validateDuplicateDocuments');
18 }
19 const pluginPackages = Object.keys(options.pluginMap).map(key => options.pluginMap[key]);
20 // merged schema with parts added by plugins
21 const additionalTypeDefs = [];
22 for (const plugin of pluginPackages) {
23 const addToSchema = typeof plugin.addToSchema === 'function' ? plugin.addToSchema(options.config) : plugin.addToSchema;
24 if (addToSchema) {
25 additionalTypeDefs.push(addToSchema);
26 }
27 }
28 const federationInConfig = (0, utils_js_1.pickFlag)('federation', options.config);
29 const isFederation = (0, utils_js_1.prioritize)(federationInConfig, false);
30 if (isFederation && !(0, utils_js_1.hasFederationSpec)(options.schemaAst || options.schema)) {
31 additionalTypeDefs.push(plugin_helpers_1.federationSpec);
32 }
33 // Use mergeSchemas, only if there is no GraphQLSchema provided or the schema should be extended
34 const mergeNeeded = !options.schemaAst || additionalTypeDefs.length > 0;
35 const schemaInstance = await profiler.run(async () => {
36 return mergeNeeded
37 ? (0, schema_1.mergeSchemas)({
38 // If GraphQLSchema provided, use it
39 schemas: options.schemaAst ? [options.schemaAst] : [],
40 // If GraphQLSchema isn't provided but DocumentNode is, use it to get the final GraphQLSchema
41 typeDefs: options.schemaAst ? additionalTypeDefs : [options.schema, ...additionalTypeDefs],
42 convertExtensions: true,
43 assumeValid: true,
44 assumeValidSDL: true,
45 ...options.config,
46 })
47 : options.schemaAst;
48 }, 'Create schema instance');
49 const schemaDocumentNode = mergeNeeded || !options.schema ? (0, plugin_helpers_1.getCachedDocumentNodeFromSchema)(schemaInstance) : options.schema;
50 const documentTransforms = Array.isArray(options.documentTransforms) ? options.documentTransforms : [];
51 const transformedDocuments = await (0, transform_document_js_1.transformDocuments)({
52 ...options,
53 documentTransforms,
54 schema: schemaDocumentNode,
55 schemaAst: schemaInstance,
56 profiler,
57 });
58 if (schemaInstance &&
59 transformedDocuments.length > 0 &&
60 (0, utils_js_1.shouldValidateDocumentsAgainstSchema)(skipDocumentsValidation)) {
61 const ignored = ['NoUnusedFragments', 'NoUnusedVariables', 'KnownDirectives'];
62 if (typeof skipDocumentsValidation === 'object' && skipDocumentsValidation.ignoreRules) {
63 ignored.push(...(0, utils_1.asArray)(skipDocumentsValidation.ignoreRules));
64 }
65 const extraFragments = (0, utils_js_1.pickFlag)('externalFragments', options.config) || [];
66 const errors = await profiler.run(() => {
67 const fragments = extraFragments.map(f => ({
68 location: f.importFrom,
69 document: { kind: graphql_1.Kind.DOCUMENT, definitions: [f.node] },
70 }));
71 const rules = graphql_1.specifiedRules.filter(rule => !ignored.some(ignoredRule => rule.name.startsWith(ignoredRule)));
72 const schemaHash = (0, utils_js_1.extractHashFromSchema)(schemaInstance);
73 if (!schemaHash || !options.cache || transformedDocuments.some(d => typeof d.hash !== 'string')) {
74 return Promise.resolve((0, utils_1.validateGraphQlDocuments)(schemaInstance, [...transformedDocuments.flatMap(d => d.document), ...fragments.flatMap(f => f.document)], rules));
75 }
76 const cacheKey = [schemaHash]
77 .concat(transformedDocuments.map(doc => doc.hash))
78 .concat(JSON.stringify(fragments))
79 .join(',');
80 return options.cache('documents-validation', cacheKey, () => Promise.resolve((0, utils_1.validateGraphQlDocuments)(schemaInstance, [...transformedDocuments.flatMap(d => d.document), ...fragments.flatMap(f => f.document)], rules)));
81 }, 'Validate documents against schema');
82 if (errors.length > 0) {
83 throw new Error(`GraphQL Document Validation failed with ${errors.length} errors;
84 ${errors.map((error, index) => `Error ${index}: ${error.stack}`).join('\n\n')}`);
85 }
86 }
87 const prepend = new Set();
88 const append = new Set();
89 const output = await Promise.all(options.plugins.map(async (plugin) => {
90 const name = Object.keys(plugin)[0];
91 const pluginPackage = options.pluginMap[name];
92 const pluginConfig = plugin[name] || {};
93 const execConfig = typeof pluginConfig === 'object' ? { ...options.config, ...pluginConfig } : pluginConfig;
94 const result = await profiler.run(() => (0, execute_plugin_js_1.executePlugin)({
95 name,
96 config: execConfig,
97 parentConfig: options.config,
98 schema: schemaDocumentNode,
99 schemaAst: schemaInstance,
100 documents: transformedDocuments,
101 outputFilename: options.filename,
102 allPlugins: options.plugins,
103 skipDocumentsValidation: options.skipDocumentsValidation,
104 pluginContext: options.pluginContext,
105 profiler,
106 }, pluginPackage), `Plugin ${name}`);
107 if (typeof result === 'string') {
108 return result || '';
109 }
110 if ((0, plugin_helpers_1.isComplexPluginOutput)(result)) {
111 if (result.append && result.append.length > 0) {
112 for (const item of result.append) {
113 if (item) {
114 append.add(item);
115 }
116 }
117 }
118 if (result.prepend && result.prepend.length > 0) {
119 for (const item of result.prepend) {
120 if (item) {
121 prepend.add(item);
122 }
123 }
124 }
125 return result.content || '';
126 }
127 return '';
128 }));
129 return [...sortPrependValues(Array.from(prepend.values())), ...output, ...Array.from(append.values())]
130 .filter(Boolean)
131 .join('\n');
132}
133exports.codegen = codegen;
134function resolveCompareValue(a) {
135 if (a.startsWith('/*') || a.startsWith('//') || a.startsWith(' *') || a.startsWith(' */') || a.startsWith('*/')) {
136 return 0;
137 }
138 if (a.startsWith('package')) {
139 return 1;
140 }
141 if (a.startsWith('import')) {
142 return 2;
143 }
144 return 3;
145}
146function sortPrependValues(values) {
147 return values.sort((a, b) => {
148 const aV = resolveCompareValue(a);
149 const bV = resolveCompareValue(b);
150 if (aV < bV) {
151 return -1;
152 }
153 if (aV > bV) {
154 return 1;
155 }
156 return 0;
157 });
158}
159exports.sortPrependValues = sortPrependValues;
160function validateDuplicateDocuments(files) {
161 // duplicated names
162 const definitionMap = {};
163 function addDefinition(file, node, deduplicatedDefinitions) {
164 var _a, _b, _c;
165 if (typeof node.name !== 'undefined') {
166 definitionMap[_a = node.kind] || (definitionMap[_a] = {});
167 (_b = definitionMap[node.kind])[_c = node.name.value] || (_b[_c] = {
168 paths: new Set(),
169 contents: new Set(),
170 });
171 const definitionKindMap = definitionMap[node.kind];
172 const length = definitionKindMap[node.name.value].contents.size;
173 definitionKindMap[node.name.value].paths.add(file.location);
174 definitionKindMap[node.name.value].contents.add((0, graphql_1.print)(node));
175 if (length === definitionKindMap[node.name.value].contents.size) {
176 return null;
177 }
178 }
179 return deduplicatedDefinitions.add(node);
180 }
181 files.forEach(file => {
182 const deduplicatedDefinitions = new Set();
183 (0, graphql_1.visit)(file.document, {
184 OperationDefinition(node) {
185 addDefinition(file, node, deduplicatedDefinitions);
186 },
187 FragmentDefinition(node) {
188 addDefinition(file, node, deduplicatedDefinitions);
189 },
190 });
191 file.document.definitions = Array.from(deduplicatedDefinitions);
192 });
193 const kinds = Object.keys(definitionMap);
194 kinds.forEach(kind => {
195 const definitionKindMap = definitionMap[kind];
196 const names = Object.keys(definitionKindMap);
197 if (names.length) {
198 const duplicated = names.filter(name => definitionKindMap[name].contents.size > 1);
199 if (!duplicated.length) {
200 return;
201 }
202 const list = duplicated
203 .map(name => `
204 * ${name} found in:
205 ${[...definitionKindMap[name].paths]
206 .map(filepath => {
207 return `
208 - ${filepath}
209 `.trimRight();
210 })
211 .join('')}
212 `.trimRight())
213 .join('');
214 const definitionKindName = kind.replace('Definition', '').toLowerCase();
215 throw new Error(`Not all ${definitionKindName}s have an unique name: ${duplicated.join(', ')}: \n
216 ${list}
217 `);
218 }
219 });
220}