UNPKG

13.8 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.buildModule = void 0;
4const graphql_1 = require("graphql");
5const change_case_all_1 = require("change-case-all");
6const utils_js_1 = require("./utils.js");
7const registryKeys = ['objects', 'inputs', 'interfaces', 'scalars', 'unions', 'enums'];
8const resolverKeys = ['scalars', 'objects', 'enums'];
9function buildModule(name, doc, { importNamespace, importPath, encapsulate, requireRootResolvers, shouldDeclare, rootTypes, schema, baseVisitor, useGraphQLModules, useTypeImports = false, }) {
10 const picks = (0, utils_js_1.createObject)(registryKeys, () => ({}));
11 const defined = (0, utils_js_1.createObject)(registryKeys, () => []);
12 const extended = (0, utils_js_1.createObject)(registryKeys, () => []);
13 // List of types used in objects, fields, arguments etc
14 const usedTypes = (0, utils_js_1.collectUsedTypes)(doc);
15 (0, graphql_1.visit)(doc, {
16 ObjectTypeDefinition(node) {
17 collectTypeDefinition(node);
18 },
19 ObjectTypeExtension(node) {
20 collectTypeExtension(node);
21 },
22 InputObjectTypeDefinition(node) {
23 collectTypeDefinition(node);
24 },
25 InputObjectTypeExtension(node) {
26 collectTypeExtension(node);
27 },
28 InterfaceTypeDefinition(node) {
29 collectTypeDefinition(node);
30 },
31 InterfaceTypeExtension(node) {
32 collectTypeExtension(node);
33 },
34 ScalarTypeDefinition(node) {
35 collectTypeDefinition(node);
36 },
37 UnionTypeDefinition(node) {
38 collectTypeDefinition(node);
39 },
40 UnionTypeExtension(node) {
41 collectTypeExtension(node);
42 },
43 EnumTypeDefinition(node) {
44 collectTypeDefinition(node);
45 },
46 EnumTypeExtension(node) {
47 collectTypeExtension(node);
48 },
49 });
50 // Defined and Extended types
51 const visited = (0, utils_js_1.createObject)(registryKeys, key => (0, utils_js_1.concatByKey)(defined, extended, key));
52 // Types that are not defined or extended in a module, they come from other modules
53 const external = (0, utils_js_1.createObject)(registryKeys, key => (0, utils_js_1.uniqueByKey)(extended, defined, key));
54 //
55 //
56 //
57 // Prints
58 //
59 //
60 //
61 // An actual output
62 const imports = [`import${useTypeImports ? ' type' : ''} * as ${importNamespace} from "${importPath}";`];
63 if (useGraphQLModules) {
64 imports.push(`import${useTypeImports ? ' type' : ''} * as gm from "graphql-modules";`);
65 }
66 let content = [
67 printDefinedFields(),
68 printDefinedEnumValues(),
69 printDefinedInputFields(),
70 printSchemaTypes(usedTypes),
71 printScalars(visited),
72 printResolveSignaturesPerType(visited),
73 printResolversType(visited),
74 useGraphQLModules ? printResolveMiddlewareMap() : undefined,
75 ]
76 .filter(Boolean)
77 .join('\n\n');
78 if (encapsulate === 'namespace') {
79 content =
80 `${shouldDeclare ? 'declare' : 'export'} namespace ${baseVisitor.convertName(name, {
81 suffix: 'Module',
82 useTypesPrefix: false,
83 useTypesSuffix: false,
84 })} {\n` +
85 (shouldDeclare ? `${(0, utils_js_1.indent)(2)(imports.join('\n'))}\n` : '') +
86 (0, utils_js_1.indent)(2)(content) +
87 '\n}';
88 }
89 return [...(!shouldDeclare ? imports : []), content].filter(Boolean).join('\n');
90 /**
91 * A dictionary of fields to pick from an object
92 */
93 function printDefinedFields() {
94 return (0, utils_js_1.buildBlock)({
95 name: `interface DefinedFields`,
96 lines: [...visited.objects, ...visited.interfaces].map(typeName => `${typeName}: ${printPicks(typeName, {
97 ...picks.objects,
98 ...picks.interfaces,
99 })};`),
100 });
101 }
102 /**
103 * A dictionary of values to pick from an enum
104 */
105 function printDefinedEnumValues() {
106 return (0, utils_js_1.buildBlock)({
107 name: `interface DefinedEnumValues`,
108 lines: visited.enums.map(typeName => `${typeName}: ${printPicks(typeName, picks.enums)};`),
109 });
110 }
111 function encapsulateTypeName(typeName) {
112 if (encapsulate === 'prefix') {
113 return `${(0, change_case_all_1.pascalCase)(name)}_${typeName}`;
114 }
115 return typeName;
116 }
117 /**
118 * A dictionary of fields to pick from an input
119 */
120 function printDefinedInputFields() {
121 return (0, utils_js_1.buildBlock)({
122 name: `interface DefinedInputFields`,
123 lines: visited.inputs.map(typeName => `${typeName}: ${printPicks(typeName, picks.inputs)};`),
124 });
125 }
126 /**
127 * Prints signatures of schema types with picks
128 */
129 function printSchemaTypes(types) {
130 return types
131 .filter(type => !visited.scalars.includes(type))
132 .map(printExportType)
133 .join('\n');
134 }
135 function printResolveSignaturesPerType(registry) {
136 return [
137 [...registry.objects, ...registry.interfaces]
138 .map(name => printResolverType(name, 'DefinedFields',
139 // In case of enabled `requireRootResolvers` flag, the preset has to produce a non-optional properties.
140 requireRootResolvers && rootTypes.includes(name), !rootTypes.includes(name) && defined.objects.includes(name) ? ` | '__isTypeOf'` : ''))
141 .join('\n'),
142 ].join('\n');
143 }
144 function printScalars(registry) {
145 if (!registry.scalars.length) {
146 return '';
147 }
148 return [
149 `export type ${encapsulateTypeName('Scalars')} = Pick<${importNamespace}.Scalars, ${registry.scalars
150 .map(utils_js_1.withQuotes)
151 .join(' | ')}>;`,
152 ...registry.scalars.map(scalar => {
153 const convertedName = baseVisitor.convertName(scalar, {
154 suffix: 'ScalarConfig',
155 });
156 return `export type ${encapsulateTypeName(convertedName)} = ${importNamespace}.${convertedName};`;
157 }),
158 ].join('\n');
159 }
160 /**
161 * Aggregation of type resolver signatures
162 */
163 function printResolversType(registry) {
164 const lines = [];
165 for (const kind in registry) {
166 const k = kind;
167 if (registry.hasOwnProperty(k) && resolverKeys.includes(k)) {
168 const types = registry[k];
169 types.forEach(typeName => {
170 if (k === 'enums') {
171 return;
172 }
173 if (k === 'scalars') {
174 lines.push(`${typeName}?: ${encapsulateTypeName(importNamespace)}.Resolvers['${typeName}'];`);
175 }
176 else {
177 // In case of enabled `requireRootResolvers` flag, the preset has to produce a non-optional property.
178 const fieldModifier = requireRootResolvers && rootTypes.includes(typeName) ? '' : '?';
179 lines.push(`${typeName}${fieldModifier}: ${encapsulateTypeName(typeName)}Resolvers;`);
180 }
181 });
182 }
183 }
184 return (0, utils_js_1.buildBlock)({
185 name: `export interface ${encapsulateTypeName('Resolvers')}`,
186 lines,
187 });
188 }
189 /**
190 * Signature for a map of resolve middlewares
191 */
192 function printResolveMiddlewareMap() {
193 const wildcardField = printResolveMiddlewareRecord((0, utils_js_1.withQuotes)('*'));
194 const blocks = [(0, utils_js_1.buildBlock)({ name: `${(0, utils_js_1.withQuotes)('*')}?:`, lines: [wildcardField] })];
195 // Type.Field
196 for (const typeName in picks.objects) {
197 if (picks.objects.hasOwnProperty(typeName)) {
198 const fields = picks.objects[typeName];
199 const lines = [wildcardField].concat(fields.map(field => printResolveMiddlewareRecord(field)));
200 blocks.push((0, utils_js_1.buildBlock)({
201 name: `${typeName}?:`,
202 lines,
203 }));
204 }
205 }
206 return (0, utils_js_1.buildBlock)({
207 name: `export interface ${encapsulateTypeName('MiddlewareMap')}`,
208 lines: blocks,
209 });
210 }
211 function printResolveMiddlewareRecord(path) {
212 return `${path}?: gm.Middleware[];`;
213 }
214 function printResolverType(typeName, picksTypeName, requireFieldsResolvers = false, extraKeys = '') {
215 const typeSignature = `Pick<${importNamespace}.${baseVisitor.convertName(typeName, {
216 suffix: 'Resolvers',
217 })}, ${picksTypeName}['${typeName}']${extraKeys}>`;
218 return `export type ${encapsulateTypeName(`${typeName}Resolvers`)} = ${requireFieldsResolvers ? `Required<${typeSignature}>` : typeSignature};`;
219 }
220 function printPicks(typeName, records) {
221 return records[typeName].filter(utils_js_1.unique).map(utils_js_1.withQuotes).join(' | ');
222 }
223 function printTypeBody(typeName) {
224 const coreType = `${importNamespace}.${baseVisitor.convertName(typeName, {
225 useTypesSuffix: true,
226 useTypesPrefix: true,
227 })}`;
228 if (external.enums.includes(typeName) || external.objects.includes(typeName)) {
229 if (schema && (0, graphql_1.isScalarType)(schema.getType(typeName))) {
230 return `${importNamespace}.Scalars['${typeName}']`;
231 }
232 return coreType;
233 }
234 if (defined.enums.includes(typeName) && picks.enums[typeName]) {
235 return `DefinedEnumValues['${typeName}']`;
236 }
237 if (defined.objects.includes(typeName) && picks.objects[typeName]) {
238 return `Pick<${coreType}, DefinedFields['${typeName}']>`;
239 }
240 if (defined.interfaces.includes(typeName) && picks.interfaces[typeName]) {
241 return `Pick<${coreType}, DefinedFields['${typeName}']>`;
242 }
243 if (defined.inputs.includes(typeName) && picks.inputs[typeName]) {
244 return `Pick<${coreType}, DefinedInputFields['${typeName}']>`;
245 }
246 return coreType;
247 }
248 function printExportType(typeName) {
249 return `export type ${encapsulateTypeName(typeName)} = ${printTypeBody(typeName)};`;
250 }
251 //
252 //
253 //
254 // Utils
255 //
256 //
257 //
258 function collectFields(node, picksObj) {
259 const name = node.name.value;
260 if (node.fields) {
261 if (!picksObj[name]) {
262 picksObj[name] = [];
263 }
264 node.fields.forEach(field => {
265 picksObj[name].push(field.name.value);
266 });
267 }
268 }
269 function collectValuesFromEnum(node) {
270 const name = node.name.value;
271 if (node.values) {
272 if (!picks.enums[name]) {
273 picks.enums[name] = [];
274 }
275 node.values.forEach(field => {
276 picks.enums[name].push(field.name.value);
277 });
278 }
279 }
280 function collectTypeDefinition(node) {
281 const name = node.name.value;
282 switch (node.kind) {
283 case graphql_1.Kind.OBJECT_TYPE_DEFINITION: {
284 defined.objects.push(name);
285 collectFields(node, picks.objects);
286 break;
287 }
288 case graphql_1.Kind.ENUM_TYPE_DEFINITION: {
289 defined.enums.push(name);
290 collectValuesFromEnum(node);
291 break;
292 }
293 case graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION: {
294 defined.inputs.push(name);
295 collectFields(node, picks.inputs);
296 break;
297 }
298 case graphql_1.Kind.SCALAR_TYPE_DEFINITION: {
299 defined.scalars.push(name);
300 break;
301 }
302 case graphql_1.Kind.INTERFACE_TYPE_DEFINITION: {
303 defined.interfaces.push(name);
304 collectFields(node, picks.interfaces);
305 break;
306 }
307 case graphql_1.Kind.UNION_TYPE_DEFINITION: {
308 defined.unions.push(name);
309 break;
310 }
311 }
312 }
313 function collectTypeExtension(node) {
314 const name = node.name.value;
315 switch (node.kind) {
316 case graphql_1.Kind.OBJECT_TYPE_EXTENSION: {
317 collectFields(node, picks.objects);
318 // Do not include root types as extensions
319 // so we can use them in DefinedFields
320 if (rootTypes.includes(name)) {
321 (0, utils_js_1.pushUnique)(defined.objects, name);
322 return;
323 }
324 (0, utils_js_1.pushUnique)(extended.objects, name);
325 break;
326 }
327 case graphql_1.Kind.ENUM_TYPE_EXTENSION: {
328 collectValuesFromEnum(node);
329 (0, utils_js_1.pushUnique)(extended.enums, name);
330 break;
331 }
332 case graphql_1.Kind.INPUT_OBJECT_TYPE_EXTENSION: {
333 collectFields(node, picks.inputs);
334 (0, utils_js_1.pushUnique)(extended.inputs, name);
335 break;
336 }
337 case graphql_1.Kind.INTERFACE_TYPE_EXTENSION: {
338 collectFields(node, picks.interfaces);
339 (0, utils_js_1.pushUnique)(extended.interfaces, name);
340 break;
341 }
342 case graphql_1.Kind.UNION_TYPE_EXTENSION: {
343 (0, utils_js_1.pushUnique)(extended.unions, name);
344 break;
345 }
346 }
347 }
348}
349exports.buildModule = buildModule;