UNPKG

7.38 kBPlain TextView Raw
1#!/usr/bin/env node
2
3import 'apollo-codegen-core/lib/polyfills';
4
5import * as glob from 'glob';
6import * as process from 'process';
7import * as path from 'path';
8import * as yargs from 'yargs';
9
10import downloadSchema from './downloadSchema';
11import introspectSchema from './introspectSchema';
12import printSchema from './printSchema';
13import { ToolError, logError } from 'apollo-codegen-core/lib/errors';
14
15import generate from './generate';
16
17import 'source-map-support/register';
18
19// Make sure unhandled errors in async code are propagated correctly
20process.on('unhandledRejection', (error) => { throw error });
21
22process.on('uncaughtException', handleError);
23
24function handleError(error: Error) {
25 logError(error);
26 process.exit(1);
27}
28
29yargs
30 .command(
31 ['introspect-schema <schema>', 'download-schema'],
32 'Generate an introspection JSON from a local GraphQL file or from a remote GraphQL server',
33 {
34 output: {
35 demand: true,
36 describe: 'Output path for GraphQL schema file',
37 default: 'schema.json',
38 normalize: true,
39 coerce: path.resolve,
40 },
41 header: {
42 alias: 'H',
43 describe: 'Additional header to send to the server as part of the introspection query request',
44 type: 'array',
45 coerce: (arg) => {
46 let additionalHeaders: {
47 [key: string]: any
48 } = {};
49 for (const header of arg) {
50 const separator = header.indexOf(":");
51 const name = header.substring(0, separator).trim();
52 const value = header.substring(separator + 1).trim();
53 if (!(name && value)) {
54 throw new ToolError('Headers should be specified as "Name: Value"');
55 }
56 additionalHeaders[name] = value;
57 }
58 return additionalHeaders;
59 }
60 },
61 insecure: {
62 alias: 'K',
63 describe: 'Allows "insecure" SSL connection to the server',
64 type: 'boolean'
65 },
66 method: {
67 demand: false,
68 describe: 'The HTTP request method to use for the introspection query request',
69 type: 'string',
70 default: 'POST',
71 choices: ['POST', 'GET', 'post', 'get']
72 }
73 },
74 async argv => {
75 const { schema, output, header, insecure, method } = argv;
76
77 const urlRegex = /^https?:\/\//i;
78 if (urlRegex.test(schema)) {
79 await downloadSchema(schema, output, header, insecure, method);
80 } else {
81 await introspectSchema(schema, output);
82 }
83 }
84 )
85 .command(
86 ['print-schema [schema]'],
87 'Print the provided schema in the GraphQL schema language format',
88 {
89 schema: {
90 demand: true,
91 describe: 'Path to GraphQL introspection query result',
92 default: 'schema.json',
93 normalize: true,
94 coerce: path.resolve,
95 },
96 output: {
97 demand: true,
98 describe: 'Output path for GraphQL schema language file',
99 default: 'schema.graphql',
100 normalize: true,
101 coerce: path.resolve,
102 }
103 },
104 async argv => {
105 const { schema, output } = argv;
106 await printSchema(schema, output);
107 }
108 )
109 .command(
110 'generate [input...]',
111 'Generate code from a GraphQL schema and query documents',
112 {
113 schema: {
114 demand: false,
115 describe: 'Path to GraphQL schema file. (Defaults to using .graphqlconfig or schema.json)',
116 normalize: true,
117 coerce: path.resolve,
118 },
119 output: {
120 demand: true,
121 describe: 'Output directory for the generated files',
122 normalize: true,
123 coerce: path.resolve,
124 },
125 target: {
126 demand: false,
127 describe: 'Code generation target language',
128 choices: ['swift', 'scala', 'json', 'ts-legacy', 'ts', 'typescript-legacy', 'typescript', 'flow-legacy', 'flow'],
129 default: 'swift'
130 },
131 only: {
132 describe: 'Parse all input files, but only output generated code for the specified file [Swift only]',
133 normalize: true,
134 coerce: path.resolve,
135 },
136 namespace: {
137 demand: false,
138 describe: 'Optional namespace for generated types [currently Swift and Scala-only]',
139 type: 'string'
140 },
141 "passthrough-custom-scalars": {
142 demand: false,
143 describe: "Use the names of custom scalars as their type name [temporary option]",
144 default: false
145 },
146 "custom-scalars-prefix": {
147 demand: false,
148 describe: "Prefix for custom scalars. (Implies that passthrough-custom-scalars is true if set)",
149 default: '',
150 normalize: true
151 },
152 "add-typename": {
153 demand: false,
154 describe: "For non-swift targets, always add the __typename GraphQL introspection type when generating target types",
155 default: false
156 },
157 "use-flow-exact-objects": {
158 demand: false,
159 describe: "Use Flow exact objects for generated types [flow only]",
160 default: false,
161 type: 'boolean'
162 },
163 "use-flow-read-only-types": {
164 demand: false,
165 describe: "Use Flow read only types for generated types [flow only]",
166 default: false,
167 type: 'boolean'
168 },
169 "tag-name": {
170 demand: false,
171 describe: "Name of the template literal tag used to identify template literals containing GraphQL queries in Javascript/Typescript code",
172 default: 'gql'
173 },
174 "project-name": {
175 demand: false,
176 describe: "Name of the project to use in a multi-project .graphqlconfig file",
177 },
178 "operation-ids-path": {
179 demand: false,
180 describe: "Path to an operation id JSON map file. If specified, also stores the operation ids (hashes) as properties on operation types [currently Swift-only]",
181 default: null,
182 normalize: true
183 },
184 "merge-in-fields-from-fragment-spreads": {
185 demand: false,
186 describe: "Merge fragment fields onto its enclosing type",
187 default: true,
188 type: 'boolean'
189 }
190 },
191 argv => {
192 let { input } = argv;
193
194 // Use glob if the user's shell was unable to expand the pattern
195 if (input.length === 1 && glob.hasMagic(input[0])) {
196 input = glob.sync(input[0]);
197 }
198
199 const inputPaths = (input as string[])
200 .map(input => path.resolve(input))
201 // Sort to normalize different glob expansions between different terminals.
202 .sort();
203
204 const options = {
205 passthroughCustomScalars: argv["passthrough-custom-scalars"] || argv["custom-scalars-prefix"] !== '',
206 customScalarsPrefix: argv["custom-scalars-prefix"] || '',
207 addTypename: argv["add-typename"],
208 namespace: argv.namespace,
209 operationIdsPath: argv["operation-ids-path"],
210 generateOperationIds: !!argv["operation-ids-path"],
211 mergeInFieldsFromFragmentSpreads: argv["merge-in-fields-from-fragment-spreads"],
212 useFlowExactObjects: argv['use-flow-exact-objects'],
213 useFlowReadOnlyTypes: argv['use-flow-read-only-types'],
214 };
215
216 generate(inputPaths, argv.schema, argv.output, argv.only, argv.target, argv.tagName, argv.projectName, options);
217 },
218 )
219 .fail(function(message, error) {
220 handleError(error ? error : new ToolError(message));
221 })
222 .help()
223 .version()
224 .strict()
225 .argv