UNPKG

7.88 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
7const graphql = require('graphql');
8const visitorPluginCommon = require('@graphql-codegen/visitor-plugin-common');
9const flow = require('@graphql-codegen/flow');
10const autoBind = _interopDefault(require('auto-bind'));
11
12class 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
87class 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}
95class 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 // In flow, all non ` * as x` imports must be type imports
136 .map(fragmentImport => ({ ...fragmentImport, typesImport: true }))
137 .map(fragmentImport => visitorPluginCommon.generateFragmentImportStatement(fragmentImport, 'type'))
138 : [];
139 }
140}
141
142const 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
170exports.plugin = plugin;