@graphql-codegen/java-apollo-android 2.3.0-alpha-a52c122aa.0 → 2.3.0-alpha-bd464a586.0

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.
Files changed (40) hide show
  1. package/cjs/base-java-visitor.js +114 -0
  2. package/cjs/custom-type-class.js +69 -0
  3. package/cjs/field-arguments.js +36 -0
  4. package/cjs/file-type.js +10 -0
  5. package/cjs/imports.js +45 -0
  6. package/cjs/index.js +5 -0
  7. package/cjs/input-type-visitor.js +187 -0
  8. package/cjs/operation-visitor.js +780 -0
  9. package/cjs/package.json +1 -0
  10. package/cjs/plugin.js +48 -0
  11. package/cjs/preset.js +95 -0
  12. package/cjs/types.js +2 -0
  13. package/cjs/visitor-config.js +2 -0
  14. package/esm/base-java-visitor.js +110 -0
  15. package/esm/custom-type-class.js +65 -0
  16. package/esm/field-arguments.js +32 -0
  17. package/esm/file-type.js +7 -0
  18. package/esm/imports.js +42 -0
  19. package/esm/index.js +2 -0
  20. package/esm/input-type-visitor.js +183 -0
  21. package/{index.mjs → esm/operation-visitor.js} +38 -620
  22. package/esm/plugin.js +44 -0
  23. package/esm/preset.js +92 -0
  24. package/esm/types.js +1 -0
  25. package/esm/visitor-config.js +1 -0
  26. package/package.json +24 -17
  27. package/{base-java-visitor.d.ts → typings/base-java-visitor.d.ts} +3 -3
  28. package/{custom-type-class.d.ts → typings/custom-type-class.d.ts} +3 -3
  29. package/{field-arguments.d.ts → typings/field-arguments.d.ts} +1 -1
  30. package/{file-type.d.ts → typings/file-type.d.ts} +0 -0
  31. package/{imports.d.ts → typings/imports.d.ts} +0 -0
  32. package/typings/index.d.ts +2 -0
  33. package/{input-type-visitor.d.ts → typings/input-type-visitor.d.ts} +3 -3
  34. package/{operation-visitor.d.ts → typings/operation-visitor.d.ts} +3 -3
  35. package/{plugin.d.ts → typings/plugin.d.ts} +4 -4
  36. package/{preset.d.ts → typings/preset.d.ts} +0 -0
  37. package/{types.d.ts → typings/types.d.ts} +0 -0
  38. package/{visitor-config.d.ts → typings/visitor-config.d.ts} +0 -0
  39. package/index.d.ts +0 -2
  40. package/index.js +0 -1364
