1 | 'use strict';
|
2 |
|
3 | Object.defineProperty(exports, '__esModule', { value: true });
|
4 |
|
5 | function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
|
6 |
|
7 | const pluginHelpers = require('@graphql-codegen/plugin-helpers');
|
8 | const graphql = require('graphql');
|
9 | const visitorPluginCommon = require('@graphql-codegen/visitor-plugin-common');
|
10 | const autoBind = _interopDefault(require('auto-bind'));
|
11 | const schemaAst = require('@graphql-codegen/schema-ast');
|
12 |
|
13 | class TypeScriptOperationVariablesToObject extends visitorPluginCommon.OperationVariablesToObject {
|
14 | constructor(_scalars, _convertName, _avoidOptionals, _immutableTypes, _namespacedImportName = null, _enumNames = [], _enumPrefix = true, _enumValues = {}, _applyCoercion = false, _directiveArgumentAndInputFieldMappings = {}, _maybeType = 'Maybe') {
|
15 | super(_scalars, _convertName, _namespacedImportName, _enumNames, _enumPrefix, _enumValues, _applyCoercion, _directiveArgumentAndInputFieldMappings);
|
16 | this._avoidOptionals = _avoidOptionals;
|
17 | this._immutableTypes = _immutableTypes;
|
18 | this._maybeType = _maybeType;
|
19 | }
|
20 | clearOptional(str) {
|
21 | const prefix = this._namespacedImportName ? `${this._namespacedImportName}.` : '';
|
22 | const rgx = new RegExp(`^${this.wrapMaybe(`(.*?)`)}$`, 'i');
|
23 | if (str.startsWith(`${prefix}${this._maybeType}`)) {
|
24 | return str.replace(rgx, '$1');
|
25 | }
|
26 | return str;
|
27 | }
|
28 | wrapAstTypeWithModifiers(baseType, typeNode, applyCoercion = false) {
|
29 | if (typeNode.kind === graphql.Kind.NON_NULL_TYPE) {
|
30 | const type = this.wrapAstTypeWithModifiers(baseType, typeNode.type, applyCoercion);
|
31 | return this.clearOptional(type);
|
32 | }
|
33 | else if (typeNode.kind === graphql.Kind.LIST_TYPE) {
|
34 | const innerType = this.wrapAstTypeWithModifiers(baseType, typeNode.type, applyCoercion);
|
35 | const listInputCoercionExtension = applyCoercion ? ` | ${innerType}` : '';
|
36 | return this.wrapMaybe(`${this._immutableTypes ? 'ReadonlyArray' : 'Array'}<${innerType}>${listInputCoercionExtension}`);
|
37 | }
|
38 | else {
|
39 | return this.wrapMaybe(baseType);
|
40 | }
|
41 | }
|
42 | formatFieldString(fieldName, isNonNullType, hasDefaultValue) {
|
43 | return `${fieldName}${this.getAvoidOption(isNonNullType, hasDefaultValue) ? '?' : ''}`;
|
44 | }
|
45 | formatTypeString(fieldType, isNonNullType, hasDefaultValue) {
|
46 | if (!hasDefaultValue && isNonNullType) {
|
47 | return this.clearOptional(fieldType);
|
48 | }
|
49 | return fieldType;
|
50 | }
|
51 | wrapMaybe(type) {
|
52 | const prefix = this._namespacedImportName ? `${this._namespacedImportName}.` : '';
|
53 | return `${prefix}${this._maybeType}${type ? `<${type}>` : ''}`;
|
54 | }
|
55 | getAvoidOption(isNonNullType, hasDefaultValue) {
|
56 | const options = visitorPluginCommon.normalizeAvoidOptionals(this._avoidOptionals);
|
57 | return ((options.object || !options.defaultValue) && hasDefaultValue) || (!options.object && !isNonNullType);
|
58 | }
|
59 | getPunctuation() {
|
60 | return ';';
|
61 | }
|
62 | }
|
63 |
|
64 | const EXACT_SIGNATURE = `type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };`;
|
65 | const MAKE_OPTIONAL_SIGNATURE = `type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };`;
|
66 | const MAKE_MAYBE_SIGNATURE = `type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };`;
|
67 | class TsVisitor extends visitorPluginCommon.BaseTypesVisitor {
|
68 | constructor(schema, pluginConfig, additionalConfig = {}) {
|
69 | super(schema, pluginConfig, {
|
70 | noExport: visitorPluginCommon.getConfigValue(pluginConfig.noExport, false),
|
71 | avoidOptionals: visitorPluginCommon.normalizeAvoidOptionals(visitorPluginCommon.getConfigValue(pluginConfig.avoidOptionals, false)),
|
72 | maybeValue: visitorPluginCommon.getConfigValue(pluginConfig.maybeValue, 'T | null'),
|
73 | inputMaybeValue: visitorPluginCommon.getConfigValue(pluginConfig.inputMaybeValue, visitorPluginCommon.getConfigValue(pluginConfig.maybeValue, 'Maybe<T>')),
|
74 | constEnums: visitorPluginCommon.getConfigValue(pluginConfig.constEnums, false),
|
75 | enumsAsTypes: visitorPluginCommon.getConfigValue(pluginConfig.enumsAsTypes, false),
|
76 | futureProofEnums: visitorPluginCommon.getConfigValue(pluginConfig.futureProofEnums, false),
|
77 | futureProofUnions: visitorPluginCommon.getConfigValue(pluginConfig.futureProofUnions, false),
|
78 | enumsAsConst: visitorPluginCommon.getConfigValue(pluginConfig.enumsAsConst, false),
|
79 | numericEnums: visitorPluginCommon.getConfigValue(pluginConfig.numericEnums, false),
|
80 | onlyEnums: visitorPluginCommon.getConfigValue(pluginConfig.onlyEnums, false),
|
81 | onlyOperationTypes: visitorPluginCommon.getConfigValue(pluginConfig.onlyOperationTypes, false),
|
82 | immutableTypes: visitorPluginCommon.getConfigValue(pluginConfig.immutableTypes, false),
|
83 | useImplementingTypes: visitorPluginCommon.getConfigValue(pluginConfig.useImplementingTypes, false),
|
84 | entireFieldWrapperValue: visitorPluginCommon.getConfigValue(pluginConfig.entireFieldWrapperValue, 'T'),
|
85 | wrapEntireDefinitions: visitorPluginCommon.getConfigValue(pluginConfig.wrapEntireFieldDefinitions, false),
|
86 | ...additionalConfig,
|
87 | });
|
88 | autoBind(this);
|
89 | const enumNames = Object.values(schema.getTypeMap())
|
90 | .filter(graphql.isEnumType)
|
91 | .map(type => type.name);
|
92 | this.setArgumentsTransformer(new TypeScriptOperationVariablesToObject(this.scalars, this.convertName, this.config.avoidOptionals, this.config.immutableTypes, null, enumNames, pluginConfig.enumPrefix, this.config.enumValues, false, this.config.directiveArgumentAndInputFieldMappings, 'InputMaybe'));
|
93 | this.setDeclarationBlockConfig({
|
94 | enumNameValueSeparator: ' =',
|
95 | ignoreExport: this.config.noExport,
|
96 | });
|
97 | }
|
98 | _getTypeForNode(node) {
|
99 | const typeAsString = node.name;
|
100 | if (this.config.useImplementingTypes) {
|
101 | const allTypesMap = this._schema.getTypeMap();
|
102 | const implementingTypes = [];
|
103 |
|
104 | for (const graphqlType of Object.values(allTypesMap)) {
|
105 | if (graphqlType instanceof graphql.GraphQLObjectType) {
|
106 | const allInterfaces = graphqlType.getInterfaces();
|
107 | if (allInterfaces.some(int => typeAsString === int.name)) {
|
108 | implementingTypes.push(this.convertName(graphqlType.name));
|
109 | }
|
110 | }
|
111 | }
|
112 | if (implementingTypes.length > 0) {
|
113 | return implementingTypes.join(' | ');
|
114 | }
|
115 | }
|
116 | const typeString = super._getTypeForNode(node);
|
117 | const schemaType = this._schema.getType(node.name);
|
118 | if (graphql.isEnumType(schemaType)) {
|
119 |
|
120 |
|
121 | const futureProofEnumUsageEnabled = this.config.futureProofEnums === true && this.config.enumsAsTypes !== true;
|
122 | if (futureProofEnumUsageEnabled && this.config.allowEnumStringTypes === true) {
|
123 | return `${typeString} | '%future added value' | ` + '`${' + typeString + '}`';
|
124 | }
|
125 | if (futureProofEnumUsageEnabled) {
|
126 | return `${typeString} | '%future added value'`;
|
127 | }
|
128 | if (this.config.allowEnumStringTypes === true) {
|
129 | return `${typeString} | ` + '`${' + typeString + '}`';
|
130 | }
|
131 | }
|
132 | return typeString;
|
133 | }
|
134 | getWrapperDefinitions() {
|
135 | if (this.config.onlyEnums)
|
136 | return [];
|
137 | const definitions = [
|
138 | this.getMaybeValue(),
|
139 | this.getInputMaybeValue(),
|
140 | this.getExactDefinition(),
|
141 | this.getMakeOptionalDefinition(),
|
142 | this.getMakeMaybeDefinition(),
|
143 | ];
|
144 | if (this.config.wrapFieldDefinitions) {
|
145 | definitions.push(this.getFieldWrapperValue());
|
146 | }
|
147 | if (this.config.wrapEntireDefinitions) {
|
148 | definitions.push(this.getEntireFieldWrapperValue());
|
149 | }
|
150 | return definitions;
|
151 | }
|
152 | getExactDefinition() {
|
153 | if (this.config.onlyEnums)
|
154 | return '';
|
155 | return `${this.getExportPrefix()}${EXACT_SIGNATURE}`;
|
156 | }
|
157 | getMakeOptionalDefinition() {
|
158 | return `${this.getExportPrefix()}${MAKE_OPTIONAL_SIGNATURE}`;
|
159 | }
|
160 | getMakeMaybeDefinition() {
|
161 | if (this.config.onlyEnums)
|
162 | return '';
|
163 | return `${this.getExportPrefix()}${MAKE_MAYBE_SIGNATURE}`;
|
164 | }
|
165 | getMaybeValue() {
|
166 | return `${this.getExportPrefix()}type Maybe<T> = ${this.config.maybeValue};`;
|
167 | }
|
168 | getInputMaybeValue() {
|
169 | return `${this.getExportPrefix()}type InputMaybe<T> = ${this.config.inputMaybeValue};`;
|
170 | }
|
171 | clearOptional(str) {
|
172 | if (str.startsWith('Maybe')) {
|
173 | return str.replace(/Maybe<(.*?)>$/, '$1');
|
174 | }
|
175 | if (str.startsWith('InputMaybe')) {
|
176 | return str.replace(/InputMaybe<(.*?)>$/, '$1');
|
177 | }
|
178 | return str;
|
179 | }
|
180 | getExportPrefix() {
|
181 | if (this.config.noExport) {
|
182 | return '';
|
183 | }
|
184 | return super.getExportPrefix();
|
185 | }
|
186 | getMaybeWrapper(ancestors) {
|
187 | const currentVisitContext = this.getVisitorKindContextFromAncestors(ancestors);
|
188 | const isInputContext = currentVisitContext.includes(graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION);
|
189 | return isInputContext ? 'InputMaybe' : 'Maybe';
|
190 | }
|
191 | NamedType(node, key, parent, path, ancestors) {
|
192 | return `${this.getMaybeWrapper(ancestors)}<${super.NamedType(node, key, parent, path, ancestors)}>`;
|
193 | }
|
194 | ListType(node, key, parent, path, ancestors) {
|
195 | return `${this.getMaybeWrapper(ancestors)}<${super.ListType(node, key, parent, path, ancestors)}>`;
|
196 | }
|
197 | UnionTypeDefinition(node, key, parent) {
|
198 | if (this.config.onlyOperationTypes || this.config.onlyEnums)
|
199 | return '';
|
200 | let withFutureAddedValue = [];
|
201 | if (this.config.futureProofUnions) {
|
202 | withFutureAddedValue = [
|
203 | this.config.immutableTypes ? `{ readonly __typename?: "%other" }` : `{ __typename?: "%other" }`,
|
204 | ];
|
205 | }
|
206 | const originalNode = parent[key];
|
207 | const possibleTypes = originalNode.types
|
208 | .map(t => (this.scalars[t.name.value] ? this._getScalar(t.name.value) : this.convertName(t)))
|
209 | .concat(...withFutureAddedValue)
|
210 | .join(' | ');
|
211 | return new visitorPluginCommon.DeclarationBlock(this._declarationBlockConfig)
|
212 | .export()
|
213 | .asKind('type')
|
214 | .withName(this.convertName(node))
|
215 | .withComment(node.description)
|
216 | .withContent(possibleTypes).string;
|
217 |
|
218 | }
|
219 | wrapWithListType(str) {
|
220 | return `${this.config.immutableTypes ? 'ReadonlyArray' : 'Array'}<${str}>`;
|
221 | }
|
222 | NonNullType(node) {
|
223 | const baseValue = super.NonNullType(node);
|
224 | return this.clearOptional(baseValue);
|
225 | }
|
226 | FieldDefinition(node, key, parent) {
|
227 | const typeString = this.config.wrapEntireDefinitions
|
228 | ? `EntireFieldWrapper<${node.type}>`
|
229 | : node.type;
|
230 | const originalFieldNode = parent[key];
|
231 | const addOptionalSign = !this.config.avoidOptionals.field && originalFieldNode.type.kind !== graphql.Kind.NON_NULL_TYPE;
|
232 | const comment = this.getNodeComment(node);
|
233 | const { type } = this.config.declarationKind;
|
234 | return (comment +
|
235 | visitorPluginCommon.indent(`${this.config.immutableTypes ? 'readonly ' : ''}${node.name}${addOptionalSign ? '?' : ''}: ${typeString}${this.getPunctuation(type)}`));
|
236 | }
|
237 | InputValueDefinition(node, key, parent) {
|
238 | const originalFieldNode = parent[key];
|
239 | const addOptionalSign = !this.config.avoidOptionals.inputValue &&
|
240 | (originalFieldNode.type.kind !== graphql.Kind.NON_NULL_TYPE ||
|
241 | (!this.config.avoidOptionals.defaultValue && node.defaultValue !== undefined));
|
242 | const comment = visitorPluginCommon.transformComment(node.description, 1);
|
243 | const declarationKind = this.config.declarationKind.type;
|
244 | let type = node.type;
|
245 | if (node.directives && this.config.directiveArgumentAndInputFieldMappings) {
|
246 | type = this._getDirectiveOverrideType(node.directives) || type;
|
247 | }
|
248 | return (comment +
|
249 | visitorPluginCommon.indent(`${this.config.immutableTypes ? 'readonly ' : ''}${node.name}${addOptionalSign ? '?' : ''}: ${type}${this.getPunctuation(declarationKind)}`));
|
250 | }
|
251 | EnumTypeDefinition(node) {
|
252 | const enumName = node.name;
|
253 |
|
254 | if (this.config.enumValues[enumName] && this.config.enumValues[enumName].sourceFile) {
|
255 | return `export { ${this.config.enumValues[enumName].typeIdentifier} };\n`;
|
256 | }
|
257 | const getValueFromConfig = (enumValue) => {
|
258 | if (this.config.enumValues[enumName] &&
|
259 | this.config.enumValues[enumName].mappedValues &&
|
260 | typeof this.config.enumValues[enumName].mappedValues[enumValue] !== 'undefined') {
|
261 | return this.config.enumValues[enumName].mappedValues[enumValue];
|
262 | }
|
263 | return null;
|
264 | };
|
265 | const withFutureAddedValue = [
|
266 | this.config.futureProofEnums ? [visitorPluginCommon.indent('| ' + visitorPluginCommon.wrapWithSingleQuotes('%future added value'))] : [],
|
267 | ];
|
268 | const enumTypeName = this.convertName(node, {
|
269 | useTypesPrefix: this.config.enumPrefix,
|
270 | });
|
271 | if (this.config.enumsAsTypes) {
|
272 | return new visitorPluginCommon.DeclarationBlock(this._declarationBlockConfig)
|
273 | .export()
|
274 | .asKind('type')
|
275 | .withComment(node.description)
|
276 | .withName(enumTypeName)
|
277 | .withContent('\n' +
|
278 | node.values
|
279 | .map(enumOption => {
|
280 | var _a;
|
281 | const name = enumOption.name;
|
282 | const enumValue = (_a = getValueFromConfig(name)) !== null && _a !== void 0 ? _a : name;
|
283 | const comment = visitorPluginCommon.transformComment(enumOption.description, 1);
|
284 | return comment + visitorPluginCommon.indent('| ' + visitorPluginCommon.wrapWithSingleQuotes(enumValue));
|
285 | })
|
286 | .concat(...withFutureAddedValue)
|
287 | .join('\n')).string;
|
288 | }
|
289 | if (this.config.numericEnums) {
|
290 | const block = new visitorPluginCommon.DeclarationBlock(this._declarationBlockConfig)
|
291 | .export()
|
292 | .withComment(node.description)
|
293 | .withName(enumTypeName)
|
294 | .asKind('enum')
|
295 | .withBlock(node.values
|
296 | .map((enumOption, i) => {
|
297 | const valueFromConfig = getValueFromConfig(enumOption.name);
|
298 | const enumValue = valueFromConfig !== null && valueFromConfig !== void 0 ? valueFromConfig : i;
|
299 | const comment = visitorPluginCommon.transformComment(enumOption.description, 1);
|
300 | const optionName = this.makeValidEnumIdentifier(this.convertName(enumOption, {
|
301 | useTypesPrefix: false,
|
302 | transformUnderscore: true,
|
303 | }));
|
304 | return comment + visitorPluginCommon.indent(optionName) + ` = ${enumValue}`;
|
305 | })
|
306 | .concat(...withFutureAddedValue)
|
307 | .join(',\n')).string;
|
308 | return block;
|
309 | }
|
310 | if (this.config.enumsAsConst) {
|
311 | const typeName = `export type ${enumTypeName} = typeof ${enumTypeName}[keyof typeof ${enumTypeName}];`;
|
312 | const enumAsConst = new visitorPluginCommon.DeclarationBlock({
|
313 | ...this._declarationBlockConfig,
|
314 | blockTransformer: block => {
|
315 | return block + ' as const';
|
316 | },
|
317 | })
|
318 | .export()
|
319 | .asKind('const')
|
320 | .withName(enumTypeName)
|
321 | .withComment(node.description)
|
322 | .withBlock(node.values
|
323 | .map(enumOption => {
|
324 | var _a;
|
325 | const optionName = this.convertName(enumOption, {
|
326 | useTypesPrefix: false,
|
327 | transformUnderscore: true,
|
328 | });
|
329 | const comment = visitorPluginCommon.transformComment(enumOption.description, 1);
|
330 | const name = enumOption.name;
|
331 | const enumValue = (_a = getValueFromConfig(name)) !== null && _a !== void 0 ? _a : name;
|
332 | return comment + visitorPluginCommon.indent(`${optionName}: ${visitorPluginCommon.wrapWithSingleQuotes(enumValue)}`);
|
333 | })
|
334 | .join(',\n')).string;
|
335 | return [enumAsConst, typeName].join('\n');
|
336 | }
|
337 | return new visitorPluginCommon.DeclarationBlock(this._declarationBlockConfig)
|
338 | .export()
|
339 | .asKind(this.config.constEnums ? 'const enum' : 'enum')
|
340 | .withName(enumTypeName)
|
341 | .withComment(node.description)
|
342 | .withBlock(this.buildEnumValuesBlock(enumName, node.values)).string;
|
343 | }
|
344 | getPunctuation(_declarationKind) {
|
345 | return ';';
|
346 | }
|
347 | }
|
348 |
|
349 | class TsIntrospectionVisitor extends TsVisitor {
|
350 | constructor(schema, pluginConfig = {}, typesToInclude) {
|
351 | super(schema, pluginConfig);
|
352 | this.typesToInclude = [];
|
353 | this.typesToInclude = typesToInclude;
|
354 | autoBind(this);
|
355 | }
|
356 | DirectiveDefinition() {
|
357 | return null;
|
358 | }
|
359 | ObjectTypeDefinition(node, key, parent) {
|
360 | const name = node.name;
|
361 | if (this.typesToInclude.some(type => type.name === name)) {
|
362 | return super.ObjectTypeDefinition(node, key, parent);
|
363 | }
|
364 | return null;
|
365 | }
|
366 | EnumTypeDefinition(node) {
|
367 | const name = node.name;
|
368 | if (this.typesToInclude.some(type => type.name === name)) {
|
369 | return super.EnumTypeDefinition(node);
|
370 | }
|
371 | return null;
|
372 | }
|
373 | }
|
374 |
|
375 | const plugin = (schema, documents, config) => {
|
376 | const { schema: _schema, ast } = schemaAst.transformSchemaAST(schema, config);
|
377 | const visitor = new TsVisitor(_schema, config);
|
378 | const visitorResult = pluginHelpers.oldVisit(ast, { leave: visitor });
|
379 | const introspectionDefinitions = includeIntrospectionTypesDefinitions(_schema, documents, config);
|
380 | const scalars = visitor.scalarsDefinition;
|
381 | const directiveArgumentAndInputFieldMappings = visitor.directiveArgumentAndInputFieldMappingsDefinition;
|
382 | return {
|
383 | prepend: [
|
384 | ...visitor.getEnumsImports(),
|
385 | ...visitor.getDirectiveArgumentAndInputFieldMappingsImports(),
|
386 | ...visitor.getScalarsImports(),
|
387 | ...visitor.getWrapperDefinitions(),
|
388 | ].filter(Boolean),
|
389 | content: [
|
390 | scalars,
|
391 | directiveArgumentAndInputFieldMappings,
|
392 | ...visitorResult.definitions,
|
393 | ...introspectionDefinitions,
|
394 | ]
|
395 | .filter(Boolean)
|
396 | .join('\n'),
|
397 | };
|
398 | };
|
399 | function includeIntrospectionTypesDefinitions(schema, documents, config) {
|
400 | const typeInfo = new graphql.TypeInfo(schema);
|
401 | const usedTypes = [];
|
402 | const documentsVisitor = graphql.visitWithTypeInfo(typeInfo, {
|
403 | Field() {
|
404 | const type = graphql.getNamedType(typeInfo.getType());
|
405 | if (graphql.isIntrospectionType(type) && !usedTypes.includes(type)) {
|
406 | usedTypes.push(type);
|
407 | }
|
408 | },
|
409 | });
|
410 | documents.forEach(doc => graphql.visit(doc.document, documentsVisitor));
|
411 | const typesToInclude = [];
|
412 | usedTypes.forEach(type => {
|
413 | collectTypes(type);
|
414 | });
|
415 | const visitor = new TsIntrospectionVisitor(schema, config, typesToInclude);
|
416 | const result = pluginHelpers.oldVisit(graphql.parse(graphql.printIntrospectionSchema(schema)), { leave: visitor });
|
417 |
|
418 |
|
419 | function collectTypes(type) {
|
420 | if (typesToInclude.includes(type)) {
|
421 | return;
|
422 | }
|
423 | typesToInclude.push(type);
|
424 | if (graphql.isObjectType(type)) {
|
425 | const fields = type.getFields();
|
426 | Object.keys(fields).forEach(key => {
|
427 | const field = fields[key];
|
428 | const type = graphql.getNamedType(field.type);
|
429 | collectTypes(type);
|
430 | });
|
431 | }
|
432 | }
|
433 | return result.definitions;
|
434 | }
|
435 |
|
436 | exports.EXACT_SIGNATURE = EXACT_SIGNATURE;
|
437 | exports.MAKE_MAYBE_SIGNATURE = MAKE_MAYBE_SIGNATURE;
|
438 | exports.MAKE_OPTIONAL_SIGNATURE = MAKE_OPTIONAL_SIGNATURE;
|
439 | exports.TsIntrospectionVisitor = TsIntrospectionVisitor;
|
440 | exports.TsVisitor = TsVisitor;
|
441 | exports.TypeScriptOperationVariablesToObject = TypeScriptOperationVariablesToObject;
|
442 | exports.includeIntrospectionTypesDefinitions = includeIntrospectionTypesDefinitions;
|
443 | exports.plugin = plugin;
|