|
1 |
| -import inquirer from 'inquirer'; |
| 1 | +import { checkbox, input, select, confirm } from '@inquirer/prompts'; |
2 | 2 | import { grey } from './helpers.js';
|
3 | 3 | import { plugins } from './plugins.js';
|
4 |
| -import { Answers, Tags } from './types.js'; |
| 4 | +import { type Answers, type PluginOption, Tags } from './types.js'; |
5 | 5 |
|
6 |
| -export function getQuestions(possibleTargets: Record<Tags, boolean>): inquirer.QuestionCollection { |
7 |
| - return [ |
8 |
| - { |
9 |
| - type: 'list', |
10 |
| - name: 'targets', |
| 6 | +export async function getAnswers(possibleTargets: Record<Tags, boolean>): Promise<Answers> { |
| 7 | + try { |
| 8 | + const targetChoices = getApplicationTypeChoices(possibleTargets); |
| 9 | + |
| 10 | + const targets = await select({ |
11 | 11 | message: `What type of application are you building?`,
|
12 |
| - choices: getApplicationTypeChoices(possibleTargets), |
13 |
| - validate: ((targets: any[]) => targets.length > 0) as any, |
14 |
| - default: getApplicationTypeChoices(possibleTargets).findIndex(c => c.checked), |
15 |
| - }, |
16 |
| - { |
17 |
| - type: 'input', |
18 |
| - name: 'schema', |
19 |
| - message: 'Where is your schema?:', |
20 |
| - suffix: grey(' (path or url)'), |
| 12 | + choices: targetChoices, |
| 13 | + default: targetChoices.find(c => c.checked)?.value, |
| 14 | + }); |
| 15 | + const schema = await input({ |
| 16 | + message: `Where is your schema?: ${grey('(path or url)')}`, |
21 | 17 | default: 'http://localhost:4000', // matches Apollo Server's default
|
22 |
| - validate: (str: string) => str.length > 0, |
23 |
| - }, |
24 |
| - { |
25 |
| - type: 'input', |
26 |
| - name: 'documents', |
27 |
| - message: 'Where are your operations and fragments?:', |
28 |
| - when: answers => { |
29 |
| - // flatten targets |
30 |
| - // I can't find an API in Inquirer that would do that |
31 |
| - answers.targets = normalizeTargets(answers.targets); |
| 18 | + validate: str => str.length > 0, |
| 19 | + }); |
32 | 20 |
|
33 |
| - return ( |
34 |
| - answers.targets.includes(Tags.client) || |
35 |
| - answers.targets.includes(Tags.angular) || |
36 |
| - answers.targets.includes(Tags.stencil) |
37 |
| - ); |
38 |
| - }, |
39 |
| - default: getDocumentsDefaultValue, |
40 |
| - validate: (str: string) => str.length > 0, |
41 |
| - }, |
42 |
| - { |
43 |
| - type: 'checkbox', |
44 |
| - name: 'plugins', |
45 |
| - when: answers => { |
46 |
| - // flatten targets |
47 |
| - // I can't find an API in Inquirer that would do that |
48 |
| - answers.targets = normalizeTargets(answers.targets); |
| 21 | + let documents: string | undefined; |
| 22 | + if (targets.includes(Tags.client) || targets.includes(Tags.angular) || targets.includes(Tags.stencil)) |
| 23 | + documents = await input({ |
| 24 | + message: 'Where are your operations and fragments?:', |
| 25 | + default: getDocumentsDefaultValue(targets), |
| 26 | + validate: str => str.length > 0, |
| 27 | + }); |
49 | 28 |
|
50 |
| - return !answers.targets.includes(Tags.client); |
51 |
| - }, |
52 |
| - message: 'Pick plugins:', |
53 |
| - choices: getPluginChoices, |
54 |
| - validate: ((plugins: any[]) => plugins.length > 0) as any, |
55 |
| - }, |
56 |
| - { |
57 |
| - type: 'input', |
58 |
| - name: 'output', |
| 29 | + let plugins: PluginOption[]; |
| 30 | + if (!targets.includes(Tags.client)) { |
| 31 | + plugins = await checkbox({ |
| 32 | + message: 'Pick plugins:', |
| 33 | + choices: getPluginChoices(targets), |
| 34 | + validate: plugins => plugins.length > 0, |
| 35 | + }); |
| 36 | + } |
| 37 | + |
| 38 | + const output = await input({ |
59 | 39 | message: 'Where to write the output:',
|
60 |
| - default: getOutputDefaultValue, |
61 |
| - validate: (str: string) => str.length > 0, |
62 |
| - }, |
63 |
| - { |
64 |
| - type: 'confirm', |
65 |
| - name: 'introspection', |
66 |
| - default: false, |
| 40 | + default: getOutputDefaultValue({ targets, plugins }), |
| 41 | + validate: str => str.length > 0, |
| 42 | + }); |
| 43 | + |
| 44 | + const introspection = await confirm({ |
67 | 45 | message: 'Do you want to generate an introspection file?',
|
68 |
| - }, |
69 |
| - { |
70 |
| - type: 'input', |
71 |
| - name: 'config', |
| 46 | + default: false, |
| 47 | + }); |
| 48 | + |
| 49 | + const config = await input({ |
72 | 50 | message: 'How to name the config file?',
|
73 |
| - default: answers => |
74 |
| - answers.targets.includes(Tags.client) || |
75 |
| - answers.targets.includes(Tags.typescript) || |
76 |
| - answers.targets.includes(Tags.angular) |
| 51 | + default: (() => |
| 52 | + targets.includes(Tags.client) || targets.includes(Tags.typescript) || targets.includes(Tags.angular) |
77 | 53 | ? 'codegen.ts'
|
78 |
| - : 'codegen.yml', |
79 |
| - validate: (str: string) => { |
| 54 | + : 'codegen.yml')(), |
| 55 | + validate: str => { |
80 | 56 | const isNotEmpty = str.length > 0;
|
81 | 57 | const hasCorrectExtension = ['json', 'yml', 'yaml', 'js', 'ts'].some(ext =>
|
82 | 58 | str.toLocaleLowerCase().endsWith(`.${ext}`)
|
83 | 59 | );
|
84 | 60 |
|
85 | 61 | return isNotEmpty && hasCorrectExtension;
|
86 | 62 | },
|
87 |
| - }, |
88 |
| - { |
89 |
| - type: 'input', |
90 |
| - name: 'script', |
| 63 | + }); |
| 64 | + |
| 65 | + const script = await input({ |
91 | 66 | default: 'codegen',
|
92 | 67 | message: 'What script in package.json should run the codegen?',
|
93 | 68 | validate: (str: string) => str.length > 0,
|
94 |
| - }, |
95 |
| - ]; |
| 69 | + }); |
| 70 | + |
| 71 | + return { |
| 72 | + targets, |
| 73 | + schema, |
| 74 | + documents, |
| 75 | + plugins, |
| 76 | + output, |
| 77 | + introspection, |
| 78 | + config, |
| 79 | + script, |
| 80 | + }; |
| 81 | + } catch (error) { |
| 82 | + if (error instanceof Error && error.name === 'ExitPromptError') { |
| 83 | + // This error because user exited using CMD+C, just exit gracefully or else user would see an ugly error message |
| 84 | + // https://github.com/SBoudrias/Inquirer.js/blob/ee16061a1e3f99a6cc714a3d473f7cd12b06a3f1/packages/prompts/README.md#handling-ctrlc-gracefully |
| 85 | + process.exit(); |
| 86 | + } else { |
| 87 | + throw error; |
| 88 | + } |
| 89 | + } |
96 | 90 | }
|
97 | 91 |
|
98 | 92 | export function getApplicationTypeChoices(possibleTargets: Record<Tags, boolean>) {
|
@@ -154,43 +148,39 @@ export function getApplicationTypeChoices(possibleTargets: Record<Tags, boolean>
|
154 | 148 | ];
|
155 | 149 | }
|
156 | 150 |
|
157 |
| -export function getPluginChoices(answers: Answers) { |
| 151 | +export function getPluginChoices(targets: Tags[]) { |
158 | 152 | return plugins
|
159 |
| - .filter(p => p.available(answers.targets)) |
160 |
| - .map<inquirer.DistinctChoice<inquirer.AllChoiceMap>>(p => { |
| 153 | + .filter(p => p.available(targets)) |
| 154 | + .map(p => { |
161 | 155 | return {
|
162 | 156 | name: p.name,
|
163 | 157 | value: p,
|
164 |
| - checked: p.shouldBeSelected(answers.targets), |
| 158 | + checked: p.shouldBeSelected(targets), |
165 | 159 | };
|
166 | 160 | });
|
167 | 161 | }
|
168 | 162 |
|
169 |
| -function normalizeTargets(targets: Tags[] | Tags[][]): Tags[] { |
170 |
| - return [].concat(...targets); |
171 |
| -} |
172 |
| - |
173 |
| -export function getOutputDefaultValue(answers: Answers) { |
174 |
| - if (answers.targets.includes(Tags.client)) { |
| 163 | +function getOutputDefaultValue({ targets, plugins }: { targets: Tags[]; plugins: PluginOption[] }) { |
| 164 | + if (targets.includes(Tags.client)) { |
175 | 165 | return 'src/gql/';
|
176 | 166 | }
|
177 |
| - if (answers.plugins.some(plugin => plugin.defaultExtension === '.tsx')) { |
| 167 | + if (plugins.some(plugin => plugin.defaultExtension === '.tsx')) { |
178 | 168 | return 'src/generated/graphql.tsx';
|
179 | 169 | }
|
180 |
| - if (answers.plugins.some(plugin => plugin.defaultExtension === '.ts')) { |
| 170 | + if (plugins.some(plugin => plugin.defaultExtension === '.ts')) { |
181 | 171 | return 'src/generated/graphql.ts';
|
182 | 172 | }
|
183 | 173 | return 'src/generated/graphql.js';
|
184 | 174 | }
|
185 | 175 |
|
186 |
| -export function getDocumentsDefaultValue(answers: Answers) { |
187 |
| - if (answers.targets.includes(Tags.vue)) { |
| 176 | +function getDocumentsDefaultValue(targets: Tags[]): string { |
| 177 | + if (targets.includes(Tags.vue)) { |
188 | 178 | return 'src/**/*.vue';
|
189 | 179 | }
|
190 |
| - if (answers.targets.includes(Tags.angular)) { |
| 180 | + if (targets.includes(Tags.angular)) { |
191 | 181 | return 'src/**/*.ts';
|
192 | 182 | }
|
193 |
| - if (answers.targets.includes(Tags.client)) { |
| 183 | + if (targets.includes(Tags.client)) { |
194 | 184 | return 'src/**/*.tsx';
|
195 | 185 | }
|
196 | 186 | return 'src/**/*.graphql';
|
|
0 commit comments