Skip to content

Commit

Permalink
feat(cli): add interactive template selection
Browse files Browse the repository at this point in the history
  • Loading branch information
heyqbnk committed Apr 7, 2024
1 parent 5c516f9 commit 842ff3a
Show file tree
Hide file tree
Showing 9 changed files with 586 additions and 162 deletions.
4 changes: 3 additions & 1 deletion packages/create-mini-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,11 @@
"access": "public"
},
"dependencies": {
"@inquirer/prompts": "^4.3.2",
"ansi-escapes": "^6.2.1",
"chalk": "^5.3.0",
"commander": "^12.0.0",
"inquirer": "^9.2.15",
"figures": "^6.1.0",
"ora": "^8.0.1"
}
}
8 changes: 5 additions & 3 deletions packages/create-mini-app/src/cloneTemplate.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import chalk from 'chalk';

import { spawnWithSpinner } from './spawnWithSpinner.js';
import type { TemplateRepository } from './templates.js';
import type { TemplateRepository } from './types.js';

const { bold, blue, red } = chalk;

Expand All @@ -22,6 +22,8 @@ export async function cloneTemplate(
link,
}: TemplateRepository,
): Promise<void> {
const titleSuccess = bold(`Template was cloned: ${blue(link)}`);

// Clone the template using https.
try {
await spawnWithSpinner({
Expand All @@ -34,7 +36,7 @@ export async function cloneTemplate(
: `Error code: ${red(outputOrCode)}`
}`;
},
titleSuccess: `Cloned the template: ${bold(blue(link))}`,
titleSuccess,
});
return;
} catch (e) { /* empty */
Expand All @@ -51,6 +53,6 @@ export async function cloneTemplate(
: `Error code: ${red(outputOrCode)}`
}`;
},
titleSuccess: `Cloned the template: ${bold(blue(link))}`,
titleSuccess,
});
}
23 changes: 17 additions & 6 deletions packages/create-mini-app/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { program } from 'commander';

import { cloneTemplate } from './cloneTemplate.js';
import { isGitInstalled } from './isGitInstalled.js';
import { promptRootDir } from './promptRootDir.js';
import { promptRootDir, promptTemplate } from './prompts.js';
import { spawnWithSpinner } from './spawnWithSpinner.js';
import { filterTemplates } from './templates.js';
import type { TemplateRepository } from './types.js';
import packageJson from '../package.json';

const { bold, green, red } = chalk;
Expand All @@ -20,18 +20,29 @@ program
.action(async () => {
// Check if git is installed.
if (!await isGitInstalled()) {
console.error('To run this CLI tool, git should be installed. Installation guide: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git');
console.error('To run this CLI tool, git is required. Installation guide: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git');
process.exit(1);
}

// Prompt the project root directory name.
let rootDir: string | null = null;
while (!rootDir) {
console.clear();
rootDir = await promptRootDir();
try {
rootDir = await promptRootDir();
} catch {
process.exit(0);
}
}

const [{ repository }] = filterTemplates('ts', 'tma.js', 'react.js');
// Prompt the target template.
let repository: TemplateRepository;
try {
const { repository: promptRepo } = await promptTemplate();
repository = promptRepo;
} catch {
process.exit(0);
}

// Clone the template.
try {
Expand Down Expand Up @@ -60,7 +71,7 @@ program

console.log([
green(bold('Your project has been successfully initialized!')),
`Now, open the ${bold(rootDir)} directory and follow the instructions presented in the ${bold('README.md')} file.`,
`Now, open the ${bold(rootDir)} directory and follow the instructions presented in the ${bold('README.md')} file. ${bold('Happy coding! 🚀')}`,
].join('\n'));
});

Expand Down
48 changes: 0 additions & 48 deletions packages/create-mini-app/src/promptRootDir.ts

This file was deleted.

48 changes: 48 additions & 0 deletions packages/create-mini-app/src/prompts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { existsSync } from 'node:fs';
import { basename } from 'node:path';

import { confirm, input } from '@inquirer/prompts';
import chalk from 'chalk';

import { templatePrompt } from './prompts/templatePrompt.js';
import { toAbsolute } from './toAbsolute.js';
import type { AnyTemplate } from './types.js';

/**
* Prompts current user project root directory.
* @returns Directory name.
*/
export async function promptRootDir(): Promise<string | null> {
const rootDir = await input({
message: 'Enter the directory name:',
validate(value) {
if (value.length === 0) {
return 'Directory name should not be empty.';
}

const dir = toAbsolute(value);
if (existsSync(dir)) {
return `Directory already exists: ${dir}`;
}

if (value !== basename(value)) {
return `Value "${value}" contains invalid symbols.`;
}

return true;
},
});

const confirmed = await confirm({
message: `Is this your desired directory? ${chalk.green(toAbsolute(rootDir))}`,
});

return confirmed ? rootDir : null;
}

/**
* Prompts a preferred template.
*/
export async function promptTemplate(): Promise<AnyTemplate> {
return templatePrompt({});
}
Loading

0 comments on commit 842ff3a

Please sign in to comment.