Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,10 @@
},
"keywords": [],
"author": "",
"license": "ISC"
"license": "ISC",
"pnpm": {
"patchedDependencies": {
"ansi-colors@4.1.3": "patches/ansi-colors@4.1.3.patch"
}
}
}
30 changes: 18 additions & 12 deletions packages/cli/command-prompts/getProjectNamePrompt.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import inquirer from 'inquirer';
import chalk from 'chalk';
import Enquirer from 'enquirer';
import { CHECK_MARK_COLOR, LEFT_PADDING } from 'stplr-utils';

export const getProjectNamePrompt = async (): Promise<string> =>
(
await inquirer.prompt([
{
type: 'input',
name: 'name',
message: 'What is your project named?',
default: 'my-stapled-app',
},
])
).name;
export const getProjectNamePrompt = async (): Promise<string> => {
const enquirer = new Enquirer();
const response = (await enquirer.prompt({
type: 'input',
name: 'name',
message: chalk.whiteBright('What is your project named?'),
initial: 'my-stapled-app',
prefix: LEFT_PADDING,
format(value) {
return `${chalk.hex(CHECK_MARK_COLOR)(value)}`;
},
})) as { name: string };

return response.name;
};
26 changes: 17 additions & 9 deletions packages/cli/command-prompts/overwriteDirectoryPrompt.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import inquirer from 'inquirer';
import chalk from 'chalk';
import Enquirer from 'enquirer';
import { CHECK_MARK_COLOR, LEFT_PADDING } from 'stplr-utils';

/**
* Prompts the user to confirm whether they want to overwrite an existing project directory.
Expand All @@ -8,12 +10,18 @@ import inquirer from 'inquirer';
*
**/

