Skip to content

Commit d6c2669

Browse files
authored
[CLI] Bump deps for next major version (#10405)
* Bump listr2 * Migrate implementation and update tests for listr2 * Migrate inquirer to inquirer/prompts
1 parent 9b9c4e7 commit d6c2669

File tree

10 files changed

+343
-294
lines changed

10 files changed

+343
-294
lines changed

.changeset/smooth-pans-walk.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@graphql-codegen/cli': major
3+
---
4+
5+
Migrate inquirer to @inquirer/prompts

.changeset/tough-apricots-bake.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@graphql-codegen/cli': major
3+
---
4+
5+
Bump listr2 to v9

packages/graphql-codegen-cli/package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,17 @@
5555
"@graphql-tools/load": "^8.1.0",
5656
"@graphql-tools/url-loader": "^8.0.0",
5757
"@graphql-tools/utils": "^10.0.0",
58+
"@inquirer/prompts": "^7.8.2",
5859
"@whatwg-node/fetch": "^0.10.0",
5960
"chalk": "^4.1.0",
6061
"cosmiconfig": "^9.0.0",
6162
"debounce": "^2.0.0",
6263
"detect-indent": "^6.0.0",
6364
"graphql-config": "^5.1.1",
64-
"inquirer": "^8.0.0",
6565
"is-glob": "^4.0.1",
6666
"jiti": "^2.3.0",
6767
"json-to-pretty-yaml": "^1.2.2",
68-
"listr2": "^4.0.5",
68+
"listr2": "^9.0.0",
6969
"log-symbols": "^4.0.0",
7070
"micromatch": "^4.0.5",
7171
"shell-quote": "^1.7.3",
@@ -78,7 +78,6 @@
7878
"devDependencies": {
7979
"@graphql-tools/merge": "9.0.6",
8080
"@parcel/watcher": "^2.1.0",
81-
"@types/inquirer": "8.2.10",
8281
"@types/is-glob": "4.0.4",
8382
"@types/js-yaml": "4.0.9",
8483
"@types/micromatch": "^4.0.2",

packages/graphql-codegen-cli/src/codegen.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -397,8 +397,17 @@ export async function executeCodegen(
397397
},
398398
],
399399
{
400-
// it stops when of the tasks failed
400+
/**
401+
* For each `generates` task, we must do the following in order:
402+
*
403+
* 1. Load schema
404+
* 2. Load documents
405+
* 3. Generate based on the schema + documents
406+
*
407+
* This way, the 3rd step has all the schema and documents loaded in previous steps to work correctly
408+
*/
401409
exitOnError: true,
410+
concurrent: false,
402411
}
403412
);
404413
},
@@ -414,13 +423,13 @@ export async function executeCodegen(
414423
{
415424
rendererOptions: {
416425
clearOutput: false,
417-
collapse: true,
426+
collapseSubtasks: true,
418427
formatOutput: 'wrap',
419428
removeEmptyLines: false,
420429
},
421430
renderer: config.verbose ? 'verbose' : 'default',
422431
ctx: { errors: [] },
423-
rendererSilent: isTest || config.silent,
432+
silentRendererCondition: isTest || config.silent,
424433
exitOnError: true,
425434
}
426435
);

packages/graphql-codegen-cli/src/init/index.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { Types } from '@graphql-codegen/plugin-helpers';
2-
import inquirer from 'inquirer';
32
import { bold, writeConfig, writePackage } from './helpers.js';
4-
import { getQuestions } from './questions.js';
3+
import { getAnswers } from './questions.js';
54
import { guessTargets } from './targets.js';
6-
import { Answers, Tags } from './types.js';
5+
import { Tags } from './types.js';
76

