1 | # `graphql-code-generators`
|
2 |
|
3 | This packages includes the built-in generators for GraphQL Codegen.
|
4 |
|
5 | Currently includes:
|
6 |
|
7 | * TypeScript single file
|
8 | * TypeScript multiple files
|
9 |
|
10 | ## Build process
|
11 |
|
12 | The build process of this package is based on Webpack with `awesome-typescript-loader` to compile TypeScript source code, and `raw-loader` to load the handlebars templates as string.
|
13 |
|
14 | The purpose of the build process is to eliminate the need to use `fs.readFile` for the template files, and integrate the template files into the compiles JS files as strings.
|
15 |
|
16 | To build this package and the generators template, start by installing the package dependencies:
|
17 |
|
18 | ```
|
19 | $ npm install
|
20 | // Or, with Yarn
|
21 | $ yarn
|
22 | ```
|
23 |
|
24 | Then, you can use the existing NPM scripts to build the package:
|
25 |
|
26 | ```
|
27 | $ npm run build
|
28 | // Or, with Yarn
|
29 | $ yarn build
|
30 | ```
|
31 |
|
32 | ## Adding a new generator
|
33 |
|
34 | To add a new generator, start by adding a new directory under `./src/` of this directory, with the name of the generator.
|
35 |
|
36 | Then, create a file called `config.ts`.
|
37 |
|
38 | Your config file should use default export, and export a config variable that implements the [`GeneratorConfig`](https://github.com/dotansimha/graphql-code-generator/blob/e9e4722723541628bc7ae58c0e4082556af4bfb8/packages/graphql-codegen-generators/src/types.ts#L7-L20) interface, for example:
|
39 |
|
40 | ```typescript
|
41 | import { EInputType, GeneratorConfig } from '../types';
|
42 |
|
43 | const config: GeneratorConfig = {
|
44 | inputType: EInputType.MULTIPLE_FILES,
|
45 | templates: {
|
46 | // Your templates here
|
47 | },
|
48 | flattenTypes: true,
|
49 | primitives: {
|
50 | String: 'string',
|
51 | Int: 'number',
|
52 | Float: 'number',
|
53 | Boolean: 'boolean',
|
54 | ID: 'string'
|
55 | },
|
56 | };
|
57 |
|
58 | export default config;
|
59 | ```
|
60 |
|
61 | Next, make sure to import your template files and add them to your `templates`, for example:
|
62 |
|
63 | ```typescript
|
64 | import * as index from './template.handlebars';
|
65 | import * as type from './type.handlebars';
|
66 | import * as schema from './schema.handlebars';
|
67 | import * as documents from './documents.handlebars';
|
68 | import * as selectionSet from './selection-set.handlebars';
|
69 | import { EInputType, GeneratorConfig } from '../types';
|
70 |
|
71 | const config: GeneratorConfig = {
|
72 | inputType: EInputType.SINGLE_FILE,
|
73 | templates: {
|
74 | index,
|
75 | type,
|
76 | schema,
|
77 | documents,
|
78 | selectionSet,
|
79 | },
|
80 | flattenTypes: true,
|
81 | primitives: {
|
82 | String: 'string',
|
83 | Int: 'number',
|
84 | Float: 'number',
|
85 | Boolean: 'boolean',
|
86 | ID: 'string'
|
87 | },
|
88 | outFile: 'types.d.ts',
|
89 | };
|
90 |
|
91 | export default config;
|
92 | ```
|
93 |
|
94 | ### inputType
|
95 |
|
96 | Allowed values: `EInputType.SINGLE_FILE`, `EInputType.MULTIPLE_FILES`
|
97 |
|
98 | `inputType` defined the template input type of the generator, and also declares the generator output.
|
99 |
|
100 | For example, we have TypeScript generators for both single and multiple files.
|
101 |
|
102 | The input type field effects the rest of the fields:
|
103 |
|
104 | #### *SINGLE_FILE*
|
105 |
|
106 | When using `SINGLE_FILE`, you must specify the main template name, with a key called `index`, and this will be the root of your app.
|
107 |
|
108 | You also need to specify the `outFile` of the package, which is the default file name in case of output filename was not specified through the CLI.
|
109 |
|
110 | #### *MULTIPLE_FILES*
|
111 |
|
112 | When using `MULTIPLE_FILES`, you need to specify a template for each available compilation context (refer to `templates` section for the list of available contexts).
|
113 |
|
114 | You also need to specify the `filesExtension` for the generated files.
|
115 |
|
116 | ### templates
|
117 |
|
118 | `templates` field should contains an object, where the key is the name of the template, and the value is a string.
|
119 |
|
120 | There are special context types for templates, and each type of templates will compile with a different context:
|
121 |
|
122 | * `index`: use with `SINGLE_FILE` to declare the main entry point of the generated file, compiled with a merged object, containing all [`SchemaTemplateContext`](https://github.com/dotansimha/graphql-code-generator/blob/e9e4722723541628bc7ae58c0e4082556af4bfb8/packages/graphql-codegen-core/src/types.ts#L78-L94) and [`Document`](https://github.com/dotansimha/graphql-code-generator/blob/e9e4722723541628bc7ae58c0e4082556af4bfb8/packages/graphql-codegen-core/src/types.ts#L170-L175) fields.
|
123 | * `type`: use with `MULTIPLE_FILES` to declare that this template belongs to GraphQL schema `type`, this template will compile with *each* [type](https://github.com/dotansimha/graphql-code-generator/blob/e9e4722723541628bc7ae58c0e4082556af4bfb8/packages/graphql-codegen-core/src/types.ts#L38-L46) in your schema.
|
124 | * `inputType`: use with `MULTIPLE_FILES` to declare that this template belongs to GraphQL schema `input`, this template will compile with *each* [input type](https://github.com/dotansimha/graphql-code-generator/blob/e9e4722723541628bc7ae58c0e4082556af4bfb8/packages/graphql-codegen-core/src/types.ts#L38-L46) in your schema.
|
125 | * `union`: use with `MULTIPLE_FILES` to declare that this template belongs to GraphQL schema `union`, this template will compile with *each* [union](https://github.com/dotansimha/graphql-code-generator/blob/e9e4722723541628bc7ae58c0e4082556af4bfb8/packages/graphql-codegen-core/src/types.ts#L65-L69) in your schema.
|
126 | * `scalar`: use with `MULTIPLE_FILES` to declare that this template belongs to GraphQL schema `scalar`, this template will compile with *each* [scalar](https://github.com/dotansimha/graphql-code-generator/blob/e9e4722723541628bc7ae58c0e4082556af4bfb8/packages/graphql-codegen-core/src/types.ts#L48-L51) in your schema.
|
127 | * `enum`: use with `MULTIPLE_FILES` to declare that this template belongs to GraphQL schema `enum`, this template will compile with *each* [enum](https://github.com/dotansimha/graphql-code-generator/blob/e9e4722723541628bc7ae58c0e4082556af4bfb8/packages/graphql-codegen-core/src/types.ts#L53-L57) in your schema.
|
128 | * `interface`: use with `MULTIPLE_FILES` to declare that this template belongs to GraphQL schema `interface`, this template will compile with *each* [interface](https://github.com/dotansimha/graphql-code-generator/blob/e9e4722723541628bc7ae58c0e4082556af4bfb8/packages/graphql-codegen-core/src/types.ts#L71-L76) in your schema.
|
129 | * `operation`: use with `MULTIPLE_FILES` to declare that this template belongs to GraphQL operation (`query`/`mutation`/`subsription`), this template will compile with [`Operation` context](https://github.com/dotansimha/graphql-code-generator/blob/e9e4722723541628bc7ae58c0e4082556af4bfb8/packages/graphql-codegen-core/src/types.ts#L151-L161).
|
130 | * `fragment`: use with `MULTIPLE_FILES` to declare that this template belongs to GraphQL `fragment`, this template will compile with [`Fragment` context](https://github.com/dotansimha/graphql-code-generator/blob/e9e4722723541628bc7ae58c0e4082556af4bfb8/packages/graphql-codegen-core/src/types.ts#L144-L149).
|
131 | * `schema`: use with `MULTIPLE_FILES` to compile with [`SchemaTemplateContext`](https://github.com/dotansimha/graphql-code-generator/blob/e9e4722723541628bc7ae58c0e4082556af4bfb8/packages/graphql-codegen-core/src/types.ts#L78-L94).
|
132 | * `documents`: use with `MULTIPLE_FILES` to compile with all operations, the context will be [`Document`](https://github.com/dotansimha/graphql-code-generator/blob/e9e4722723541628bc7ae58c0e4082556af4bfb8/packages/graphql-codegen-core/src/types.ts#L170-L175).
|
133 | * `all`: same as to `index`.
|
134 |
|
135 | Also, all templates specified under `templates` will be loaded as Handlebars template partials, so you can use it any time inside other templates, for example, the following templates definitions:
|
136 |
|
137 | ```typescript
|
138 | const config = {
|
139 | // ...
|
140 | templates: {
|
141 | index: '{{>selectionSet}}',
|
142 | selectionSet: 'Hello',
|
143 | },
|
144 | // ...
|
145 | };
|
146 | ```
|
147 |
|
148 | The `index` template loads `selectionSet` template, and it can also provide a context for the specific partial:
|
149 |
|
150 | ```typescript
|
151 | const config = {
|
152 | // ...
|
153 | templates: {
|
154 | index: '{{>selectionSet types}}',
|
155 | selectionSet: '{{#each this }} Type name: {{ name }}{{/each}}',
|
156 | },
|
157 | // ...
|
158 | };
|
159 | ```
|
160 |
|
161 | > You can also load a template from itself, and create a recursive generation of the template.
|
162 |
|
163 | ### flattenTypes
|
164 |
|
165 | Type flattening is a useful feature when generation a template, when `true` is specified, the generator will return a flatten version of the GraphQL selection set when using inner types.
|
166 |
|
167 | For example, let's take a look in the following GraphQL schema and `query`:
|
168 |
|
169 | ```graphql schema
|
170 | type NameFields {
|
171 | firstName: String
|
172 | lastName: String
|
173 | }
|
174 |
|
175 | type User {
|
176 | name: NameFields
|
177 | email: String
|
178 | age: Int
|
179 | }
|
180 |
|
181 | type Query {
|
182 | me: User
|
183 | }
|
184 |
|
185 | schema {
|
186 | query: Query
|
187 | }
|
188 | ```
|
189 |
|
190 | ```graphql
|
191 | query myQuery {
|
192 | user {
|
193 | me {
|
194 | firstName
|
195 | lastName
|
196 | }
|
197 | }
|
198 | }
|
199 | ```
|
200 |
|
201 | This query uses multiple levels of selection set (`user` > `name` > `firstName`), but when adding `flattenTypes: true`, the generator will append a new field to the operation/fragment context, called `innerModels`, and it this case it will contains the following:
|
202 |
|
203 | ```
|
204 | [
|
205 | {
|
206 | schemaBaseType: 'User',
|
207 | modelType: 'Me',
|
208 | fields: [ ... ] // Original SelectionSetFieldNode from the operation
|
209 | // .. more fields
|
210 | },
|
211 | {
|
212 | schemaBaseType: 'NameFields',
|
213 | modelType: 'Name',
|
214 | fields: [ ... ] // Original SelectionSetFieldNode from the operation
|
215 | // .. more fields
|
216 | }
|
217 | ]
|
218 | ```
|
219 |
|
220 | So the two available levels of selection set were flatten into a single level, so you can generate you whole selection set in a single iteration.
|
221 |
|
222 | The `modelType` becomes the name of the selection set field, because we use only part of the available fields (for example, the query only asks for part of the `User` fields), so we can't use the actual GraphQL `type` from the schema - so each selection set creates new "types", and the usage in the selection set also changes, so the `type` of `me` is not `User` - it's `Me`.
|
223 |
|
224 | The actual compilation context when using `flattenTypes: true` is [available here](https://github.com/dotansimha/graphql-code-generator/blob/e9e4722723541628bc7ae58c0e4082556af4bfb8/packages/graphql-codegen-compiler/src/types.ts#L11-L37).
|
225 |
|
226 | ### primitives
|
227 |
|
228 | Specify `primitives` object map to replace the original GraphQL built-in types to a language-specific primitives.
|
229 |
|
230 | For example, GraphQL type of `String` is actually a `string` in TypeScript.
|
231 |
|
232 | ### outFile
|
233 |
|
234 | Use with `SINGLE_FILE`, specify the default filename for the generated file.
|
235 |
|
236 |
|
237 | ### filesExtension
|
238 |
|
239 | Use with `MULTIPLE_FILES`, specify the file extension for the generated files.
|