export const overwriteDirectoryPrompt = async (projectName: string): Promise<{ overwrite: boolean }> =>
await inquirer.prompt([
{
type: 'confirm',
name: 'overwrite',
message: `The directory "${projectName}" already exists. Do you want to overwrite it?`,
default: false,
export const overwriteDirectoryPrompt = async (projectName: string): Promise<{ overwrite: boolean }> => {
const enquirer = new Enquirer();
const response = (await enquirer.prompt({
type: 'confirm',
name: 'overwrite',
message: chalk.whiteBright(`The directory "${projectName}" already exists. Do you want to overwrite it?`),
initial: false,
prefix: LEFT_PADDING,
format(value) {
return `${chalk.hex(CHECK_MARK_COLOR)(value)}`;
},
]);
})) as { overwrite: boolean };

return response;
};
26 changes: 17 additions & 9 deletions packages/cli/command-prompts/shouldUsePayloadPrompt.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import inquirer from 'inquirer';
import chalk from 'chalk';
import Enquirer from 'enquirer';
import { CHECK_MARK_COLOR, LEFT_PADDING } from 'stplr-utils';

/**
* Prompts the user to confirm whether they want to overwrite an existing project directory.
Expand All @@ -8,12 +10,18 @@ import inquirer from 'inquirer';
*
**/

export const shouldUsePayloadPrompt = async (): Promise<{ usePayload: boolean }> =>
await inquirer.prompt([
{
type: 'confirm',
name: 'usePayload',
message: 'Would you like to add Payload to your app?',
default: true,
export const shouldUsePayloadPrompt = async (): Promise<{ usePayload: boolean }> => {
const payloadEnquirer = new Enquirer();
const response = (await payloadEnquirer.prompt({
type: 'confirm',
name: 'usePayload',
message: chalk.whiteBright('Would you like to use Payload?'),
initial: true, // Default value
prefix: LEFT_PADDING, // Removes the default '?' prefix
format(value) {
return `${chalk.hex(CHECK_MARK_COLOR)(value)}`;
},
]);
})) as { usePayload: boolean };

return response;
};
88 changes: 71 additions & 17 deletions packages/cli/command-prompts/unfinishedProjectsChoicePrompt.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import inquirer from 'inquirer';
import Enquirer from 'enquirer';

import chalk from 'chalk';
import { CHECK_MARK_COLOR, LEFT_PADDING, QUESTION_MARK } from 'stplr-utils';
import { ProjectChoice, UnfinishedProject } from '../utils/findUnfinishedProjects';

export type UnfinishedProjectsChoiceAnswers = {
resume: boolean;
unfinishedSelectedProject: string;
};

export type UnfinishedProjectsChoiceResponse = {
resume: boolean;
unfinishedSelectedProject: UnfinishedProject;
};
Expand All @@ -18,21 +26,67 @@ export type UnfinishedProjectsChoiceAnswers = {
export const unfinishedProjectsChoice = async (
unfinishedProjects: UnfinishedProject[],
projectChoices: ProjectChoice[],
): Promise<UnfinishedProjectsChoiceAnswers> =>
await inquirer.prompt([
{
type: 'confirm',
name: 'resume',
message: `We found the following unfinished project(s):\n${unfinishedProjects
.map((p) => `- ${p.projectName}`)
.join('\n')}\nWould you like to resume one of them?`,
default: true,
): Promise<UnfinishedProjectsChoiceResponse> => {
const enquirer = new Enquirer();
const formattedProjectChoices = projectChoices.map((choice) => {
return {
name: choice.name,
value: choice.name,
message: chalk.whiteBright(choice.name),
};
});

// we might need to create custom prompt format like in: https://www.npmjs.com/package/enquirer#-custom-prompts
const shouldResume = (await enquirer.prompt({
type: 'confirm',
name: 'resume',
message: chalk.whiteBright(
`We found the following unfinished project(s):\n${unfinishedProjects
.map((p) => `${LEFT_PADDING} - ${p.projectName}`)
.join('\n')}\n ${LEFT_PADDING}${QUESTION_MARK} Would you like to resume one of them?`,
),
initial: true,
prefix: LEFT_PADDING,
format(value) {
return `${chalk.hex(CHECK_MARK_COLOR)(value)}`;
},
})) as { resume: boolean };

if (!shouldResume.resume) {
return {
resume: false,
unfinishedSelectedProject: unfinishedProjects[0],
};
}

const selectProjectAnswer = (await enquirer.prompt({
type: 'select',
name: 'unfinishedSelectedProject',
message: chalk.whiteBright('Select a project to resume:'),
choices: formattedProjectChoices,
prefix: ' ' + LEFT_PADDING + QUESTION_MARK,
// use it only when we want to resume a project
skip: (state: unknown) => {
if (typeof state === 'object' && state !== null && 'resume' in state) {
console.log('state', state);
return !(state as UnfinishedProjectsChoiceAnswers).resume;
}
console.log('state', state);
return false; // default fallback if not sure
},
{
type: 'list',
name: 'unfinishedSelectedProject',
message: 'Select a project to resume:',
choices: projectChoices,
when: (answers) => answers.resume && unfinishedProjects.length > 1,
format(value) {
return chalk.hex(CHECK_MARK_COLOR)(value);
},
]);
})) as UnfinishedProjectsChoiceAnswers;

const selectedProject = unfinishedProjects.find(
(project) => project.projectName === selectProjectAnswer.unfinishedSelectedProject,
);

const response = {
resume: selectProjectAnswer.resume,
unfinishedSelectedProject: selectedProject,
} as UnfinishedProjectsChoiceResponse;

return response;
};
20 changes: 9 additions & 11 deletions packages/cli/index.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
#!/usr/bin/env node
import fs from 'fs';
import chalk from 'chalk';
import { Command } from 'commander';
import fs from 'fs';
import { createProject } from 'stplr-core';
import {
checkAuthentication,
checkTools,
displayHeader,
findUnfinishedProjects,
getProjectChoices,
UnfinishedProject,
} from './utils';
import { logger } from 'stplr-utils';
import {
getProjectNamePrompt,
overwriteDirectoryPrompt,
shouldUsePayloadPrompt,
unfinishedProjectsChoice,
} from './command-prompts';
import { checkAuthentication, checkTools, findUnfinishedProjects, getProjectChoices, UnfinishedProject } from './utils';

interface Flags {
deploy?: boolean;
Expand All @@ -33,7 +27,7 @@ program
)
.version('0.1.0')
.hook('preAction', () => {
displayHeader();
logger.displayHeader();
})
.option('-n, --name <name>', 'Set the name of the project')
.option(
Expand All @@ -53,6 +47,7 @@ const createAction = async (options: Flags) => {

const unfinishedProjects: UnfinishedProject[] = findUnfinishedProjects(currentDir);

logger.withLabel('dir', 'Your project name and location');
// If no project name is provided, and there are unfinished projects, we prompt the user to resume one of them
if (!options.name && unfinishedProjects.length > 0) {
const projectChoices = getProjectChoices(unfinishedProjects);
Expand Down Expand Up @@ -104,15 +99,18 @@ const createAction = async (options: Flags) => {

// Clear the directory if overwrite is confirmed
fs.rmSync(projectDir, { recursive: true, force: true });
console.log(chalk.yellow(`The directory "${projectName}" has been cleared.`));
logger.log(`The directory "${projectName}" has been cleared.`);
}

// Skip Payload if specified by the flag
logger.withLabel('cms', 'CMS setup');
const payloadAnswer = options.skipPayload ? { usePayload: false } : await shouldUsePayloadPrompt();

const finalOptions = { name: projectName, shouldDeploy, ...payloadAnswer };
if (shouldDeploy) {
logger.withLabel('auth', 'Authentication status');
await checkAuthentication();
logger.withLabel('stapler', 'Tooling status');
await checkTools();
}

Expand Down
6 changes: 4 additions & 2 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,18 @@
"dev": "tsc -w"
},
"dependencies": {
"ansi-colors": "4.1.3",
"chalk": "^5.3.0",
"commander": "^12.1.0",
"enquirer": "^2.4.1",
"gradient-string": "^3.0.0",
"inquirer": "^10.2.2"
},
"devDependencies": {
"stplr-core": "workspace:*",
"stplr-utils": "workspace:*",
"@types/inquirer": "^9.0.7",
"@types/node": "^22.5.4",
"stplr-core": "workspace:*",
"stplr-utils": "workspace:*",
"tsup": "^8.2.4",
"typescript": "^5.6.2"
}
Expand Down
Loading