UNPKG

20.7 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.BaseTypesVisitor = void 0;
4const graphql_1 = require("graphql");
5const base_visitor_js_1 = require("./base-visitor.js");
6const scalars_js_1 = require("./scalars.js");
7const declaration_kinds_js_1 = require("./declaration-kinds.js");
8const utils_js_1 = require("./utils.js");
9const variables_to_object_js_1 = require("./variables-to-object.js");
10const enum_values_js_1 = require("./enum-values.js");
11const mappers_js_1 = require("./mappers.js");
12class BaseTypesVisitor extends base_visitor_js_1.BaseVisitor {
13 constructor(_schema, rawConfig, additionalConfig, defaultScalars = scalars_js_1.DEFAULT_SCALARS) {
14 var _a;
15 super(rawConfig, {
16 enumPrefix: (0, utils_js_1.getConfigValue)(rawConfig.enumPrefix, true),
17 onlyEnums: (0, utils_js_1.getConfigValue)(rawConfig.onlyEnums, false),
18 onlyOperationTypes: (0, utils_js_1.getConfigValue)(rawConfig.onlyOperationTypes, false),
19 addUnderscoreToArgsType: (0, utils_js_1.getConfigValue)(rawConfig.addUnderscoreToArgsType, false),
20 enumValues: (0, enum_values_js_1.parseEnumValues)({
21 schema: _schema,
22 mapOrStr: rawConfig.enumValues,
23 ignoreEnumValuesFromSchema: rawConfig.ignoreEnumValuesFromSchema,
24 }),
25 declarationKind: (0, declaration_kinds_js_1.normalizeDeclarationKind)(rawConfig.declarationKind),
26 scalars: (0, utils_js_1.buildScalarsFromConfig)(_schema, rawConfig, defaultScalars),
27 fieldWrapperValue: (0, utils_js_1.getConfigValue)(rawConfig.fieldWrapperValue, 'T'),
28 wrapFieldDefinitions: (0, utils_js_1.getConfigValue)(rawConfig.wrapFieldDefinitions, false),
29 entireFieldWrapperValue: (0, utils_js_1.getConfigValue)(rawConfig.entireFieldWrapperValue, 'T'),
30 wrapEntireDefinitions: (0, utils_js_1.getConfigValue)(rawConfig.wrapEntireFieldDefinitions, false),
31 ignoreEnumValuesFromSchema: (0, utils_js_1.getConfigValue)(rawConfig.ignoreEnumValuesFromSchema, false),
32 directiveArgumentAndInputFieldMappings: (0, mappers_js_1.transformDirectiveArgumentAndInputFieldMappings)((_a = rawConfig.directiveArgumentAndInputFieldMappings) !== null && _a !== void 0 ? _a : {}, rawConfig.directiveArgumentAndInputFieldMappingTypeSuffix),
33 ...additionalConfig,
34 });
35 this._schema = _schema;
36 // Note: Missing directive mappers but not a problem since always overriden by implementors
37 this._argumentsTransformer = new variables_to_object_js_1.OperationVariablesToObject(this.scalars, this.convertName);
38 }
39 getExportPrefix() {
40 return 'export ';
41 }
42 getFieldWrapperValue() {
43 if (this.config.fieldWrapperValue) {
44 return `${this.getExportPrefix()}type FieldWrapper<T> = ${this.config.fieldWrapperValue};`;
45 }
46 return '';
47 }
48 getEntireFieldWrapperValue() {
49 if (this.config.entireFieldWrapperValue) {
50 return `${this.getExportPrefix()}type EntireFieldWrapper<T> = ${this.config.entireFieldWrapperValue};`;
51 }
52 return '';
53 }
54 getScalarsImports() {
55 return Object.keys(this.config.scalars)
56 .map(enumName => {
57 const mappedValue = this.config.scalars[enumName];
58 if (mappedValue.isExternal) {
59 return this._buildTypeImport(mappedValue.import, mappedValue.source, mappedValue.default);
60 }
61 return null;
62 })
63 .filter(a => a);
64 }
65 getDirectiveArgumentAndInputFieldMappingsImports() {
66 return Object.keys(this.config.directiveArgumentAndInputFieldMappings)
67 .map(directive => {
68 const mappedValue = this.config.directiveArgumentAndInputFieldMappings[directive];
69 if (mappedValue.isExternal) {
70 return this._buildTypeImport(mappedValue.import, mappedValue.source, mappedValue.default);
71 }
72 return null;
73 })
74 .filter(a => a);
75 }
76 get scalarsDefinition() {
77 if (this.config.onlyEnums)
78 return '';
79 const allScalars = Object.keys(this.config.scalars).map(scalarName => {
80 const scalarValue = this.config.scalars[scalarName].type;
81 const scalarType = this._schema.getType(scalarName);
82 const comment = scalarType && scalarType.astNode && scalarType.description ? (0, utils_js_1.transformComment)(scalarType.description, 1) : '';
83 const { scalar } = this._parsedConfig.declarationKind;
84 return comment + (0, utils_js_1.indent)(`${scalarName}: ${scalarValue}${this.getPunctuation(scalar)}`);
85 });
86 return new utils_js_1.DeclarationBlock(this._declarationBlockConfig)
87 .export()
88 .asKind(this._parsedConfig.declarationKind.scalar)
89 .withName('Scalars')
90 .withComment('All built-in and custom scalars, mapped to their actual values')
91 .withBlock(allScalars.join('\n')).string;
92 }
93 get directiveArgumentAndInputFieldMappingsDefinition() {
94 const directiveEntries = Object.entries(this.config.directiveArgumentAndInputFieldMappings);
95 if (directiveEntries.length === 0) {
96 return '';
97 }
98 const allDirectives = [];
99 for (const [directiveName, parsedMapper] of directiveEntries) {
100 const directiveType = this._schema.getDirective(directiveName);
101 const comment = (directiveType === null || directiveType === void 0 ? void 0 : directiveType.astNode) && directiveType.description ? (0, utils_js_1.transformComment)(directiveType.description, 1) : '';
102 const { directive } = this._parsedConfig.declarationKind;
103 allDirectives.push(comment + (0, utils_js_1.indent)(`${directiveName}: ${parsedMapper.type}${this.getPunctuation(directive)}`));
104 }
105 return new utils_js_1.DeclarationBlock(this._declarationBlockConfig)
106 .export()
107 .asKind(this._parsedConfig.declarationKind.directive)
108 .withName('DirectiveArgumentAndInputFieldMappings')
109 .withComment('Type overrides using directives')
110 .withBlock(allDirectives.join('\n')).string;
111 }
112 setDeclarationBlockConfig(config) {
113 this._declarationBlockConfig = config;
114 }
115 setArgumentsTransformer(argumentsTransfomer) {
116 this._argumentsTransformer = argumentsTransfomer;
117 }
118 NonNullType(node) {
119 const asString = node.type;
120 return asString;
121 }
122 getInputObjectDeclarationBlock(node) {
123 return new utils_js_1.DeclarationBlock(this._declarationBlockConfig)
124 .export()
125 .asKind(this._parsedConfig.declarationKind.input)
126 .withName(this.convertName(node))
127 .withComment(node.description)
128 .withBlock(node.fields.join('\n'));
129 }
130 getInputObjectOneOfDeclarationBlock(node) {
131 // As multiple fields always result in a union, we have
132 // to force a declaration kind of `type` in this case
133 const declarationKind = node.fields.length === 1 ? this._parsedConfig.declarationKind.input : 'type';
134 return new utils_js_1.DeclarationBlock(this._declarationBlockConfig)
135 .export()
136 .asKind(declarationKind)
137 .withName(this.convertName(node))
138 .withComment(node.description)
139 .withContent(`\n` + node.fields.join('\n |'));
140 }
141 InputObjectTypeDefinition(node) {
142 if (this.config.onlyEnums)
143 return '';
144 // Why the heck is node.name a string and not { value: string } at runtime ?!
145 if ((0, utils_js_1.isOneOfInputObjectType)(this._schema.getType(node.name))) {
146 return this.getInputObjectOneOfDeclarationBlock(node).string;
147 }
148 return this.getInputObjectDeclarationBlock(node).string;
149 }
150 InputValueDefinition(node) {
151 if (this.config.onlyEnums)
152 return '';
153 const comment = (0, utils_js_1.transformComment)(node.description, 1);
154 const { input } = this._parsedConfig.declarationKind;
155 let type = node.type;
156 if (node.directives && this.config.directiveArgumentAndInputFieldMappings) {
157 type = this._getDirectiveOverrideType(node.directives) || type;
158 }
159 return comment + (0, utils_js_1.indent)(`${node.name}: ${type}${this.getPunctuation(input)}`);
160 }
161 Name(node) {
162 return node.value;
163 }
164 FieldDefinition(node) {
165 if (this.config.onlyEnums)
166 return '';
167 const typeString = node.type;
168 const { type } = this._parsedConfig.declarationKind;
169 const comment = this.getNodeComment(node);
170 return comment + (0, utils_js_1.indent)(`${node.name}: ${typeString}${this.getPunctuation(type)}`);
171 }
172 UnionTypeDefinition(node, key, parent) {
173 if (this.config.onlyOperationTypes || this.config.onlyEnums)
174 return '';
175 const originalNode = parent[key];
176 const possibleTypes = originalNode.types
177 .map(t => (this.scalars[t.name.value] ? this._getScalar(t.name.value) : this.convertName(t)))
178 .join(' | ');
179 return new utils_js_1.DeclarationBlock(this._declarationBlockConfig)
180 .export()
181 .asKind('type')
182 .withName(this.convertName(node))
183 .withComment(node.description)
184 .withContent(possibleTypes).string;
185 }
186 mergeInterfaces(interfaces, hasOtherFields) {
187 return interfaces.join(' & ') + (interfaces.length && hasOtherFields ? ' & ' : '');
188 }
189 appendInterfacesAndFieldsToBlock(block, interfaces, fields) {
190 block.withContent(this.mergeInterfaces(interfaces, fields.length > 0));
191 block.withBlock(this.mergeAllFields(fields, interfaces.length > 0));
192 }
193 getObjectTypeDeclarationBlock(node, originalNode) {
194 const optionalTypename = this.config.nonOptionalTypename ? '__typename' : '__typename?';
195 const { type, interface: interfacesType } = this._parsedConfig.declarationKind;
196 const allFields = [
197 ...(this.config.addTypename
198 ? [
199 (0, utils_js_1.indent)(`${this.config.immutableTypes ? 'readonly ' : ''}${optionalTypename}: '${node.name}'${this.getPunctuation(type)}`),
200 ]
201 : []),
202 ...node.fields,
203 ];
204 const interfacesNames = originalNode.interfaces ? originalNode.interfaces.map(i => this.convertName(i)) : [];
205 const declarationBlock = new utils_js_1.DeclarationBlock(this._declarationBlockConfig)
206 .export()
207 .asKind(type)
208 .withName(this.convertName(node))
209 .withComment(node.description);
210 if (type === 'interface' || type === 'class') {
211 if (interfacesNames.length > 0) {
212 const keyword = interfacesType === 'interface' && type === 'class' ? 'implements' : 'extends';
213 declarationBlock.withContent(`${keyword} ` + interfacesNames.join(', ') + (allFields.length > 0 ? ' ' : ' {}'));
214 }
215 declarationBlock.withBlock(this.mergeAllFields(allFields, false));
216 }
217 else {
218 this.appendInterfacesAndFieldsToBlock(declarationBlock, interfacesNames, allFields);
219 }
220 return declarationBlock;
221 }
222 mergeAllFields(allFields, _hasInterfaces) {
223 return allFields.join('\n');
224 }
225 ObjectTypeDefinition(node, key, parent) {
226 if (this.config.onlyOperationTypes || this.config.onlyEnums)
227 return '';
228 const originalNode = parent[key];
229 return [this.getObjectTypeDeclarationBlock(node, originalNode).string, this.buildArgumentsBlock(originalNode)]
230 .filter(f => f)
231 .join('\n\n');
232 }
233 getInterfaceTypeDeclarationBlock(node, _originalNode) {
234 const declarationBlock = new utils_js_1.DeclarationBlock(this._declarationBlockConfig)
235 .export()
236 .asKind(this._parsedConfig.declarationKind.interface)
237 .withName(this.convertName(node))
238 .withComment(node.description);
239 return declarationBlock.withBlock(node.fields.join('\n'));
240 }
241 InterfaceTypeDefinition(node, key, parent) {
242 if (this.config.onlyOperationTypes || this.config.onlyEnums)
243 return '';
244 const originalNode = parent[key];
245 return [this.getInterfaceTypeDeclarationBlock(node, originalNode).string, this.buildArgumentsBlock(originalNode)]
246 .filter(f => f)
247 .join('\n\n');
248 }
249 ScalarTypeDefinition(_node) {
250 // We empty this because we handle scalars in a different way, see constructor.
251 return '';
252 }
253 _buildTypeImport(identifier, source, asDefault = false) {
254 const { useTypeImports } = this.config;
255 if (asDefault) {
256 if (useTypeImports) {
257 return `import type { default as ${identifier} } from '${source}';`;
258 }
259 return `import ${identifier} from '${source}';`;
260 }
261 return `import${useTypeImports ? ' type' : ''} { ${identifier} } from '${source}';`;
262 }
263 handleEnumValueMapper(typeIdentifier, importIdentifier, sourceIdentifier, sourceFile) {
264 const importStatement = this._buildTypeImport(importIdentifier || sourceIdentifier, sourceFile);
265 if (importIdentifier !== sourceIdentifier || sourceIdentifier !== typeIdentifier) {
266 return [importStatement, `import ${typeIdentifier} = ${sourceIdentifier};`];
267 }
268 return [importStatement];
269 }
270 getEnumsImports() {
271 return Object.keys(this.config.enumValues)
272 .flatMap(enumName => {
273 const mappedValue = this.config.enumValues[enumName];
274 if (mappedValue.sourceFile) {
275 if (mappedValue.isDefault) {
276 return [this._buildTypeImport(mappedValue.typeIdentifier, mappedValue.sourceFile, true)];
277 }
278 return this.handleEnumValueMapper(mappedValue.typeIdentifier, mappedValue.importIdentifier, mappedValue.sourceIdentifier, mappedValue.sourceFile);
279 }
280 return [];
281 })
282 .filter(Boolean);
283 }
284 EnumTypeDefinition(node) {
285 const enumName = node.name;
286 // In case of mapped external enum string
287 if (this.config.enumValues[enumName] && this.config.enumValues[enumName].sourceFile) {
288 return null;
289 }
290 return new utils_js_1.DeclarationBlock(this._declarationBlockConfig)
291 .export()
292 .asKind('enum')
293 .withName(this.convertName(node, { useTypesPrefix: this.config.enumPrefix }))
294 .withComment(node.description)
295 .withBlock(this.buildEnumValuesBlock(enumName, node.values)).string;
296 }
297 // We are using it in order to transform "description" field
298 StringValue(node) {
299 return node.value;
300 }
301 makeValidEnumIdentifier(identifier) {
302 if (/^[0-9]/.exec(identifier)) {
303 return (0, utils_js_1.wrapWithSingleQuotes)(identifier, true);
304 }
305 return identifier;
306 }
307 buildEnumValuesBlock(typeName, values) {
308 const schemaEnumType = this._schema
309 ? this._schema.getType(typeName)
310 : undefined;
311 return values
312 .map(enumOption => {
313 const optionName = this.makeValidEnumIdentifier(this.convertName(enumOption, {
314 useTypesPrefix: false,
315 transformUnderscore: true,
316 }));
317 const comment = this.getNodeComment(enumOption);
318 const schemaEnumValue = schemaEnumType && !this.config.ignoreEnumValuesFromSchema
319 ? schemaEnumType.getValue(enumOption.name).value
320 : undefined;
321 let enumValue = typeof schemaEnumValue !== 'undefined' ? schemaEnumValue : enumOption.name;
322 if (this.config.enumValues[typeName] &&
323 this.config.enumValues[typeName].mappedValues &&
324 typeof this.config.enumValues[typeName].mappedValues[enumValue] !== 'undefined') {
325 enumValue = this.config.enumValues[typeName].mappedValues[enumValue];
326 }
327 return (comment +
328 (0, utils_js_1.indent)(`${optionName}${this._declarationBlockConfig.enumNameValueSeparator} ${(0, utils_js_1.wrapWithSingleQuotes)(enumValue, typeof schemaEnumValue !== 'undefined')}`));
329 })
330 .join(',\n');
331 }
332 DirectiveDefinition(_node) {
333 return '';
334 }
335 getArgumentsObjectDeclarationBlock(node, name, field) {
336 return new utils_js_1.DeclarationBlock(this._declarationBlockConfig)
337 .export()
338 .asKind(this._parsedConfig.declarationKind.arguments)
339 .withName(this.convertName(name))
340 .withComment(node.description)
341 .withBlock(this._argumentsTransformer.transform(field.arguments));
342 }
343 getArgumentsObjectTypeDefinition(node, name, field) {
344 if (this.config.onlyEnums)
345 return '';
346 return this.getArgumentsObjectDeclarationBlock(node, name, field).string;
347 }
348 buildArgumentsBlock(node) {
349 const fieldsWithArguments = node.fields.filter(field => field.arguments && field.arguments.length > 0) || [];
350 return fieldsWithArguments
351 .map(field => {
352 const name = node.name.value +
353 (this.config.addUnderscoreToArgsType ? '_' : '') +
354 this.convertName(field, {
355 useTypesPrefix: false,
356 useTypesSuffix: false,
357 }) +
358 'Args';
359 return this.getArgumentsObjectTypeDefinition(node, name, field);
360 })
361 .join('\n\n');
362 }
363 _getScalar(name) {
364 return `Scalars['${name}']`;
365 }
366 _getDirectiveArgumentNadInputFieldMapping(name) {
367 return `DirectiveArgumentAndInputFieldMappings['${name}']`;
368 }
369 _getDirectiveOverrideType(directives) {
370 const type = directives
371 .map(directive => {
372 const directiveName = directive.name;
373 if (this.config.directiveArgumentAndInputFieldMappings[directiveName]) {
374 return this._getDirectiveArgumentNadInputFieldMapping(directiveName);
375 }
376 return null;
377 })
378 .reverse()
379 .find(a => !!a);
380 return type || null;
381 }
382 _getTypeForNode(node) {
383 const typeAsString = node.name;
384 if (this.scalars[typeAsString]) {
385 return this._getScalar(typeAsString);
386 }
387 if (this.config.enumValues[typeAsString]) {
388 return this.config.enumValues[typeAsString].typeIdentifier;
389 }
390 const schemaType = this._schema.getType(node.name);
391 if (schemaType && (0, graphql_1.isEnumType)(schemaType)) {
392 return this.convertName(node, { useTypesPrefix: this.config.enumPrefix });
393 }
394 return this.convertName(node);
395 }
396 NamedType(node, key, parent, path, ancestors) {
397 const currentVisitContext = this.getVisitorKindContextFromAncestors(ancestors);
398 const isVisitingInputType = currentVisitContext.includes(graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION);
399 const typeToUse = this._getTypeForNode(node);
400 if (!isVisitingInputType && this.config.fieldWrapperValue && this.config.wrapFieldDefinitions) {
401 return `FieldWrapper<${typeToUse}>`;
402 }
403 return typeToUse;
404 }
405 ListType(node, key, parent, path, ancestors) {
406 const asString = node.type;
407 return this.wrapWithListType(asString);
408 }
409 SchemaDefinition() {
410 return null;
411 }
412 getNodeComment(node) {
413 let commentText = node.description;
414 const deprecationDirective = node.directives.find((v) => v.name === 'deprecated');
415 if (deprecationDirective) {
416 const deprecationReason = this.getDeprecationReason(deprecationDirective);
417 commentText = `${commentText ? `${commentText}\n` : ''}@deprecated ${deprecationReason}`;
418 }
419 const comment = (0, utils_js_1.transformComment)(commentText, 1);
420 return comment;
421 }
422 getDeprecationReason(directive) {
423 if (directive.name === 'deprecated') {
424 const hasArguments = directive.arguments.length > 0;
425 let reason = 'Field no longer supported';
426 if (hasArguments) {
427 reason = directive.arguments[0].value;
428 }
429 return reason;
430 }
431 }
432 wrapWithListType(str) {
433 return `Array<${str}>`;
434 }
435}
436exports.BaseTypesVisitor = BaseTypesVisitor;