Skip to content

Commit

Permalink
[cli] overhaul cli prompts via clack
Browse files Browse the repository at this point in the history
  • Loading branch information
danstepanov committed Apr 2, 2024
1 parent 99c01e5 commit 9becc72
Show file tree
Hide file tree
Showing 8 changed files with 237 additions and 171 deletions.
5 changes: 5 additions & 0 deletions .changeset/breezy-pigs-boil.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'create-expo-stack': patch
---

overhaul cli prompts via clack
Binary file modified bun.lockb
Binary file not shown.
27 changes: 19 additions & 8 deletions cli/src/commands/create-expo-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { DEFAULT_APP_NAME, defaultOptions } from '../constants';
import { CliResults, availablePackages } from '../types';
import clearStylingPackages from '../utilities/clearStylingPackages';
import { validateProjectName } from '../utilities/validateProjectName';
import { cancel, intro, isCancel, text } from '@clack/prompts';

const navigationValidationError = `You must pass in either --react-navigation or --expo-router if you want to use the --tabs or --drawer+tabs options`;
const projectNameValidationError = `A project with the name`;
Expand Down Expand Up @@ -72,18 +73,29 @@ const command: GluegunCommand = {
}

await renderTitle(toolbox);
intro(`Let's get started!`);

// Prompt the user for the project name if it is not passed in via the command
// - TODO: simplify this if statement to clarify what is being checked
if (!first && (options.ignite || !(useDefault || optionsPassedIn || skipCLI || useBlankTypescript))) {
const askName = {
type: 'input',
name: 'name',
message: `What do you want to name your project? (${DEFAULT_APP_NAME})`
};
const { name } = await prompt.ask(askName);
const name = await text({
message: 'What do you want to name your project?',
placeholder: DEFAULT_APP_NAME
});

if (isCancel(name)) {
cancel('Cancelled... 👋');
return process.exit(0);
}

// const askName = {
// type: 'input',
// name: 'name',
// message: `What do you want to name your project? (${DEFAULT_APP_NAME})`
// };
// const { name } = await prompt.ask(askName);
// if name is undefined or empty string, use default name
cliResults.projectName = name || DEFAULT_APP_NAME;
cliResults.projectName = (name && name.toString()) || DEFAULT_APP_NAME;
} else {
// Destructure the results but set the projectName if the first param is passed in
cliResults.projectName = first || DEFAULT_APP_NAME;
Expand All @@ -103,7 +115,6 @@ const command: GluegunCommand = {
removeAsync,
!(useDefault || optionsPassedIn || skipCLI || useBlankTypescript) ? prompt : null,
cliResults.projectName,
success,
cliResults.flags.overwrite
);
} catch (err: string | any) {
Expand Down
6 changes: 6 additions & 0 deletions cli/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,14 @@ export const availablePackages = [
'i18next'
] as const;

export type AuthenticationSelect = 'supabase' | 'firebase' | undefined;

export type NavigationSelect = 'react-navigation' | 'expo-router' | undefined;

export type NavigationTypes = 'stack' | 'tabs' | 'drawer + tabs' | undefined;

export type StylingSelect = 'nativewind' | 'restyle' | 'stylesheet' | 'tamagui' | 'unistyles';

export type PackageManager = 'yarn' | 'npm' | 'pnpm' | 'bun';

export type Internalization = 'i18next';
Expand Down
73 changes: 34 additions & 39 deletions cli/src/utilities/printOutput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Toolbox } from 'gluegun/build/types/domain/toolbox';
import { getPackageManager, getPackageManagerRunnerX } from './getPackageManager';
import { AvailablePackages, CliResults } from '../types';
import { copyBaseAssets } from './copyBaseAssets';
import { outro, spinner } from '@clack/prompts';