87
function log(...msgs: string[]) {
98
// eslint-disable-next-line no-console
@@ -17,8 +16,7 @@ export async function init() {
1716
`);
1817

1918
const possibleTargets = await guessTargets();
20-
21-
const answers = await inquirer.prompt<Answers>(getQuestions(possibleTargets));
19+
const answers = await getAnswers(possibleTargets);
2220

2321
// define config
2422
const config: Types.Config = {

packages/graphql-codegen-cli/src/init/questions.ts

Lines changed: 80 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,92 @@
1-
import inquirer from 'inquirer';
1+
import { checkbox, input, select, confirm } from '@inquirer/prompts';
22
import { grey } from './helpers.js';
33
import { plugins } from './plugins.js';
4-
import { Answers, Tags } from './types.js';
4+
import { type Answers, type PluginOption, Tags } from './types.js';
55

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({
1111
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)')}`,
2117
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+
});
3220

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+
});
4928

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({
5939
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({
6745
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({
7250
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)
7753
? 'codegen.ts'
78-
: 'codegen.yml',
79-
validate: (str: string) => {
54+
: 'codegen.yml')(),
55+
validate: str => {
8056
const isNotEmpty = str.length > 0;
8157
const hasCorrectExtension = ['json', 'yml', 'yaml', 'js', 'ts'].some(ext =>
8258
str.toLocaleLowerCase().endsWith(`.${ext}`)
8359
);
8460

8561
return isNotEmpty && hasCorrectExtension;
8662
},
87-
},
88-
{
89-
type: 'input',
90-
name: 'script',
63+
});
64+
65+
const script = await input({
9166
default: 'codegen',
9267
message: 'What script in package.json should run the codegen?',
9368
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+
}
9690
}
9791

9892
export function getApplicationTypeChoices(possibleTargets: Record<Tags, boolean>) {
@@ -154,43 +148,39 @@ export function getApplicationTypeChoices(possibleTargets: Record<Tags, boolean>
154148
];
155149
}
156150

157-
export function getPluginChoices(answers: Answers) {
151+
export function getPluginChoices(targets: Tags[]) {
158152
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 => {
161155
return {
162156
name: p.name,
163157
value: p,
164-
checked: p.shouldBeSelected(answers.targets),
158+
checked: p.shouldBeSelected(targets),
165159
};
166160
});
167161
}
168162

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)) {
175165
return 'src/gql/';
176166
}
177-
if (answers.plugins.some(plugin => plugin.defaultExtension === '.tsx')) {
167+
if (plugins.some(plugin => plugin.defaultExtension === '.tsx')) {
178168
return 'src/generated/graphql.tsx';
179169
}
180-
if (answers.plugins.some(plugin => plugin.defaultExtension === '.ts')) {
170+
if (plugins.some(plugin => plugin.defaultExtension === '.ts')) {
181171
return 'src/generated/graphql.ts';
182172
}
183173
return 'src/generated/graphql.js';
184174
}
185175

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)) {
188178
return 'src/**/*.vue';
189179
}
190-
if (answers.targets.includes(Tags.angular)) {
180+
if (targets.includes(Tags.angular)) {
191181
return 'src/**/*.ts';
192182
}
193-
if (answers.targets.includes(Tags.client)) {
183+
if (targets.includes(Tags.client)) {
194184
return 'src/**/*.tsx';
195185
}
196186
return 'src/**/*.graphql';

packages/graphql-codegen-cli/tests/__snapshots__/init.spec.ts.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ export default config;
9999
"
100100
`;
101101

102-
exports[`init should have few default values 1`] = `
102+
exports[`init should have few default values for Angular 1`] = `
103103
"
104104
import type { CodegenConfig } from '@graphql-codegen/cli';
105105
@@ -119,7 +119,7 @@ export default config;
119119
"
120120
`;
121121

122-
exports[`init should have few default values 2`] = `
122+
exports[`init should have few default values for React 1`] = `
123123
"overwrite: true
124124
schema: "./schema.ts"
125125
documents: "graphql/**/*.graphql"

0 commit comments

Comments
 (0)