| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- #!/usr/bin/env node
- import fs from 'fs-extra';
- import path from 'node:path';
- import { fileURLToPath } from 'node:url';
- import * as p from '@clack/prompts';
- import { bold, cyan, grey, red, blue } from 'kleur/colors';
- import minimist from 'minimist';
- import * as langAll from './lang';
- // 获取版本号
- // Get version
- // @ts-ignore
- const { version } = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf-8'));
- // 显示版本号
- // Display version number
- console.log(`
- ${grey(`create-stdf@${version}
- `)}`);
- const spinner = p.spinner();
- p.intro('Welcome to use STDF!');
- let lang = langAll.en_US;
- // 获取命令行参数
- // Get command line parameters
- const argv = minimist(process.argv.slice(2));
- // 获取项目名称和模板名称和语言
- // Get project name and template name
- const argvProjectName = argv._[0];
- const argvTemplate = argv.template || argv.t;
- const argvLanguage = argv.language || argv.l;
- // 语言列表
- // Language list
- const languages = [];
- // 循环 langAll 对象,将语言列表中的语言名字替换为对应的语言名字,且按照 sort 排序
- // Loop through the langAll object and replace the language name in the language list with the corresponding language name, and sort by sort
- for (const key in langAll) {
- languages.push({
- value: key,
- label: langAll[key].name,
- sort: langAll[key].sort,
- });
- }
- // 按照 sort 排序
- // Sort by sort
- languages.sort((a, b) => a.sort - b.sort);
- // 如果命令行参数中有语言,且语言列表中有该语言,使用该语言,否则使用英语
- // If there is a language in the command line parameters and the language list has the language, use the language, otherwise use English
- lang = argvLanguage && languages.find(item => item.value === argvLanguage) ? langAll[argvLanguage] : langAll.en_US;
- // 模板列表
- // Template list
- const templateOptions = [
- { value: 'skt', label: 'SvelteKit + Tailwind', template: 'sveltekit-tailwind', finish: true },
- { value: 'vt', label: 'Vite + Tailwind', template: 'vite-tailwind', finish: true },
- { value: 'vu', label: 'Vite + UnoCSS', template: 'vite-uno', finish: true },
- { value: 'sku', label: 'SvelteKit + UnoCSS', template: 'sveltekit-uno', finish: true },
- { value: 'vtt', label: 'Vite + Tailwind + TypeScript', template: 'vite-tailwind-typescript', finish: false },
- { value: 'vut', label: 'Vite + UnoCSS + TypeScript', template: 'vite-uno-typescript', finish: false },
- { value: 'sktt', label: 'SvelteKit + Tailwind + TypeScript', template: 'sveltekit-tailwind-typescript', finish: false },
- { value: 'skut', label: 'SvelteKit + UnoCSS + TypeScript', template: 'sveltekit-uno-typescript', finish: false },
- ];
- // 如果命令行参数中有项目名称,但没有模板名称,直接使用默认模板 skt
- // If there is a project name in the command line parameters, but no template name, use the default template skt directly
- if (argvProjectName && !argvTemplate) {
- createFunc(argvProjectName, templateOptions[0]);
- }
- // 如果命令行参数中有项目名称和模板名称,直接使用命令行参数中的值
- // If there is a project name and template name in the command line parameters, use the value in the command line parameters directly
- else if (argvProjectName && argvTemplate) {
- const item = templateOptions.find(item => item.value === argvTemplate);
- if (!item) {
- p.intro(red(lang.pectn));
- } else if (!item.finish) {
- p.intro(red(item.label + ' ' + lang.hnay));
- } else {
- createFunc(argvProjectName, item);
- }
- } else {
- (async () => {
- // 选择一种语言
- // Select a language
- const languageType = await p.select({
- message: bold('Please select your preferred language'),
- options: languages,
- });
- if (p.isCancel(languageType)) {
- p.cancel(red('⛔ ') + lang.oc);
- process.exit(0);
- }
- lang = langAll[languageType];
- // 选择一个模板
- // Select a template
- let template = await p.select({
- message: bold(lang.psat),
- options: templateOptions,
- });
- if (p.isCancel(template)) {
- p.cancel(red('⛔ ') + lang.oc);
- process.exit(0);
- }
- // 直到选择的 template 所在项 的 finish 为 true 为止,否则一直重新选择
- // Until the finish of the selected template is true, otherwise keep reselecting
- while (!templateOptions.find(item => item.value === template)?.finish) {
- if (p.isCancel(template)) {
- p.cancel(red('⛔ ') + lang.oc);
- process.exit(0);
- }
- p.intro(red(templateOptions.find(item => item.value === template).label + ' ' + lang.hnay + ' ' + lang.pca));
- template = await p.select({
- message: bold(lang.psat),
- options: templateOptions,
- });
- }
- // 是否启用类型检查
- // Whether to enable type checking
- const isTypeCheck = await p.confirm({
- message: bold(lang.wtetcfjsf),
- });
- if (p.isCancel(isTypeCheck)) {
- p.cancel(red('⛔ ') + lang.oc);
- process.exit(0);
- }
- // 输入项目名称
- // Enter the project name
- const projectName = await p.text({
- message: bold(lang.pn),
- placeholder: 'stdf-project',
- validate: value => {
- if (!value) {
- // 判断是否为空,提示 “项目名称不能为空”
- // Determine whether it is empty, prompt "Project name cannot be empty"
- return lang.pncbne;
- }
- if (fs.existsSync(value)) {
- // 判断是否已存在,提示 “项目名称已存在”
- // Determine whether it already exists, prompt "Project name already exists"
- return lang.pane;
- }
- },
- });
- if (p.isCancel(projectName)) {
- p.cancel(red('⛔ ') + lang.oc);
- process.exit(0);
- }
- // 根据 template 的值,复制对应目录下的所有文件到当前目录
- // According to the value of template, copy all files under the corresponding directory to the current directory
- templateOptions.forEach(async item => {
- if (item.value === template) {
- createFunc(projectName, item, isTypeCheck);
- }
- });
- })();
- }
- function createFunc(projectName, item, isTypeCheck = true) {
- // 如果 projectName 是数字,转为字符串
- // If projectName is a number, convert it to a string
- if (typeof projectName === 'number') {
- projectName = projectName.toString();
- }
- // 项目目录
- // Project directory
- const projectDir = path.join(path.resolve(), projectName);
- spinner.start('🚀 ' + lang.cfsing);
- fs.mkdirSync(projectDir);
- // 获取模板目录的绝对路径,考虑到 Windows 系统的兼容性, 使用 path.join
- // Get the absolute path of the template directory, considering the compatibility of the Windows system, use path.join
- // @ts-ignore
- const templatePath = path.resolve(fileURLToPath(import.meta.url), '../..', `templates/${item.template}`);
- // 将 templatePath 目录下的所有文件复制到 projectDir 目录下
- // Copy all files under the templatePath directory to the projectDir directory\
- fs.copy(templatePath, projectDir)
- .then(() => {
- spinner.stop();
- p.outro(`${projectName} - ${lang.pcsucc} 🎉`);
- // 如果 isTypeCheck 为 true,将 common 目录下的 jsconfig.json 文件复制到项目目录下
- // If isTypeCheck is true, copy the jsconfig.json file under the common directory to the project directory
- if (isTypeCheck) {
- // @ts-ignore
- const commonPath = path.resolve(fileURLToPath(import.meta.url), '../..', 'common');
- fs.copySync(path.join(commonPath, '/jsconfig.json'), path.join(projectDir, 'jsconfig.json'));
- }
- // 读取 package.json 文件
- // Read the package.json file
- const packageJson = JSON.parse(fs.readFileSync(`${projectDir}/package.json`, 'utf-8'));
- // 将项目内的 package.json 中的 name 属性修改为 projectName
- // Modify the name attribute in package.json in the project to projectName
- packageJson.name = projectName;
- // 将修改后的 packageJson 写入到项目内的 package.json 文件中
- // Write the modified packageJson to the package.json file in the project
- fs.writeFileSync(`${projectDir}/package.json`, JSON.stringify(packageJson, null, 4), 'utf-8');
- // 根据 item.value 的值,判断是否使用了 @sveltejs/kit
- // According to the value of item.value, determine whether @sveltejs/kit is used
- const isHasKit = item.value === 'skt' || item.value === 'sku' || item.value === 'sktt' || item.value === 'skut';
- // 根据 item.value 的值,判断使用 Tailwind 还是 UnoCSS
- // According to the value of item.value, determine whether to use Tailwind or UnoCSS
- const isHasUno = item.value === 'vu' || item.value === 'sku' || item.value === 'vut' || item.value === 'skut';
- // 获得依赖的版本号
- // get the version number of the dependency
- const versions = {
- vite: packageJson.devDependencies.vite.replace('^', ''),
- svelte: packageJson.devDependencies.svelte.replace('^', ''),
- stdf: packageJson.devDependencies.stdf.replace('^', ''),
- };
- if (isHasKit) {
- versions['@sveltejs/kit'] = packageJson.devDependencies['@sveltejs/kit'].replace('^', '');
- }
- if (isHasUno) {
- versions['unocss'] = packageJson.devDependencies.unocss.replace('^', '');
- } else {
- versions['tailwindcss'] = packageJson.devDependencies.tailwindcss.replace('^', '');
- }
- // 将 versions 的键值拼接为 bold('Vite:') cyan(versions.vite) bold('Svelte:') cyan(versions.svelte) 的形式
- // Splice the key value of versions into the form of bold('Vite:') cyan(versions.vite) bold('Svelte:') cyan(versions.svelte)
- let versionsString = '';
- for (const key in versions) {
- versionsString += bold(key) + ': ' + cyan(versions[key]) + ' ';
- }
- // 显示版本号
- // Display version number
- console.log(`📦 ${versionsString}
- `);
- // 显示提示信息
- // Display prompt information
- console.log(
- `👉 ${bold(lang.tgs)}
- ${blue(`cd ${projectName}`)}
- ${blue('pnpm i / npm i / yarn / bun i')}
- ${blue('npm dev / bun dev')}
- `,
- );
- // 显示配置主题色
- // Display configuration theme color
- console.log(
- `🎨 ${grey(isHasUno ? lang.pcyt_vu : lang.pcyt_vt)}
- `,
- );
- })
- .catch(err => {
- spinner.stop();
- console.error(red(lang.cferror + '--' + err));
- });
- }
|