export async function printOutput(
cliResults: CliResults,
Expand All @@ -17,61 +18,52 @@ export async function printOutput(
} = toolbox;

const { projectName, flags } = cliResults;
const s = spinner();

// Output the results to the user
info(``);
highlight(`Initializing your project...`);

s.start('Initializing your project...');
await Promise.all(formattedFiles);
s.stop('Project initialized!');

info(``);
highlight(`Copying base assets...`);
s.start('Copying base assets...');
await copyBaseAssets(projectName, toolbox);
s.stop('Base assets copied!');

// check if npm option is set, otherwise set based on what the system is configure to use
const packageManager = cliResults.flags.packageManager || getPackageManager(toolbox, cliResults);

if (!options.noInstall && !flags.noInstall) {
info(``);
highlight(`Installing dependencies using ${packageManager}...`);
info(``);

s.start(`Installing dependencies using ${packageManager}...`);
// install with yarn or npm i
await system.spawn(`cd ${projectName} && ${packageManager} install --silent`, {
shell: true,
stdio: 'inherit'
});
s.stop('Dependencies installed!');

info(``);
highlight(`Cleaning up your project...`);
info(``);

s.start(`Cleaning up your project...`);
// format the files with prettier and eslint using installed packages.
await system.spawn(`cd ${projectName} && ${packageManager} run format`, {
shell: true,
stdio: 'inherit'
});
s.stop('Project files formatted!');
} else {
const runnerType = getPackageManagerRunnerX(toolbox, cliResults);

info(``);
highlight(`No installation found.`);
highlight(`Cleaning up your project using ${runnerType}...`);
info(``);

s.start(`No installation found.\nCleaning up your project using ${runnerType}...`);
// Running prettier using global runners against the template.
// Use --no-config to prevent using project's config (that may have plugins/dependencies)
await system.spawn(`${runnerType} prettier "${projectName}/**/*.{json,js,jsx,ts,tsx}" --no-config --write`, {
shell: true,
stdio: 'inherit'
});
s.stop('Project files formatted!');
}

if (!options.noGit && !flags.noGit) {
info(``);
highlight(`Initializing git...`);
info(``);

s.start(`Initializing git...`);
// initialize git repo and add first commit
await system.spawn(
`cd ${projectName} && git init --quiet && git add . && git commit -m "Initial commit" -m "Generated by create-expo-stack 2.0.0." --quiet`,
Expand All @@ -80,11 +72,12 @@ export async function printOutput(
stdio: 'inherit'
}
);
s.stop(`Git initialized!`);
}

// check if packages includes package with name "supabase"
if (cliResults.packages.some((pkg) => pkg.name === 'supabase')) {
success(`Success! 🎉 Now, here's what's next:`);
success(`\nSuccess! 🎉 Now, here's what's next:`);
info(``);
highlight('Head over to https://database.new to create a new Supabase project.');
info(``);
Expand All @@ -98,7 +91,7 @@ export async function printOutput(
success(`Once you're done, run the following to get started: `);
info(``);
} else if (cliResults.packages.some((pkg) => pkg.name === 'firebase')) {
success(`Success! 🎉 Now, here's what's next:`);
success(`\nSuccess! 🎉 Now, here's what's next:`);
info(``);
highlight('Head over to https://console.firebase.google.com/ to create a new Firebase project.');
info(``);
Expand All @@ -113,37 +106,39 @@ export async function printOutput(
success(`Once you're done, run the following to get started: `);
info(``);
} else {
success('Success! 🎉 Now, just run the following to get started: ');
success('\nSuccess! 🎉 Now, just run the following to get started: ');
info(``);
}
info(`cd ${projectName}`);
let step = 1;
highlight(`${step}. cd ${projectName}`);
if (packageManager === 'npm') {
if (options.noInstall) info('npm install');
if (options.noInstall) highlight(`${++step}. npm install`);
if (stylingPackage.name === 'unistyles') {
info('npx expo prebuild --clean');
highlight(`${++step}. npx expo prebuild --clean`);
}
info('npm run ios');
highlight(`${++step}. npm run ios`);
} else if (packageManager === 'pnpm') {
if (options.noInstall) info('pnpm install');
if (options.noInstall) highlight(`${++step}. pnpm install`);
if (stylingPackage.name === 'unistyles') {
info('pnpm expo prebuild --clean');
highlight(`${++step}. pnpm expo prebuild --clean`);
}
info('pnpm run ios');
highlight(`${++step}. pnpm run ios`);
} else if (packageManager === 'bun') {
if (options.noInstall) info('bun install');
if (options.noInstall) highlight(`${++step}. bun install`);
if (stylingPackage.name === 'unistyles') {
info('bun expo prebuild --clean');
highlight(`${++step}. bun expo prebuild --clean`);
}
info('bun run ios');
highlight(`${++step}. bun run ios`);
} else {
if (options.noInstall) info('yarn install');
if (options.noInstall) highlight(`${++step}. yarn install`);
if (stylingPackage.name === 'unistyles') {
info('yarn expo prebuild --clean');
highlight(`${++step}. yarn expo prebuild --clean`);
}
info('yarn ios');
highlight(`${++step}. yarn ios`);
}
info(``);

success(`If you frequently use create expo stack, please consider sponsoring the project ❤️`);
highlight(`https://github.com/sponsors/danstepanov`);
outro(
'If you frequently use create expo stack, please consider sponsoring the project ❤️\n- https://github.com/sponsors/danstepanov'
);
}
Loading

0 comments on commit 9becc72

Please sign in to comment.