Skip to content

Commit 4334991

Browse files
feat: non-interactive 'headless' mode
1 parent 18cdd9e commit 4334991

File tree

1 file changed

+131
-84
lines changed

1 file changed

+131
-84
lines changed

cli.js

Lines changed: 131 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { execSync } from 'child_process';
77
import inquirer from 'inquirer';
88
import chalk from 'chalk';
99
import fs from 'fs-extra';
10+
import { parseArgs } from 'node:util';
1011

1112
const __filename = fileURLToPath(import.meta.url);
1213
const __dirname = dirname(__filename);
@@ -24,95 +25,141 @@ function isValidProjectName(name) {
2425
}
2526

2627
async function main() {
27-
console.log(chalk.cyan.bold('\n🚀 Cloudinary React + Vite Boilerplate\n'));
28-
console.log(chalk.gray('💡 Need a Cloudinary account? Sign up for free: https://cloudinary.com/users/register/free\n'));
28+
29+
let answers = {};
30+
31+
if (process.argv.includes('--headless')) {
2932

30-
const answers = await inquirer.prompt([
31-
{
32-
type: 'input',
33-
name: 'projectName',
34-
message: 'What’s your project’s name?\n',
35-
default: 'my-cloudinary-app',
36-
validate: (input) => {
37-
if (!input.trim()) {
38-
return 'Project name cannot be empty';
33+
const { values, positionals } = parseArgs({
34+
options: {
35+
headless: {
36+
type: 'boolean'
37+
},
38+
projectName: {
39+
type: 'string',
40+
default: 'my-cloudinary-app'
41+
},
42+
cloudName: {
43+
type: 'string'
44+
},
45+
hasUploadPreset: {
46+
type: 'boolean',
47+
default: false
48+
},
49+
uploadPreset: {
50+
type: 'string'
51+
},
52+
aiTools: {
53+
type: 'string',
54+
multiple: true,
55+
default: ['cursor']
56+
},
57+
installDeps: {
58+
type: 'boolean',
59+
default: true
60+
},
61+
startDev: {
62+
type: 'boolean',
63+
default: false
3964
}
40-
if (!isValidProjectName(input)) {
41-
return 'Project name can only contain letters, numbers, hyphens, and underscores';
42-
}
43-
if (existsSync(input)) {
44-
return `Directory "${input}" already exists. Please choose a different name.`;
45-
}
46-
return true;
65+
}
66+
});
67+
console.log(values)
68+
69+
Object.assign(answers, values);
70+
71+
} else {
72+
73+
console.log(chalk.cyan.bold('\n🚀 Cloudinary React + Vite Boilerplate\n'));
74+
console.log(chalk.gray('💡 Need a Cloudinary account? Sign up for free: https://cloudinary.com/users/register/free\n'));
75+
76+
answers = await inquirer.prompt([
77+
{
78+
type: 'input',
79+
name: 'projectName',
80+
message: 'What’s your project’s name?\n',
81+
default: 'my-cloudinary-app',
82+
validate: (input) => {
83+
if (!input.trim()) {
84+
return 'Project name cannot be empty';
85+
}
86+
if (!isValidProjectName(input)) {
87+
return 'Project name can only contain letters, numbers, hyphens, and underscores';
88+
}
89+
if (existsSync(input)) {
90+
return `Directory "${input}" already exists. Please choose a different name.`;
91+
}
92+
return true;
93+
},
4794
},
48-
},
49-
{
50-
type: 'input',
51-
name: 'cloudName',
52-
message:
53-
'What’s your Cloudinary cloud name?\n' +
54-
chalk.gray(' → Find your cloud name: https://console.cloudinary.com/app/home/dashboard') + '\n',
55-
validate: (input) => {
56-
if (!input.trim()) {
57-
return chalk.yellow(
58-
'Cloud name is required.\n' +
59-
' → Sign up: https://cloudinary.com/users/register/free\n' +
60-
' → Find your cloud name: https://console.cloudinary.com/app/home/dashboard'
61-
);
62-
}
63-
if (!isValidCloudName(input)) {
64-
return 'Cloud name can only contain lowercase letters, numbers, hyphens, and underscores';
65-
}
66-
return true;
95+
{
96+
type: 'input',
97+
name: 'cloudName',
98+
message:
99+
'What’s your Cloudinary cloud name?\n' +
100+
chalk.gray(' → Find your cloud name: https://console.cloudinary.com/app/home/dashboard') + '\n',
101+
validate: (input) => {
102+
if (!input.trim()) {
103+
return chalk.yellow(
104+
'Cloud name is required.\n' +
105+
' → Sign up: https://cloudinary.com/users/register/free\n' +
106+
' → Find your cloud name: https://console.cloudinary.com/app/home/dashboard'
107+
);
108+
}
109+
if (!isValidCloudName(input)) {
110+
return 'Cloud name can only contain lowercase letters, numbers, hyphens, and underscores';
111+
}
112+
return true;
113+
},
67114
},
68-
},
69-
{
70-
type: 'confirm',
71-
name: 'hasUploadPreset',
72-
message:
73-
'Do you have an unsigned upload preset?\n' +
74-
chalk.gray(' → You’ll need one if you want to upload new images to Cloudinary,\n but not if you only want to transform or deliver existing images.') + '\n' +
75-
chalk.gray(' → Create one here: https://console.cloudinary.com/app/settings/upload/presets') + '\n',
76-
default: false,
77-
},
78-
{
79-
type: 'input',
80-
name: 'uploadPreset',
81-
message: 'What’s your unsigned upload preset’s name?\n',
82-
when: (answers) => answers.hasUploadPreset,
83-
validate: (input) => {
84-
if (!input.trim()) {
85-
return 'Upload preset name cannot be empty';
86-
}
87-
return true;
115+
{
116+
type: 'confirm',
117+
name: 'hasUploadPreset',
118+
message:
119+
'Do you have an unsigned upload preset?\n' +
120+
chalk.gray(' → You’ll need one if you want to upload new images to Cloudinary,\n but not if you only want to transform or deliver existing images.') + '\n' +
121+
chalk.gray(' → Create one here: https://console.cloudinary.com/app/settings/upload/presets') + '\n',
122+
default: false,
123+
},
124+
{
125+
type: 'input',
126+
name: 'uploadPreset',
127+
message: 'What’s your unsigned upload preset’s name?\n',
128+
when: (answers) => answers.hasUploadPreset,
129+
validate: (input) => {
130+
if (!input.trim()) {
131+
return 'Upload preset name cannot be empty';
132+
}
133+
return true;
134+
},
135+
},
136+
{
137+
type: 'checkbox',
138+
name: 'aiTools',
139+
message: 'Which AI coding assistant(s) are you using? (Select all that apply)',
140+
choices: [
141+
{ name: 'Cursor', value: 'cursor' },
142+
{ name: 'GitHub Copilot', value: 'copilot' },
143+
{ name: 'Claude Code / Claude Desktop', value: 'claude' },
144+
{ name: 'Other / Generic AI tools', value: 'generic' },
145+
],
146+
default: ['cursor'],
88147
},
89-
},
90-
{
91-
type: 'checkbox',
92-
name: 'aiTools',
93-
message: 'Which AI coding assistant(s) are you using? (Select all that apply)',
94-
choices: [
95-
{ name: 'Cursor', value: 'cursor' },
96-
{ name: 'GitHub Copilot', value: 'copilot' },
97-
{ name: 'Claude Code / Claude Desktop', value: 'claude' },
98-
{ name: 'Other / Generic AI tools', value: 'generic' },
99-
],
100-
default: ['cursor'],
101-
},
102-
{
103-
type: 'confirm',
104-
name: 'installDeps',
105-
message: 'Install dependencies now?\n',
106-
default: true,
107-
},
108-
{
109-
type: 'confirm',
110-
name: 'startDev',
111-
message: 'Start development server?\n',
112-
default: false,
113-
when: (answers) => answers.installDeps,
114-
},
115-
]);
148+
{
149+
type: 'confirm',
150+
name: 'installDeps',
151+
message: 'Install dependencies now?\n',
152+
default: true,
153+
},
154+
{
155+
type: 'confirm',
156+
name: 'startDev',
157+
message: 'Start development server?\n',
158+
default: false,
159+
when: (answers) => answers.installDeps,
160+
},
161+
]);
162+
}
116163

117164
const { projectName, cloudName, uploadPreset, aiTools, installDeps, startDev } = answers;
118165

0 commit comments

Comments
 (0)