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 graphql = require('graphql');
|
8 | const visitorPluginCommon = require('@graphql-codegen/visitor-plugin-common');
|
9 | const flow = require('@graphql-codegen/flow');
|
10 | const autoBind = _interopDefault(require('auto-bind'));
|
11 |
|
12 | class FlowWithPickSelectionSetProcessor extends visitorPluginCommon.BaseSelectionSetProcessor {
|
13 | transformAliasesPrimitiveFields(schemaType, fields) {
|
14 | if (fields.length === 0) {
|
15 | return [];
|
16 | }
|
17 | const useFlowExactObject = this.config.useFlowExactObjects;
|
18 | const formatNamedField = this.config.formatNamedField;
|
19 | const fieldObj = schemaType.getFields();
|
20 | const parentName = (this.config.namespacedImportName ? `${this.config.namespacedImportName}.` : '') +
|
21 | this.config.convertName(schemaType.name, {
|
22 | useTypesPrefix: true,
|
23 | });
|
24 | return [
|
25 | `{${useFlowExactObject ? '|' : ''} ${fields
|
26 | .map(aliasedField => `${formatNamedField(aliasedField.alias, fieldObj[aliasedField.fieldName].type)}: $ElementType<${parentName}, '${aliasedField.fieldName}'>`)
|
27 | .join(', ')} ${useFlowExactObject ? '|' : ''}}`,
|
28 | ];
|
29 | }
|
30 | buildFieldsIntoObject(allObjectsMerged) {
|
31 | return `...{ ${allObjectsMerged.join(', ')} }`;
|
32 | }
|
33 | buildSelectionSetFromStrings(pieces) {
|
34 | if (pieces.length === 0) {
|
35 | return null;
|
36 | }
|
37 | else if (pieces.length === 1) {
|
38 | return pieces[0];
|
39 | }
|
40 | else {
|
41 | return `({\n ${pieces.map(t => visitorPluginCommon.indent(`...${t}`)).join(`,\n`)}\n})`;
|
42 | }
|
43 | }
|
44 | transformLinkFields(fields) {
|
45 | if (fields.length === 0) {
|
46 | return [];
|
47 | }
|
48 | const useFlowExactObject = this.config.useFlowExactObjects;
|
49 | return [
|
50 | `{${useFlowExactObject ? '|' : ''} ${fields
|
51 | .map(field => `${field.alias || field.name}: ${field.selectionSet}`)
|
52 | .join(', ')} ${useFlowExactObject ? '|' : ''}}`,
|
53 | ];
|
54 | }
|
55 | transformPrimitiveFields(schemaType, fields) {
|
56 | if (fields.length === 0) {
|
57 | return [];
|
58 | }
|
59 | const useFlowExactObject = this.config.useFlowExactObjects;
|
60 | const formatNamedField = this.config.formatNamedField;
|
61 | const parentName = (this.config.namespacedImportName ? `${this.config.namespacedImportName}.` : '') +
|
62 | this.config.convertName(schemaType.name, {
|
63 | useTypesPrefix: true,
|
64 | });
|
65 | const fieldObj = schemaType.getFields();
|
66 | let hasConditionals = false;
|
67 | const conditilnalsList = [];
|
68 | let resString = `$Pick<${parentName}, {${useFlowExactObject ? '|' : ''} ${fields
|
69 | .map(field => {
|
70 | if (field.isConditional) {
|
71 | hasConditionals = true;
|
72 | conditilnalsList.push(field.fieldName);
|
73 | }
|
74 | return `${formatNamedField(field.fieldName, fieldObj[field.fieldName].type)}: *`;
|
75 | })
|
76 | .join(', ')} ${useFlowExactObject ? '|' : ''}}>`;
|
77 | if (hasConditionals) {
|
78 | resString = `$MakeOptional<${resString}, ${conditilnalsList.map(field => `{ ${field}: * }`).join(' | ')}>`;
|
79 | }
|
80 | return [resString];
|
81 | }
|
82 | transformTypenameField(type, name) {
|
83 | return [`{ ${name}: ${type} }`];
|
84 | }
|
85 | }
|
86 |
|
87 | class FlowSelectionSetToObject extends visitorPluginCommon.SelectionSetToObject {
|
88 | getUnknownType() {
|
89 | return 'any';
|
90 | }
|
91 | createNext(parentSchemaType, selectionSet) {
|
92 | return new FlowSelectionSetToObject(this._processor, this._scalars, this._schema, this._convertName.bind(this), this._getFragmentSuffix.bind(this), this._loadedFragments, this._config, parentSchemaType, selectionSet);
|
93 | }
|
94 | }
|
95 | class FlowDocumentsVisitor extends visitorPluginCommon.BaseDocumentsVisitor {
|
96 | constructor(schema, config, allFragments) {
|
97 | super(config, {
|
98 | useFlowExactObjects: visitorPluginCommon.getConfigValue(config.useFlowExactObjects, true),
|
99 | useFlowReadOnlyTypes: visitorPluginCommon.getConfigValue(config.useFlowReadOnlyTypes, false),
|
100 | }, schema);
|
101 | autoBind(this);
|
102 | const wrapArray = (type) => `${this.config.useFlowReadOnlyTypes ? '$ReadOnlyArray' : 'Array'}<${type}>`;
|
103 | const wrapOptional = (type) => `?${type}`;
|
104 | const useFlowReadOnlyTypes = this.config.useFlowReadOnlyTypes;
|
105 | const formatNamedField = (name, type, isConditional = false) => {
|
106 | const optional = (!!type && !graphql.isNonNullType(type)) || isConditional;
|
107 | return `${useFlowReadOnlyTypes ? '+' : ''}${name}${optional ? '?' : ''}`;
|
108 | };
|
109 | const processorConfig = {
|
110 | namespacedImportName: this.config.namespacedImportName,
|
111 | convertName: this.convertName.bind(this),
|
112 | enumPrefix: this.config.enumPrefix,
|
113 | scalars: this.scalars,
|
114 | formatNamedField,
|
115 | wrapTypeWithModifiers(baseType, type) {
|
116 | return visitorPluginCommon.wrapTypeWithModifiers(baseType, type, { wrapOptional, wrapArray });
|
117 | },
|
118 | };
|
119 | const processor = config.preResolveTypes
|
120 | ? new visitorPluginCommon.PreResolveTypesProcessor(processorConfig)
|
121 | : new FlowWithPickSelectionSetProcessor({
|
122 | ...processorConfig,
|
123 | useFlowExactObjects: this.config.useFlowExactObjects,
|
124 | });
|
125 | const enumsNames = Object.keys(schema.getTypeMap()).filter(typeName => graphql.isEnumType(schema.getType(typeName)));
|
126 | this.setSelectionSetHandler(new FlowSelectionSetToObject(processor, this.scalars, this.schema, this.convertName.bind(this), this.getFragmentSuffix.bind(this), allFragments, this.config));
|
127 | this.setVariablesTransformer(new flow.FlowOperationVariablesToObject(this.scalars, this.convertName.bind(this), this.config.namespacedImportName, enumsNames, this.config.enumPrefix, {}, true));
|
128 | }
|
129 | getPunctuation(declarationKind) {
|
130 | return declarationKind === 'type' ? ',' : ';';
|
131 | }
|
132 | getImports() {
|
133 | return !this.config.globalNamespace && !this.config.inlineFragmentTypes
|
134 | ? this.config.fragmentImports
|
135 |
|
136 | .map(fragmentImport => ({ ...fragmentImport, typesImport: true }))
|
137 | .map(fragmentImport => visitorPluginCommon.generateFragmentImportStatement(fragmentImport, 'type'))
|
138 | : [];
|
139 | }
|
140 | }
|
141 |
|
142 | const plugin = (schema, rawDocuments, config) => {
|
143 | const documents = config.flattenGeneratedTypes
|
144 | ? visitorPluginCommon.optimizeOperations(schema, rawDocuments, { includeFragments: true })
|
145 | : rawDocuments;
|
146 | const prefix = config.preResolveTypes
|
147 | ? ''
|
148 | : `type $Pick<Origin: Object, Keys: Object> = $ObjMapi<Keys, <Key>(k: Key) => $ElementType<Origin, Key>>;\n`;
|
149 | const allAst = graphql.concatAST(documents.map(v => v.document));
|
150 | const includedFragments = allAst.definitions.filter(d => d.kind === graphql.Kind.FRAGMENT_DEFINITION);
|
151 | const allFragments = [
|
152 | ...includedFragments.map(fragmentDef => ({
|
153 | node: fragmentDef,
|
154 | name: fragmentDef.name.value,
|
155 | onType: fragmentDef.typeCondition.name.value,
|
156 | isExternal: false,
|
157 | })),
|
158 | ...(config.externalFragments || []),
|
159 | ];
|
160 | const visitor = new FlowDocumentsVisitor(schema, config, allFragments);
|
161 | const visitorResult = graphql.visit(allAst, {
|
162 | leave: visitor,
|
163 | });
|
164 | return {
|
165 | prepend: ['// @flow\n', ...visitor.getImports()],
|
166 | content: [prefix, ...visitorResult.definitions].join('\n'),
|
167 | };
|
168 | };
|
169 |
|
170 | exports.plugin = plugin;
|