package/index.js DELETED
@@ -1,1364 +0,0 @@
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 javaCommon = require('@graphql-codegen/java-common');
11
- const crypto = require('crypto');
12
- const pluralize = _interopDefault(require('pluralize'));
13
- const changeCaseAll = require('change-case-all');
14
- const path = require('path');
15
-
16
- const Imports = {
17
- // Primitives
18
- String: 'java.lang.String',
19
- Boolean: 'java.lang.Boolean',
20
- Integer: 'java.lang.Integer',
21
- Object: 'java.lang.Object',
22
- Float: 'java.lang.Float',
23
- Long: 'java.lang.Long',
24
- // Java Base
25
- Class: 'java.lang.Class',
26
- Arrays: 'java.util.Arrays',
27
- List: 'java.util.List',
28
- IOException: 'java.io.IOException',
29
- Collections: 'java.util.Collections',
30
- LinkedHashMap: 'java.util.LinkedHashMap',
31
- Map: 'java.util.Map',
32
- // Annotations
33
- Nonnull: 'javax.annotation.Nonnull',
34
- Nullable: 'javax.annotation.Nullable',
35
- Override: 'java.lang.Override',
36
- Generated: 'javax.annotation.Generated',
37
- // Apollo Android
38
- ScalarType: 'com.apollographql.apollo.api.ScalarType',
39
- GraphqlFragment: 'com.apollographql.apollo.api.GraphqlFragment',
40
- Operation: 'com.apollographql.apollo.api.Operation',
41
- OperationName: 'com.apollographql.apollo.api.OperationName',
42
- Mutation: 'com.apollographql.apollo.api.Mutation',
43
- Query: 'com.apollographql.apollo.api.Query',
44
- Subscription: 'com.apollographql.apollo.api.Subscription',
45
- ResponseField: 'com.apollographql.apollo.api.ResponseField',
46
- ResponseFieldMapper: 'com.apollographql.apollo.api.ResponseFieldMapper',
47
- ResponseFieldMarshaller: 'com.apollographql.apollo.api.ResponseFieldMarshaller',
48
- ResponseReader: 'com.apollographql.apollo.api.ResponseReader',
49
- ResponseWriter: 'com.apollographql.apollo.api.ResponseWriter',
50
- FragmentResponseFieldMapper: 'com.apollographql.apollo.api.FragmentResponseFieldMapper',
51
- UnmodifiableMapBuilder: 'com.apollographql.apollo.api.internal.UnmodifiableMapBuilder',
52
- Utils: 'com.apollographql.apollo.api.internal.Utils',
53
- InputType: 'com.apollographql.apollo.api.InputType',
54
- Input: 'com.apollographql.apollo.api.Input',
55
- InputFieldMarshaller: 'com.apollographql.apollo.api.InputFieldMarshaller',
56
- InputFieldWriter: 'com.apollographql.apollo.api.InputFieldWriter',
57
- };
58
-
59
- const SCALAR_TO_WRITER_METHOD = {
60
- ID: 'writeString',
61
- String: 'writeString',
62
- Int: 'writeInt',
63
- Boolean: 'writeBoolean',
64
- Float: 'writeDouble',
65
- };
66
- function isTypeNode(type) {
67
- return type && !!type.kind;
68
- }
69
- class BaseJavaVisitor extends visitorPluginCommon.BaseVisitor {
70
- constructor(_schema, rawConfig, additionalConfig) {
71
- super(rawConfig, {
72
- ...additionalConfig,
73
- scalars: visitorPluginCommon.buildScalars(_schema, { ID: 'String' }, javaCommon.JAVA_SCALARS),
74
- });
75
- this._schema = _schema;
76
- this._imports = new Set();
77
- }
78
- getPackage() {
79
- return '';
80
- }
81
- additionalContent() {
82
- return '';
83
- }
84
- getImports() {
85
- return Array.from(this._imports).map(imp => `import ${imp};`);
86
- }
87
- getImplementingTypes(node) {
88
- const allTypesMap = this._schema.getTypeMap();
89
- const implementingTypes = [];
90
- for (const graphqlType of Object.values(allTypesMap)) {
91
- if (graphqlType instanceof graphql.GraphQLObjectType) {
92
- const allInterfaces = graphqlType.getInterfaces();
93
- if (allInterfaces.find(int => int.name === node.name)) {
94
- implementingTypes.push(graphqlType.name);
95
- }
96
- }
97
- }
98
- return implementingTypes;
99
- }
100
- transformType(type) {
101
- let schemaType;
102
- let isNonNull;
103
- if (isTypeNode(type)) {
104
- const baseTypeNode = visitorPluginCommon.getBaseTypeNode(type);
105
- schemaType = this._schema.getType(baseTypeNode.name.value);
106
- isNonNull = type.kind === graphql.Kind.NON_NULL_TYPE;
107
- }
108
- else {
109
- schemaType = this._schema.getType(pluginHelpers.getBaseType(type).name);
110
- isNonNull = graphql.isNonNullType(type);
111
- }
112
- const javaType = this.getJavaClass(schemaType);
113
- const annotation = isNonNull ? 'Nonnull' : 'Nullable';
114
- const typeToUse = isTypeNode(type)
115
- ? this.getListTypeNodeWrapped(javaType, type)
116
- : this.getListTypeWrapped(javaType, type);
117
- return {
118
- baseType: schemaType.name,
119
- javaType,
120
- isNonNull,
121
- annotation,
122
- typeToUse,
123
- };
124
- }
125
- // Replaces a GraphQL type with a Java class
126
- getJavaClass(schemaType) {
127
- let typeToUse = schemaType.name;
128
- if (graphql.isScalarType(schemaType)) {
129
- const scalar = this.scalars[schemaType.name] || 'Object';
130
- if (Imports[scalar]) {
131
- this._imports.add(Imports[scalar]);
132
- }
133
- typeToUse = scalar;
134
- }
135
- else if (graphql.isInputObjectType(schemaType)) {
136
- // Make sure to import it if it's in use
137
- this._imports.add(`${this.config.typePackage}.${schemaType.name}`);
138
- }
139
- return typeToUse;
140
- }
141
- getListTypeWrapped(toWrap, type) {
142
- if (graphql.isNonNullType(type)) {
143
- return this.getListTypeWrapped(toWrap, type.ofType);
144
- }
145
- if (graphql.isListType(type)) {
146
- const child = this.getListTypeWrapped(toWrap, type.ofType);
147
- this._imports.add(Imports.List);
148
- return `List<${child}>`;
149
- }
150
- return toWrap;
151
- }
152
- getListTypeNodeWrapped(toWrap, type) {
153
- if (type.kind === graphql.Kind.NON_NULL_TYPE) {
154
- return this.getListTypeNodeWrapped(toWrap, type.type);
155
- }
156
- if (type.kind === graphql.Kind.LIST_TYPE) {
157
- const child = this.getListTypeNodeWrapped(toWrap, type.type);
158
- this._imports.add(Imports.List);
159
- return `List<${child}>`;
160
- }
161
- return toWrap;
162
- }
163
- }
164
-
165
- class InputTypeVisitor extends BaseJavaVisitor {
166
- constructor(_schema, rawConfig) {
167
- super(_schema, rawConfig, {
168
- typePackage: rawConfig.typePackage || 'type',
169
- });
170
- }
171
- getPackage() {
172
- return this.config.typePackage;
173
- }
174
- addInputMembers(cls, fields) {
175
- fields.forEach(field => {
176
- const type = this.transformType(field.type);
177
- const actualType = type.isNonNull ? type.typeToUse : `Input<${type.typeToUse}>`;
178
- const annotations = type.isNonNull ? [type.annotation] : [];
179
- this._imports.add(Imports[type.annotation]);
180
- cls.addClassMember(field.name.value, actualType, null, annotations, 'private', { final: true });
181
- cls.addClassMethod(field.name.value, actualType, `return this.${field.name.value};`, [], [type.annotation], 'public');
182
- });
183
- }
184
- addInputCtor(cls, className, fields) {
185
- const impl = fields.map(field => `this.${field.name.value} = ${field.name.value};`).join('\n');
186
- cls.addClassMethod(className, null, impl, fields.map(f => {
187
- const type = this.transformType(f.type);
188
- const actualType = type.isNonNull ? type.typeToUse : `Input<${type.typeToUse}>`;
189
- this._imports.add(Imports[type.annotation]);
190
- return {
191
- name: f.name.value,
192
- type: actualType,
193
- annotations: type.isNonNull ? [type.annotation] : [],
194
- };
195
- }), [], 'public');
196
- }
197
- getFieldWriterCall(field, listItemCall = false) {
198
- const baseType = visitorPluginCommon.getBaseTypeNode(field.type);
199
- const schemaType = this._schema.getType(baseType.name.value);
200
- const isNonNull = field.type.kind === graphql.Kind.NON_NULL_TYPE;
201
- let writerMethod = null;
202
- if (graphql.isScalarType(schemaType)) {
203
- writerMethod = SCALAR_TO_WRITER_METHOD[schemaType.name] || 'writeCustom';
204
- }
205
- else if (graphql.isInputObjectType(schemaType)) {
206
- return listItemCall
207
- ? `writeObject($item.marshaller())`
208
- : `writeObject("${field.name.value}", ${field.name.value}.value != null ? ${field.name.value}.value.marshaller() : null)`;
209
- }
210
- else if (graphql.isEnumType(schemaType)) {
211
- writerMethod = 'writeString';
212
- }
213
- return listItemCall
214
- ? `${writerMethod}($item)`
215
- : `${writerMethod}("${field.name.value}", ${field.name.value}${isNonNull ? '' : '.value'})`;
216
- }
217
- getFieldWithTypePrefix(field, wrapWith = null, applyNullable = false) {
218
- this._imports.add(Imports.Input);
219
- const typeToUse = this.getJavaClass(this._schema.getType(visitorPluginCommon.getBaseTypeNode(field.type).name.value));
220
- const isNonNull = field.type.kind === graphql.Kind.NON_NULL_TYPE;
221
- const name = field.kind === graphql.Kind.INPUT_VALUE_DEFINITION ? field.name.value : field.variable.name.value;
222
- if (isNonNull) {
223
- this._imports.add(Imports.Nonnull);
224
- return `@Nonnull ${typeToUse} ${name}`;
225
- }
226
- else {
227
- if (wrapWith) {
228
- return typeof wrapWith === 'function' ? `${wrapWith(typeToUse)} ${name}` : `${wrapWith}<${typeToUse}> ${name}`;
229
- }
230
- else {
231
- if (applyNullable) {
232
- this._imports.add(Imports.Nullable);
233
- }
234
- return `${applyNullable ? '@Nullable ' : ''}${typeToUse} ${name}`;
235
- }
236
- }
237
- }
238
- buildFieldsMarshaller(field) {
239
- const isNonNull = field.type.kind === graphql.Kind.NON_NULL_TYPE;
240
- const isArray = field.type.kind === graphql.Kind.LIST_TYPE ||
241
- (field.type.kind === graphql.Kind.NON_NULL_TYPE && field.type.type.kind === graphql.Kind.LIST_TYPE);
242
- const call = this.getFieldWriterCall(field, isArray);
243
- const baseTypeNode = visitorPluginCommon.getBaseTypeNode(field.type);
244
- const listItemType = this.getJavaClass(this._schema.getType(baseTypeNode.name.value));
245
- let result = '';
246
- // TODO: Refactor
247
- if (isArray) {
248
- result = `writer.writeList("${field.name.value}", ${field.name.value}.value != null ? new InputFieldWriter.ListWriter() {
249
- @Override
250
- public void write(InputFieldWriter.ListItemWriter listItemWriter) throws IOException {
251
- for (${listItemType} $item : ${field.name.value}.value) {
252
- listItemWriter.${call};
253
- }
254
- }
255
- } : null);`;
256
- }
257
- else {
258
- result = visitorPluginCommon.indent(`writer.${call};`);
259
- }
260
- if (isNonNull) {
261
- return result;
262
- }
263
- else {
264
- return visitorPluginCommon.indentMultiline(`if(${field.name.value}.defined) {
265
- ${visitorPluginCommon.indentMultiline(result)}
266
- }`);
267
- }
268
- }
269
- buildMarshallerOverride(fields) {
270
- this._imports.add(Imports.Override);
271
- this._imports.add(Imports.IOException);
272
- this._imports.add(Imports.InputFieldWriter);
273
- this._imports.add(Imports.InputFieldMarshaller);
274
- const allMarshallers = fields.map(field => visitorPluginCommon.indentMultiline(this.buildFieldsMarshaller(field), 2));
275
- return visitorPluginCommon.indentMultiline(`@Override
276
- public InputFieldMarshaller marshaller() {
277
- return new InputFieldMarshaller() {
278
- @Override
279
- public void marshal(InputFieldWriter writer) throws IOException {
280
- ${allMarshallers.join('\n')}
281
- }
282
- };
283
- }`);
284
- }
285
- buildBuilderNestedClass(className, fields) {
286
- const builderClassName = 'Builder';
287
- const privateFields = fields
288
- .map(field => {
289
- const isArray = field.type.kind === graphql.Kind.LIST_TYPE ||
290
- (field.type.kind === graphql.Kind.NON_NULL_TYPE && field.type.type.kind === graphql.Kind.LIST_TYPE);
291
- const fieldType = this.getFieldWithTypePrefix(field, v => (!isArray ? `Input<${v}>` : `Input<List<${v}>>`));
292
- const isNonNull = field.type.kind === graphql.Kind.NON_NULL_TYPE;
293
- return `private ${fieldType}${isNonNull ? '' : ' = Input.absent()'};`;
294
- })
295
- .map(s => visitorPluginCommon.indent(s));
296
- const setters = fields
297
- .map(field => {
298
- const isArray = field.type.kind === graphql.Kind.LIST_TYPE ||
299
- (field.type.kind === graphql.Kind.NON_NULL_TYPE && field.type.type.kind === graphql.Kind.LIST_TYPE);
300
- const fieldType = this.getFieldWithTypePrefix(field, isArray ? 'List' : null);
301
- const isNonNull = field.type.kind === graphql.Kind.NON_NULL_TYPE;
302
- return `\npublic ${builderClassName} ${field.name.value}(${isNonNull ? '' : '@Nullable '}${fieldType}) {
303
- this.${field.name.value} = ${isNonNull ? field.name.value : `Input.fromNullable(${field.name.value})`};
304
- return this;
305
- }`;
306
- })
307
- .map(s => visitorPluginCommon.indentMultiline(s));
308
- const nonNullFields = fields
309
- .filter(f => f.type.kind === graphql.Kind.NON_NULL_TYPE)
310
- .map(nnField => {
311
- this._imports.add(Imports.Utils);
312
- return visitorPluginCommon.indent(`Utils.checkNotNull(${nnField.name.value}, "${nnField.name.value} == null");`, 1);
313
- });
314
- const ctor = '\n' + visitorPluginCommon.indent(`${builderClassName}() {}`);
315
- const buildFn = visitorPluginCommon.indentMultiline(`public ${className} build() {
316
- ${nonNullFields.join('\n')}
317
- return new ${className}(${fields.map(f => f.name.value).join(', ')});
318
- }`);
319
- const body = [...privateFields, ctor, ...setters, '', buildFn].join('\n');
320
- return visitorPluginCommon.indentMultiline(new javaCommon.JavaDeclarationBlock()
321
- .withName(builderClassName)
322
- .access('public')
323
- .final()
324
- .static()
325
- .withBlock(body)
326
- .asKind('class').string);
327
- }
328
- InputObjectTypeDefinition(node) {
329
- const className = node.name.value;
330
- this._imports.add(Imports.InputType);
331
- this._imports.add(Imports.Generated);
332
- const cls = new javaCommon.JavaDeclarationBlock()
333
- .annotate([`Generated("Apollo GraphQL")`])
334
- .access('public')
335
- .final()
336
- .asKind('class')
337
- .withName(className)
338
- .implements(['InputType']);
339
- this.addInputMembers(cls, node.fields);
340
- this.addInputCtor(cls, className, node.fields);
341
- cls.addClassMethod('builder', 'Builder', 'return new Builder();', [], [], 'public', { static: true });
342
- const marshallerOverride = this.buildMarshallerOverride(node.fields);
343
- const builderClass = this.buildBuilderNestedClass(className, node.fields);
344
- const classBlock = [marshallerOverride, '', builderClass].join('\n');
345
- cls.withBlock(classBlock);
346
- return cls.string;
347
- }
348
- }
349
-
350
- function visitFieldArguments(selection, imports) {
351
- if (!selection.arguments || selection.arguments.length === 0) {
352
- return 'null';
353
- }
354
- imports.add(Imports.UnmodifiableMapBuilder);
355
- imports.add(Imports.String);
356
- imports.add(Imports.Object);
357
- return pluginHelpers.oldVisit(selection, {
358
- leave: {
359
- Field: (node) => {
360
- return (`new UnmodifiableMapBuilder<String, Object>(${node.arguments.length})` + node.arguments.join('') + '.build()');
361
- },
362
- Argument: (node) => {
363
- return `.put("${node.name.value}", ${node.value})`;
364
- },
365
- ObjectValue: (node) => {
366
- return `new UnmodifiableMapBuilder<String, Object>(${node.fields.length})` + node.fields.join('') + '.build()';
367
- },
368
- ObjectField: (node) => {
369
- return `.put("${node.name.value}", ${node.value})`;
370
- },
371
- Variable: (node) => {
372
- return `new UnmodifiableMapBuilder<String, Object>(2).put("kind", "Variable").put("variableName", "${node.name.value}").build()`;
373
- },
374
- StringValue: (node) => `"${node.value}"`,
375
- IntValue: (node) => `"${node.value}"`,
376
- FloatValue: (node) => `"${node.value}"`,
377
- },
378
- });
379
- }
380
-
381
- const { singular, isPlural } = pluralize;
382
- class OperationVisitor extends BaseJavaVisitor {
383
- constructor(_schema, rawConfig, _availableFragments) {
384
- super(_schema, rawConfig, {
385
- package: rawConfig.package || javaCommon.buildPackageNameFromPath(process.cwd()),
386
- fragmentPackage: rawConfig.fragmentPackage || 'fragment',
387
- typePackage: rawConfig.typePackage || 'type',
388
- });
389
- this._availableFragments = _availableFragments;
390
- this.visitingFragment = false;
391
- }
392
- printDocument(node) {
393
- return graphql.print(node)
394
- .replace(/\r?\n|\r/g, ' ')
395
- .replace(/"/g, '\\"')
396
- .trim();
397
- }
398
- getPackage() {
399
- return this.visitingFragment ? this.config.fragmentPackage : this.config.package;
400
- }
401
- addCtor(className, node, cls) {
402
- const variables = node.variableDefinitions || [];
403
- const hasVariables = variables.length > 0;
404
- const nonNullVariables = variables
405
- .filter(v => v.type.kind === graphql.Kind.NON_NULL_TYPE)
406
- .map(v => {
407
- this._imports.add(Imports.Utils);
408
- return `Utils.checkNotNull(${v.variable.name.value}, "${v.variable.name.value} == null");`;
409
- });
410
- const impl = [
411
- ...nonNullVariables,
412
- `this.variables = ${!hasVariables
413
- ? 'Operation.EMPTY_VARIABLES'
414
- : `new ${className}.Variables(${variables.map(v => v.variable.name.value).join(', ')})`};`,
415
- ].join('\n');
416
- cls.addClassMethod(className, null, impl, node.variableDefinitions.map(varDec => {
417
- const outputType = visitorPluginCommon.getBaseTypeNode(varDec.type).name.value;
418
- const schemaType = this._schema.getType(outputType);
419
- const javaClass = this.getJavaClass(schemaType);
420
- const typeToUse = this.getListTypeNodeWrapped(javaClass, varDec.type);
421
- const isNonNull = varDec.type.kind === graphql.Kind.NON_NULL_TYPE;
422
- return {
423
- name: varDec.variable.name.value,
424
- type: typeToUse,
425
- annotations: [isNonNull ? 'Nonnull' : 'Nullable'],
426
- };
427
- }), null, 'public');
428
- }
429
- getRootType(operation) {
430
- if (operation === 'query') {
431
- return this._schema.getQueryType();
432
- }
433
- else if (operation === 'mutation') {
434
- return this._schema.getMutationType();
435
- }
436
- else if (operation === 'subscription') {
437
- return this._schema.getSubscriptionType();
438
- }
439
- else {
440
- return null;
441
- }
442
- }
443
- createUniqueClassName(inUse, name, count = 0) {
444
- const possibleNewName = count === 0 ? name : `${name}${count}`;
445
- while (inUse.includes(possibleNewName)) {
446
- return this.createUniqueClassName(inUse, name, count + 1);
447
- }
448
- return possibleNewName;
449
- }
450
- transformSelectionSet(options, isRoot = true) {
451
- if (!options.result) {
452
- options.result = {};
453
- }
454
- if (!graphql.isObjectType(options.schemaType) && !graphql.isInterfaceType(options.schemaType)) {
455
- return options.result;
456
- }
457
- const className = this.createUniqueClassName(Object.keys(options.result), options.className);
458
- const cls = new javaCommon.JavaDeclarationBlock()
459
- .access('public')
460
- .asKind('class')
461
- .withName(className)
462
- .implements(options.implements || []);
463
- if (!options.nonStaticClass) {
464
- cls.static();
465
- }
466
- options.result[className] = cls;
467
- const fields = options.schemaType.getFields();
468
- const childFields = [...(options.additionalFields || [])];
469
- const childInlineFragments = [];
470
- const childFragmentSpread = [...(options.additionalFragments || [])];
471
- const selections = [...(options.selectionSet || [])];
472
- const responseFieldArr = [];
473
- for (const selection of selections) {
474
- if (selection.kind === graphql.Kind.FIELD) {
475
- this._imports.add(Imports.ResponseField);
476
- const field = fields[selection.name.value];
477
- const isObject = selection.selectionSet && selection.selectionSet.selections && selection.selectionSet.selections.length > 0;
478
- const isNonNull = graphql.isNonNullType(field.type);
479
- const fieldAnnotation = isNonNull ? 'Nonnull' : 'Nullable';
480
- this._imports.add(Imports[fieldAnnotation]);
481
- const baseType = pluginHelpers.getBaseType(field.type);
482
- const isList = graphql.isListType(field.type) || (graphql.isNonNullType(field.type) && graphql.isListType(field.type.ofType));
483
- if (isObject) {
484
- let childClsName = this.convertName(field.name);
485
- if (isList && isPlural(childClsName)) {
486
- childClsName = singular(childClsName);
487
- }
488
- this.transformSelectionSet({
489
- className: childClsName,
490
- result: options.result,
491
- selectionSet: selection.selectionSet.selections,
492
- schemaType: baseType,
493
- }, false);
494
- childFields.push({
495
- rawType: field.type,
496
- isObject: true,
497
- isList,
498
- isFragment: false,
499
- type: baseType,
500
- isNonNull,
501
- annotation: fieldAnnotation,
502
- className: childClsName,
503
- fieldName: field.name,
504
- });
505
- }
506
- else {
507
- const javaClass = this.getJavaClass(baseType);
508
- childFields.push({
509
- rawType: field.type,
510
- isObject: false,
511
- isFragment: false,
512
- isList: isList,
513
- type: baseType,
514
- isNonNull,
515
- annotation: fieldAnnotation,
516
- className: javaClass,
517
- fieldName: field.name,
518
- });
519
- }
520
- this._imports.add(Imports.ResponseField);
521
- this._imports.add(Imports.Collections);
522
- const operationArgs = visitFieldArguments(selection, this._imports);
523
- const responseFieldMethod = this._resolveResponseFieldMethodForBaseType(field.type);
524
- responseFieldArr.push(`ResponseField.${responseFieldMethod.fn}("${selection.alias ? selection.alias.value : selection.name.value}", "${selection.name.value}", ${operationArgs}, ${!graphql.isNonNullType(field.type)},${responseFieldMethod.custom ? ` CustomType.${baseType.name},` : ''} Collections.<ResponseField.Condition>emptyList())`);
525
- }
526
- else if (selection.kind === graphql.Kind.INLINE_FRAGMENT) {
527
- if (graphql.isUnionType(options.schemaType) || graphql.isInterfaceType(options.schemaType)) {
528
- childInlineFragments.push({
529
- onType: selection.typeCondition.name.value,
530
- node: selection,
531
- });
532
- }
533
- else {
534
- selections.push(...selection.selectionSet.selections);
535
- }
536
- }
537
- else if (selection.kind === graphql.Kind.FRAGMENT_SPREAD) {
538
- const fragment = this._availableFragments.find(f => f.name === selection.name.value);
539
- if (fragment) {
540
- childFragmentSpread.push(fragment);
541
- this._imports.add(`${this.config.fragmentPackage}.${fragment.name}`);
542
- }
543
- else {
544
- throw new Error(`Fragment with name ${selection.name.value} was not loaded as document!`);
545
- }
546
- }
547
- }
548
- if (childInlineFragments.length > 0) {
549
- const childFieldsBase = [...childFields];
550
- childFields.push(...childInlineFragments.map(inlineFragment => {
551
- const cls = `As${inlineFragment.onType}`;
552
- const schemaType = this._schema.getType(inlineFragment.onType);
553
- this.transformSelectionSet({
554
- additionalFields: childFieldsBase,
555
- additionalFragments: childFragmentSpread,
556
- className: cls,
557
- result: options.result,
558
- selectionSet: inlineFragment.node.selectionSet.selections,
559
- schemaType,
560
- }, false);
561
- this._imports.add(Imports.Nullable);
562
- return {
563
- isFragment: false,
564
- rawType: schemaType,
565
- isObject: true,
566
- isList: false,
567
- type: schemaType,
568
- isNonNull: false,
569
- annotation: 'Nullable',
570
- className: cls,
571
- fieldName: `as${inlineFragment.onType}`,
572
- };
573
- }));
574
- responseFieldArr.push(...childInlineFragments.map(f => {
575
- this._imports.add(Imports.Arrays);
576
- return `ResponseField.forInlineFragment("__typename", "__typename", Arrays.asList("${f.onType}"))`;
577
- }));
578
- }
579
- if (childFragmentSpread.length > 0) {
580
- responseFieldArr.push(`ResponseField.forFragment("__typename", "__typename", Arrays.asList(${childFragmentSpread
581
- .map(f => `"${f.onType}"`)
582
- .join(', ')}))`);
583
- this._imports.add(Imports.ResponseField);
584
- this._imports.add(Imports.Nonnull);
585
- this._imports.add(Imports.Arrays);
586
- const fragmentsClassName = 'Fragments';
587
- childFields.push({
588
- isObject: true,
589
- isList: false,
590
- isFragment: true,
591
- rawType: options.schemaType,
592
- type: options.schemaType,
593
- isNonNull: true,
594
- annotation: 'Nonnull',
595
- className: fragmentsClassName,
596
- fieldName: 'fragments',
597
- });
598
- const fragmentsClass = new javaCommon.JavaDeclarationBlock()
599
- .withName(fragmentsClassName)
600
- .access('public')
601
- .static()
602
- .final()
603
- .asKind('class');
604
- const fragmentMapperClass = new javaCommon.JavaDeclarationBlock()
605
- .withName('Mapper')
606
- .access('public')
607
- .static()
608
- .final()
609
- .implements([`FragmentResponseFieldMapper<${fragmentsClassName}>`])
610
- .asKind('class');
611
- fragmentsClass.addClassMethod(fragmentsClassName, null, childFragmentSpread
612
- .map(spread => {
613
- const varName = changeCaseAll.camelCase(spread.name);
614
- this._imports.add(Imports.Utils);
615
- return `this.${varName} = Utils.checkNotNull(${varName}, "${varName} == null");`;
616
- })
617
- .join('\n'), childFragmentSpread.map(spread => ({
618
- name: changeCaseAll.camelCase(spread.name),
619
- type: spread.name,
620
- annotations: ['Nonnull'],
621
- })), [], 'public');
622
- for (const spread of childFragmentSpread) {
623
- const fragmentVarName = changeCaseAll.camelCase(spread.name);
624
- fragmentsClass.addClassMember(fragmentVarName, spread.name, null, ['Nonnull'], 'private', { final: true });
625
- fragmentsClass.addClassMethod(fragmentVarName, spread.name, `return this.${fragmentVarName};`, [], ['Nonnull'], 'public', {}, []);
626
- fragmentMapperClass.addClassMember(`${fragmentVarName}FieldMapper`, `${spread.name}.Mapper`, `new ${spread.name}.Mapper()`, [], 'private', { final: true });
627
- }
628
- fragmentMapperClass.addClassMethod('map', fragmentsClassName, `
629
- ${childFragmentSpread
630
- .map(spread => {
631
- const fragmentVarName = changeCaseAll.camelCase(spread.name);
632
- return `${spread.name} ${fragmentVarName} = null;
633
- if (${spread.name}.POSSIBLE_TYPES.contains(conditionalType)) {
634
- ${fragmentVarName} = ${fragmentVarName}FieldMapper.map(reader);
635
- }`;
636
- })
637
- .join('\n')}
638
-
639
- return new Fragments(${childFragmentSpread
640
- .map(spread => {
641
- const fragmentVarName = changeCaseAll.camelCase(spread.name);
642
- return `Utils.checkNotNull(${fragmentVarName}, "${fragmentVarName} == null")`;
643
- })
644
- .join(', ')});
645
- `, [
646
- {
647
- name: 'reader',
648
- type: 'ResponseReader',
649
- },
650
- {
651
- name: 'conditionalType',
652
- type: 'String',
653
- annotations: ['Nonnull'],
654
- },
655
- ], ['Nonnull'], 'public', {}, ['Override']);
656
- this._imports.add(Imports.String);
657
- this._imports.add(Imports.ResponseReader);
658
- this._imports.add(Imports.ResponseFieldMarshaller);
659
- this._imports.add(Imports.ResponseWriter);
660
- fragmentsClass.addClassMethod('marshaller', 'ResponseFieldMarshaller', `return new ResponseFieldMarshaller() {
661
- @Override
662
- public void marshal(ResponseWriter writer) {
663
- ${childFragmentSpread
664
- .map(spread => {
665
- const fragmentVarName = changeCaseAll.camelCase(spread.name);
666
- return visitorPluginCommon.indentMultiline(`final ${spread.name} $${fragmentVarName} = ${fragmentVarName};\nif ($${fragmentVarName} != null) { $${fragmentVarName}.marshaller().marshal(writer); }`, 2);
667
- })
668
- .join('\n')}
669
- }
670
- };
671
- `, [], [], 'public');
672
- fragmentsClass.addClassMember('$toString', 'String', null, [], 'private', { volatile: true });
673
- fragmentsClass.addClassMember('$hashCode', 'int', null, [], 'private', { volatile: true });
674
- fragmentsClass.addClassMember('$hashCodeMemoized', 'boolean', null, [], 'private', { volatile: true });
675
- fragmentsClass.addClassMethod('toString', 'String', `if ($toString == null) {
676
- $toString = "${fragmentsClassName}{"
677
- ${childFragmentSpread
678
- .map(spread => {
679
- const varName = changeCaseAll.camelCase(spread.name);
680
- return visitorPluginCommon.indent(`+ "${varName}=" + ${varName} + ", "`, 2);
681
- })
682
- .join('\n')}
683
- + "}";
684
- }
685
-
686
- return $toString;`, [], [], 'public', {}, ['Override']);
687
- // Add equals
688
- fragmentsClass.addClassMethod('equals', 'boolean', `if (o == this) {
689
- return true;
690
- }
691
- if (o instanceof ${fragmentsClassName}) {
692
- ${fragmentsClassName} that = (${fragmentsClassName}) o;
693
- return ${childFragmentSpread
694
- .map(spread => {
695
- const varName = changeCaseAll.camelCase(spread.name);
696
- return `this.${varName}.equals(that.${varName})`;
697
- })
698
- .join(' && ')};
699
- }
700
-
701
- return false;`, [{ name: 'o', type: 'Object' }], [], 'public', {}, ['Override']);
702
- // hashCode
703
- fragmentsClass.addClassMethod('hashCode', 'int', `if (!$hashCodeMemoized) {
704
- int h = 1;
705
- ${childFragmentSpread
706
- .map(spread => {
707
- const varName = changeCaseAll.camelCase(spread.name);
708
- return visitorPluginCommon.indentMultiline(`h *= 1000003;\nh ^= ${varName}.hashCode();`, 1);
709
- })
710
- .join('\n')}
711
- $hashCode = h;
712
- $hashCodeMemoized = true;
713
- }
714
-
715
- return $hashCode;`, [], [], 'public', {}, ['Override']);
716
- this._imports.add(Imports.FragmentResponseFieldMapper);
717
- fragmentsClass.nestedClass(fragmentMapperClass);
718
- cls.nestedClass(fragmentsClass);
719
- }
720
- if (responseFieldArr.length > 0 && !isRoot) {
721
- responseFieldArr.unshift(`ResponseField.forString("__typename", "__typename", null, false, Collections.<ResponseField.Condition>emptyList())`);
722
- }
723
- if (!isRoot) {
724
- this._imports.add(Imports.Nonnull);
725
- childFields.unshift({
726
- isObject: false,
727
- isFragment: false,
728
- isList: false,
729
- type: graphql.GraphQLString,
730
- rawType: graphql.GraphQLString,
731
- isNonNull: true,
732
- annotation: 'Nonnull',
733
- className: 'String',
734
- fieldName: '__typename',
735
- });
736
- }
737
- // Add members
738
- childFields.forEach(c => {
739
- cls.addClassMember(c.fieldName, this.getListTypeWrapped(c.className, c.rawType), null, [c.annotation], 'private', { final: true });
740
- });
741
- // Add $toString, $hashCode, $hashCodeMemoized
742
- cls.addClassMember('$toString', 'String', null, [], 'private', { volatile: true });
743
- cls.addClassMember('$hashCode', 'int', null, [], 'private', { volatile: true });
744
- cls.addClassMember('$hashCodeMemoized', 'boolean', null, [], 'private', { volatile: true });
745
- // Add responseFields for all fields
746
- cls.addClassMember('$responseFields', 'ResponseField[]', `{\n${visitorPluginCommon.indentMultiline(responseFieldArr.join(',\n'), 2) + '\n }'}`, [], null, { static: true, final: true });
747
- // Add Ctor
748
- this._imports.add(Imports.Utils);
749
- cls.addClassMethod(className, null, childFields
750
- .map(c => `this.${c.fieldName} = ${c.isNonNull ? `Utils.checkNotNull(${c.fieldName}, "${c.fieldName} == null")` : c.fieldName};`)
751
- .join('\n'), childFields.map(c => ({
752
- name: c.fieldName,
753
- type: this.getListTypeWrapped(c.className, c.rawType),
754
- annotations: [c.annotation],
755
- })), null, 'public');
756
- // Add getters for all members
757
- childFields.forEach(c => {
758
- cls.addClassMethod(c.fieldName, this.getListTypeWrapped(c.className, c.rawType), `return this.${c.fieldName};`, [], [c.annotation], 'public', {});
759
- });
760
- // Add .toString()
761
- cls.addClassMethod('toString', 'String', `if ($toString == null) {
762
- $toString = "${className}{"
763
- ${childFields.map(c => visitorPluginCommon.indent(`+ "${c.fieldName}=" + ${c.fieldName} + ", "`, 2)).join('\n')}
764
- + "}";
765
- }
766
-
767
- return $toString;`, [], [], 'public', {}, ['Override']);
768
- // Add equals
769
- cls.addClassMethod('equals', 'boolean', `if (o == this) {
770
- return true;
771
- }
772
- if (o instanceof ${className}) {
773
- ${className} that = (${className}) o;
774
- return ${childFields
775
- .map(c => c.isNonNull
776
- ? `this.${c.fieldName}.equals(that.${c.fieldName})`
777
- : `((this.${c.fieldName} == null) ? (that.${c.fieldName} == null) : this.${c.fieldName}.equals(that.${c.fieldName}))`)
778
- .join(' && ')};
779
- }
780
-
781
- return false;`, [{ name: 'o', type: 'Object' }], [], 'public', {}, ['Override']);
782
- // hashCode
783
- cls.addClassMethod('hashCode', 'int', `if (!$hashCodeMemoized) {
784
- int h = 1;
785
- ${childFields
786
- .map(f => visitorPluginCommon.indentMultiline(`h *= 1000003;\nh ^= ${!f.isNonNull ? `(${f.fieldName} == null) ? 0 : ` : ''}${f.fieldName}.hashCode();`, 1))
787
- .join('\n')}
788
- $hashCode = h;
789
- $hashCodeMemoized = true;
790
- }
791
-
792
- return $hashCode;`, [], [], 'public', {}, ['Override']);
793
- this._imports.add(Imports.ResponseReader);
794
- this._imports.add(Imports.ResponseFieldMarshaller);
795
- this._imports.add(Imports.ResponseWriter);
796
- // marshaller
797
- cls.addClassMethod('marshaller', 'ResponseFieldMarshaller', `return new ResponseFieldMarshaller() {
798
- @Override
799
- public void marshal(ResponseWriter writer) {
800
- ${childFields
801
- .map((f, index) => {
802
- const writerMethod = this._getWriterMethodByType(f.type);
803
- if (f.isList) {
804
- return visitorPluginCommon.indentMultiline(`writer.writeList($responseFields[${index}], ${f.fieldName}, new ResponseWriter.ListWriter() {
805
- @Override
806
- public void write(Object value, ResponseWriter.ListItemWriter listItemWriter) {
807
- listItemWriter.${writerMethod.name}(((${f.className}) value)${writerMethod.useMarshaller ? '.marshaller()' : ''});
808
- }
809
- });`, 2);
810
- }
811
- let fValue = `${f.fieldName}${writerMethod.useMarshaller ? '.marshaller()' : ''}`;
812
- if (writerMethod.checkNull || !f.isNonNull) {
813
- fValue = `${f.fieldName} != null ? ${fValue} : null`;
814
- }
815
- return visitorPluginCommon.indent(`writer.${writerMethod.name}(${writerMethod.castTo ? `(${writerMethod.castTo}) ` : ''}$responseFields[${index}], ${fValue});`, 2);
816
- })
817
- .join('\n')}
818
- }
819
- };`, [], [], 'public');
820
- cls.nestedClass(this.buildMapperClass(className, childFields));
821
- return options.result;
822
- }
823
- getReaderFn(baseType) {
824
- if (graphql.isScalarType(baseType)) {
825
- if (baseType.name === 'String') {
826
- return { fn: `readString` };
827
- }
828
- else if (baseType.name === 'Int') {
829
- return { fn: `readInt` };
830
- }
831
- else if (baseType.name === 'Float') {
832
- return { fn: `readDouble` };
833
- }
834
- else if (baseType.name === 'Boolean') {
835
- return { fn: `readBoolean` };
836
- }
837
- else {
838
- return { fn: `readCustomType`, custom: true };
839
- }
840
- }
841
- else if (graphql.isEnumType(baseType)) {
842
- return { fn: `readString` };
843
- }
844
- else {
845
- return { fn: `readObject`, object: baseType.name };
846
- }
847
- }
848
- buildMapperClass(parentClassName, childFields) {
849
- const wrapList = (childField, rawType, edgeStr) => {
850
- if (graphql.isNonNullType(rawType)) {
851
- return wrapList(childField, rawType.ofType, edgeStr);
852
- }
853
- if (graphql.isListType(rawType)) {
854
- const typeStr = this.getListTypeWrapped(childField.className, rawType.ofType);
855
- const innerContent = wrapList(childField, rawType.ofType, edgeStr);
856
- const inner = graphql.isListType(rawType.ofType) ? `return listItemReader.readList(${innerContent});` : innerContent;
857
- return `new ResponseReader.ListReader<${typeStr}>() {
858
- @Override
859
- public ${typeStr} read(ResponseReader.ListItemReader listItemReader) {
860
- ${visitorPluginCommon.indentMultiline(inner, 2)}
861
- }
862
- }`;
863
- }
864
- return edgeStr;
865
- };
866
- this._imports.add(Imports.ResponseReader);
867
- const mapperBody = childFields.map((f, index) => {
868
- const varDec = `final ${this.getListTypeWrapped(f.className, f.rawType)} ${f.fieldName} =`;
869
- const readerFn = this.getReaderFn(f.type);
870
- if (f.isFragment) {
871
- return `${varDec} reader.readConditional($responseFields[${index}], new ResponseReader.ConditionalTypeReader<${f.className}>() {
872
- @Override
873
- public ${f.className} read(String conditionalType, ResponseReader reader) {
874
- return fragmentsFieldMapper.map(reader, conditionalType);
875
- }
876
- });`;
877
- }
878
- else if (f.isList) {
879
- const listReader = readerFn.object
880
- ? `return listItemReader.${readerFn.fn}(new ResponseReader.ObjectReader<Item>() {
881
- @Override
882
- public Item read(ResponseReader reader) {
883
- return ${f.fieldName}FieldMapper.map(reader);
884
- }
885
- });`
886
- : `return listItemReader.${readerFn.fn}();`;
887
- const wrappedList = wrapList(f, f.rawType, listReader);
888
- return `${varDec} reader.readList($responseFields[${index}], ${wrappedList});`;
889
- }
890
- else if (readerFn.object) {
891
- return `${varDec} reader.readObject($responseFields[${index}], new ResponseReader.ObjectReader<${f.className}>() {
892
- @Override
893
- public ${f.className} read(ResponseReader reader) {
894
- return ${f.fieldName}FieldMapper.map(reader);
895
- }
896
- });`;
897
- }
898
- else {
899
- return `${varDec} reader.${readerFn.fn}(${readerFn.custom ? '(ResponseField.CustomTypeField) ' : ''}$responseFields[${index}]);`;
900
- }
901
- });
902
- const mapperImpl = [
903
- ...mapperBody,
904
- `return new ${parentClassName}(${childFields.map(f => f.fieldName).join(', ')});`,
905
- ].join('\n');
906
- const cls = new javaCommon.JavaDeclarationBlock()
907
- .access('public')
908
- .static()
909
- .final()
910
- .asKind('class')
911
- .withName('Mapper')
912
- .implements([`ResponseFieldMapper<${parentClassName}>`])
913
- .addClassMethod('map', parentClassName, mapperImpl, [
914
- {
915
- name: 'reader',
916
- type: 'ResponseReader',
917
- },
918
- ], [], 'public', {}, ['Override']);
919
- childFields
920
- .filter(c => c.isObject)
921
- .forEach(childField => {
922
- cls.addClassMember(`${childField.fieldName}FieldMapper`, `${childField.className}.Mapper`, `new ${childField.className}.Mapper()`, [], 'private', { final: true });
923
- });
924
- return cls;
925
- }
926
- _resolveResponseFieldMethodForBaseType(baseType) {
927
- if (graphql.isListType(baseType)) {
928
- return { fn: `forList` };
929
- }
930
- else if (graphql.isNonNullType(baseType)) {
931
- return this._resolveResponseFieldMethodForBaseType(baseType.ofType);
932
- }
933
- else if (graphql.isScalarType(baseType)) {
934
- if (baseType.name === 'String') {
935
- return { fn: `forString` };
936
- }
937
- else if (baseType.name === 'Int') {
938
- return { fn: `forInt` };
939
- }
940
- else if (baseType.name === 'Float') {
941
- return { fn: `forDouble` };
942
- }
943
- else if (baseType.name === 'Boolean') {
944
- return { fn: `forBoolean` };
945
- }
946
- else {
947
- this._imports.add(`${this.config.typePackage}.CustomType`);
948
- return { fn: `forCustomType`, custom: true };
949
- }
950
- }
951
- else if (graphql.isEnumType(baseType)) {
952
- return { fn: `forEnum` };
953
- }
954
- else {
955
- return { fn: `forObject` };
956
- }
957
- }
958
- FragmentDefinition(node) {
959
- this.visitingFragment = true;
960
- const className = node.name.value;
961
- const schemaType = this._schema.getType(node.typeCondition.name.value);
962
- this._imports.add(Imports.Arrays);
963
- this._imports.add(Imports.GraphqlFragment);
964
- this._imports.add(Imports.List);
965
- this._imports.add(Imports.String);
966
- this._imports.add(Imports.Collections);
967
- this._imports.add(Imports.Override);
968
- this._imports.add(Imports.Generated);
969
- this._imports.add(Imports.ResponseFieldMapper);
970
- const dataClasses = this.transformSelectionSet({
971
- className: className,
972
- nonStaticClass: true,
973
- implements: ['GraphqlFragment'],
974
- selectionSet: node.selectionSet && node.selectionSet.selections ? node.selectionSet.selections : [],
975
- result: {},
976
- schemaType: schemaType,
977
- }, false);
978
- const rootCls = dataClasses[className];
979
- const printed = this.printDocument(node);
980
- rootCls.addClassMember('FRAGMENT_DEFINITION', 'String', `"${printed}"`, [], 'public', {
981
- static: true,
982
- final: true,
983
- });
984
- const possibleTypes = graphql.isObjectType(schemaType) ? [schemaType.name] : this.getImplementingTypes(schemaType);
985
- rootCls.addClassMember('POSSIBLE_TYPES', 'List<String>', `Collections.unmodifiableList(Arrays.asList(${possibleTypes.map(t => `"${t}"`).join(', ')}))`, [], 'public', { static: true, final: true });
986
- Object.keys(dataClasses)
987
- .filter(name => name !== className)
988
- .forEach(clsName => {
989
- rootCls.nestedClass(dataClasses[clsName]);
990
- });
991
- return rootCls.string;
992
- }
993
- OperationDefinition(node) {
994
- this.visitingFragment = false;
995
- const operationType = changeCaseAll.pascalCase(node.operation);
996
- const operationSchemaType = this.getRootType(node.operation);
997
- const className = node.name.value.endsWith(operationType) ? operationType : `${node.name.value}${operationType}`;
998
- this._imports.add(Imports[operationType]);
999
- this._imports.add(Imports.String);
1000
- this._imports.add(Imports.Override);
1001
- this._imports.add(Imports.Generated);
1002
- this._imports.add(Imports.OperationName);
1003
- this._imports.add(Imports.Operation);
1004
- this._imports.add(Imports.ResponseFieldMapper);
1005
- const cls = new javaCommon.JavaDeclarationBlock()
1006
- .annotate([`Generated("Apollo GraphQL")`])
1007
- .access('public')
1008
- .final()
1009
- .asKind('class')
1010
- .withName(className);
1011
- const printed = this.printDocument(node);
1012
- cls.implements([
1013
- `${operationType}<${className}.Data, ${className}.Data, ${node.variableDefinitions.length === 0 ? 'Operation' : className}.Variables>`,
1014
- ]);
1015
- cls.addClassMember('OPERATION_DEFINITION', 'String', `"${printed}"`, [], 'public', { static: true, final: true });
1016
- cls.addClassMember('QUERY_DOCUMENT', 'String', 'OPERATION_DEFINITION', [], 'public', { static: true, final: true });
1017
- cls.addClassMember('OPERATION_NAME', 'OperationName', `new OperationName() {
1018
- @Override
1019
- public String name() {
1020
- return "${node.name.value}";
1021
- }
1022
- }`, [], 'public', { static: true, final: true });
1023
- cls.addClassMember('variables', `${node.variableDefinitions.length === 0 ? 'Operation' : className}.Variables`, null, [], 'private', { final: true });
1024
- cls.addClassMethod('queryDocument', `String`, `return QUERY_DOCUMENT;`, [], [], 'public', {}, ['Override']);
1025
- cls.addClassMethod('wrapData', `${className}.Data`, `return data;`, [
1026
- {
1027
- name: 'data',
1028
- type: `${className}.Data`,
1029
- },
1030
- ], [], 'public', {}, ['Override']);
1031
- cls.addClassMethod('variables', `${node.variableDefinitions.length === 0 ? 'Operation' : className}.Variables`, `return variables;`, [], [], 'public', {}, ['Override']);
1032
- cls.addClassMethod('responseFieldMapper', `ResponseFieldMapper<${className}.Data>`, `return new Data.Mapper();`, [], [], 'public', {}, ['Override']);
1033
- cls.addClassMethod('builder', `Builder`, `return new Builder();`, [], [], 'public', { static: true }, []);
1034
- cls.addClassMethod('name', `OperationName`, `return OPERATION_NAME;`, [], [], 'public', {}, ['Override']);
1035
- cls.addClassMethod('operationId', `String`, `return "${crypto.createHash('md5').update(printed).digest('hex')}";`, [], [], 'public', {}, []);
1036
- this.addCtor(className, node, cls);
1037
- this._imports.add(Imports.Operation);
1038
- const dataClasses = this.transformSelectionSet({
1039
- className: 'Data',
1040
- implements: ['Operation.Data'],
1041
- selectionSet: node.selectionSet && node.selectionSet.selections ? node.selectionSet.selections : [],
1042
- result: {},
1043
- schemaType: operationSchemaType,
1044
- });
1045
- Object.keys(dataClasses).forEach(className => {
1046
- cls.nestedClass(dataClasses[className]);
1047
- });
1048
- cls.nestedClass(this.createBuilderClass(className, node.variableDefinitions || []));
1049
- cls.nestedClass(this.createVariablesClass(className, node.variableDefinitions || []));
1050
- return cls.string;
1051
- }
1052
- createVariablesClass(parentClassName, variables) {
1053
- const className = 'Variables';
1054
- const cls = new javaCommon.JavaDeclarationBlock()
1055
- .static()
1056
- .access('public')
1057
- .final()
1058
- .asKind('class')
1059
- .extends(['Operation.Variables'])
1060
- .withName(className);
1061
- const ctorImpl = [];
1062
- const ctorArgs = [];
1063
- variables.forEach(variable => {
1064
- ctorImpl.push(`this.${variable.variable.name.value} = ${variable.variable.name.value};`);
1065
- ctorImpl.push(`this.valueMap.put("${variable.variable.name.value}", ${variable.variable.name.value});`);
1066
- const baseTypeNode = visitorPluginCommon.getBaseTypeNode(variable.type);
1067
- const schemaType = this._schema.getType(baseTypeNode.name.value);
1068
- const javaClass = this.getJavaClass(schemaType);
1069
- const annotation = graphql.isNonNullType(variable.type) ? 'Nullable' : 'Nonnull';
1070
- this._imports.add(Imports[annotation]);
1071
- ctorArgs.push({ name: variable.variable.name.value, type: javaClass, annotations: [annotation] });
1072
- cls.addClassMember(variable.variable.name.value, javaClass, null, [annotation], 'private');
1073
- cls.addClassMethod(variable.variable.name.value, javaClass, `return ${variable.variable.name.value};`, [], [], 'public');
1074
- });
1075
- this._imports.add(Imports.LinkedHashMap);
1076
- this._imports.add(Imports.Map);
1077
- cls.addClassMethod(className, null, ctorImpl.join('\n'), ctorArgs, [], 'public');
1078
- cls.addClassMember('valueMap', 'Map<String, Object>', 'new LinkedHashMap<>()', [], 'private', {
1079
- final: true,
1080
- transient: true,
1081
- });
1082
- cls.addClassMethod('valueMap', 'Map<String, Object>', 'return Collections.unmodifiableMap(valueMap);', [], [], 'public', {}, ['Override']);
1083
- const marshallerImpl = `return new InputFieldMarshaller() {
1084
- @Override
1085
- public void marshal(InputFieldWriter writer) throws IOException {
1086
- ${variables
1087
- .map(v => {
1088
- const baseTypeNode = visitorPluginCommon.getBaseTypeNode(v.type);
1089
- const schemaType = this._schema.getType(baseTypeNode.name.value);
1090
- const writerMethod = this._getWriterMethodByType(schemaType, true);
1091
- return visitorPluginCommon.indent(`writer.${writerMethod.name}("${v.variable.name.value}", ${writerMethod.checkNull
1092
- ? `${v.variable.name.value} != null ? ${v.variable.name.value}${writerMethod.useMarshaller ? '.marshaller()' : ''} : null`
1093
- : v.variable.name.value});`, 2);
1094
- })
1095
- .join('\n')}
1096
- }
1097
- };`;
1098
- this._imports.add(Imports.InputFieldMarshaller);
1099
- this._imports.add(Imports.InputFieldWriter);
1100
- this._imports.add(Imports.IOException);
1101
- cls.addClassMethod('marshaller', 'InputFieldMarshaller', marshallerImpl, [], [], 'public', {}, ['Override']);
1102
- return cls;
1103
- }
1104
- _getWriterMethodByType(schemaType, idAsString = false) {
1105
- if (graphql.isScalarType(schemaType)) {
1106
- if (SCALAR_TO_WRITER_METHOD[schemaType.name] && (idAsString || schemaType.name !== 'ID')) {
1107
- return {
1108
- name: SCALAR_TO_WRITER_METHOD[schemaType.name],
1109
- checkNull: false,
1110
- useMarshaller: false,
1111
- };
1112
- }
1113
- return { name: 'writeCustom', checkNull: false, useMarshaller: false, castTo: 'ResponseField.CustomTypeField' };
1114
- }
1115
- else if (graphql.isInputObjectType(schemaType)) {
1116
- return { name: 'writeObject', checkNull: true, useMarshaller: true };
1117
- }
1118
- else if (graphql.isEnumType(schemaType)) {
1119
- return { name: 'writeString', checkNull: false, useMarshaller: false };
1120
- }
1121
- else if (graphql.isObjectType(schemaType) || graphql.isInterfaceType(schemaType)) {
1122
- return { name: 'writeObject', checkNull: true, useMarshaller: true };
1123
- }
1124
- return { name: 'writeString', useMarshaller: false, checkNull: false };
1125
- }
1126
- createBuilderClass(parentClassName, variables) {
1127
- const builderClassName = 'Builder';
1128
- const cls = new javaCommon.JavaDeclarationBlock()
1129
- .static()
1130
- .final()
1131
- .access('public')
1132
- .asKind('class')
1133
- .withName(builderClassName)
1134
- .addClassMethod(builderClassName, null, '');
1135
- variables.forEach(variable => {
1136
- const baseTypeNode = visitorPluginCommon.getBaseTypeNode(variable.type);
1137
- const schemaType = this._schema.getType(baseTypeNode.name.value);
1138
- const javaClass = this.getJavaClass(schemaType);
1139
- const annotation = graphql.isNonNullType(variable.type) ? 'Nonnull' : 'Nullable';
1140
- this._imports.add(Imports[annotation]);
1141
- cls.addClassMember(variable.variable.name.value, javaClass, null, [annotation], 'private');
1142
- cls.addClassMethod(variable.variable.name.value, builderClassName, `this.${variable.variable.name.value} = ${variable.variable.name.value};\nreturn this;`, [
1143
- {
1144
- name: variable.variable.name.value,
1145
- type: javaClass,
1146
- annotations: [annotation],
1147
- },
1148
- ], [], 'public');
1149
- });
1150
- this._imports.add(Imports.Utils);
1151
- const nonNullChecks = variables
1152
- .filter(f => graphql.isNonNullType(f))
1153
- .map(f => `Utils.checkNotNull(${f.variable.name.value}, "${f.variable.name.value} == null");`);
1154
- const returnStatement = `return new ${parentClassName}(${variables.map(v => v.variable.name.value).join(', ')});`;
1155
- cls.addClassMethod('build', parentClassName, `${[...nonNullChecks, returnStatement].join('\n')}`, [], [], 'public');
1156
- return cls;
1157
- }
1158
- }
1159
-
1160
- var FileType;
1161
- (function (FileType) {
1162
- FileType[FileType["INPUT_TYPE"] = 0] = "INPUT_TYPE";
1163
- FileType[FileType["OPERATION"] = 1] = "OPERATION";
1164
- FileType[FileType["FRAGMENT"] = 2] = "FRAGMENT";
1165
- FileType[FileType["CUSTOM_TYPES"] = 3] = "CUSTOM_TYPES";
1166
- })(FileType || (FileType = {}));
1167
-
1168
- const filteredScalars = ['String', 'Float', 'Int', 'Boolean'];
1169
- class CustomTypeClassVisitor extends BaseJavaVisitor {
1170
- constructor(schema, rawConfig) {
1171
- super(schema, rawConfig, {
1172
- typePackage: rawConfig.typePackage || 'type',
1173
- });
1174
- }
1175
- extract(name) {
1176
- const lastIndex = name.lastIndexOf('.');
1177
- if (lastIndex === -1) {
1178
- return {
1179
- className: name,
1180
- importFrom: Imports[name] || null,
1181
- };
1182
- }
1183
- else {
1184
- return {
1185
- className: name.substring(lastIndex + 1),
1186
- importFrom: name,
1187
- };
1188
- }
1189
- }
1190
- additionalContent() {
1191
- this._imports.add(Imports.ScalarType);
1192
- this._imports.add(Imports.Class);
1193
- this._imports.add(Imports.Override);
1194
- this._imports.add(Imports.Generated);
1195
- const allTypes = this._schema.getTypeMap();
1196
- const enumValues = Object.keys(allTypes)
1197
- .filter(t => graphql.isScalarType(allTypes[t]) && !filteredScalars.includes(t))
1198
- .map(t => allTypes[t])
1199
- .map(scalarType => {
1200
- const uppercaseName = scalarType.name.toUpperCase();
1201
- const javaType = this.extract(this.scalars[scalarType.name] || 'String');
1202
- if (javaType.importFrom) {
1203
- this._imports.add(javaType.importFrom);
1204
- }
1205
- return visitorPluginCommon.indentMultiline(`${uppercaseName} {
1206
- @Override
1207
- public String typeName() {
1208
- return "${scalarType.name}";
1209
- }
1210
-
1211
- @Override
1212
- public Class javaType() {
1213
- return ${javaType.className}.class;
1214
- }
1215
- }`);
1216
- })
1217
- .join(',\n\n');
1218
- return new javaCommon.JavaDeclarationBlock()
1219
- .annotate([`Generated("Apollo GraphQL")`])
1220
- .access('public')
1221
- .asKind('enum')
1222
- .withName('CustomType')
1223
- .implements(['ScalarType'])
1224
- .withBlock(enumValues).string;
1225
- }
1226
- getPackage() {
1227
- return this.config.typePackage;
1228
- }
1229
- }
1230
-
1231
- const plugin = (schema, documents, config) => {
1232
- const allAst = graphql.concatAST(documents.map(v => v.document));
1233
- const allFragments = [
1234
- ...allAst.definitions.filter(d => d.kind === graphql.Kind.FRAGMENT_DEFINITION).map(fragmentDef => ({
1235
- node: fragmentDef,
1236
- name: fragmentDef.name.value,
1237
- onType: fragmentDef.typeCondition.name.value,
1238
- isExternal: false,
1239
- })),
1240
- ...(config.externalFragments || []),
1241
- ];
1242
- let visitor;
1243
- switch (config.fileType) {
1244
- case FileType.FRAGMENT:
1245
- case FileType.OPERATION: {
1246
- visitor = new OperationVisitor(schema, config, allFragments);
1247
- break;
1248
- }
1249
- case FileType.INPUT_TYPE: {
1250
- visitor = new InputTypeVisitor(schema, config);
1251
- break;
1252
- }
1253
- case FileType.CUSTOM_TYPES: {
1254
- visitor = new CustomTypeClassVisitor(schema, config);
1255
- break;
1256
- }
1257
- }
1258
- if (!visitor) {
1259
- return { content: '' };
1260
- }
1261
- const visitResult = pluginHelpers.oldVisit(allAst, visitor);
1262
- const additionalContent = visitor.additionalContent();
1263
- const imports = visitor.getImports();
1264
- return {
1265
- prepend: [`package ${visitor.getPackage()};\n`, ...imports],
1266
- content: '\n' + [...visitResult.definitions.filter(a => a && typeof a === 'string'), additionalContent].join('\n'),
1267
- };
1268
- };
1269
-
1270
- const packageNameToDirectory = (packageName) => {
1271
- return `./${packageName.split('.').join('/')}/`;
1272
- };
1273
- const preset = {
1274
- buildGeneratesSection: options => {
1275
- const outDir = options.baseOutputDir;
1276
- const inputTypesAst = [];
1277
- graphql.visit(options.schema, {
1278
- InputObjectTypeDefinition: {
1279
- enter(node) {
1280
- inputTypesAst.push(node);
1281
- },
1282
- },
1283
- });
1284
- const inputTypesDocumentNode = { kind: graphql.Kind.DOCUMENT, definitions: inputTypesAst };
1285
- const allAst = graphql.concatAST(options.documents.map(v => v.document));
1286
- const operationsAst = allAst.definitions.filter(d => d.kind === graphql.Kind.OPERATION_DEFINITION);
1287
- const fragments = allAst.definitions.filter(d => d.kind === graphql.Kind.FRAGMENT_DEFINITION);
1288
- const externalFragments = fragments.map(frag => ({
1289
- isExternal: true,
1290
- importFrom: frag.name.value,
1291
- name: frag.name.value,
1292
- onType: frag.typeCondition.name.value,
1293
- node: frag,
1294
- }));
1295
- return [
1296
- {
1297
- filename: path.join(outDir, packageNameToDirectory(options.config.typePackage), 'CustomType.java'),
1298
- plugins: options.plugins,
1299
- pluginMap: options.pluginMap,
1300
- config: {
1301
- ...options.config,
1302
- fileType: FileType.CUSTOM_TYPES,
1303
- },
1304
- schema: options.schema,
1305
- documents: [],
1306
- cache: options.cache,
1307
- },
1308
- ...inputTypesDocumentNode.definitions.map((ast) => {
1309
- const document = { kind: graphql.Kind.DOCUMENT, definitions: [ast] };
1310
- return {
1311
- filename: path.join(outDir, packageNameToDirectory(options.config.typePackage), ast.name.value + '.java'),
1312
- plugins: options.plugins,
1313
- pluginMap: options.pluginMap,
1314
- config: {
1315
- ...options.config,
1316
- fileType: FileType.INPUT_TYPE,
1317
- skipDocumentsValidation: true,
1318
- },
1319
- schema: options.schema,
1320
- documents: [{ document, location: '' }],
1321
- cache: options.cache,
1322
- };
1323
- }),
1324
- ...operationsAst.map((ast) => {
1325
- const fileName = ast.name.value.toLowerCase().endsWith(ast.operation)
1326
- ? ast.name.value
1327
- : `${ast.name.value}${changeCaseAll.pascalCase(ast.operation)}`;
1328
- const document = { kind: graphql.Kind.DOCUMENT, definitions: [ast] };
1329
- return {
1330
- filename: path.join(outDir, packageNameToDirectory(options.config.package), fileName + '.java'),
1331
- plugins: options.plugins,
1332
- pluginMap: options.pluginMap,
1333
- config: {
1334
- ...options.config,
1335
- fileType: FileType.OPERATION,
1336
- externalFragments,
1337
- },
1338
- schema: options.schema,
1339
- documents: [{ document, location: '' }],
1340
- cache: options.cache,
1341
- };
1342
- }),
1343
- ...fragments.map((ast) => {
1344
- const document = { kind: graphql.Kind.DOCUMENT, definitions: [ast] };
1345
- return {
1346
- filename: path.join(outDir, packageNameToDirectory(options.config.fragmentPackage), ast.name.value + '.java'),
1347
- plugins: options.plugins,
1348
- pluginMap: options.pluginMap,
1349
- config: {
1350
- ...options.config,
1351
- fileType: FileType.FRAGMENT,
1352
- externalFragments,
1353
- },
1354
- schema: options.schema,
1355
- documents: [{ document, location: '' }],
1356
- cache: options.cache,
1357
- };
1358
- }),
1359
- ];
1360
- },
1361
- };
1362
-
1363
- exports.plugin = plugin;
1364
- exports.preset = preset;