diff --git a/package.json b/package.json
index 9798f7d..c8b5ec5 100644
--- a/package.json
+++ b/package.json
@@ -47,6 +47,8 @@
"fs-extra": "^10.0.1",
"jsonfile": "^6.1.0",
"minimist": "^1.2.5",
+ "nanoid": "^3.3.1",
+ "ora": "^5.0.0",
"preferred-pm": "^3.0.3",
"prettier": "^2.5.1",
"prompts": "^2.4.2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a7592fc..9d370d2 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -27,6 +27,8 @@ importers:
jsonfile: ^6.1.0
lodash: ^4.17.21
minimist: ^1.2.5
+ nanoid: ^3.3.1
+ ora: ^5.0.0
preferred-pm: ^3.0.3
prettier: ^2.5.1
prompts: ^2.4.2
@@ -57,6 +59,8 @@ importers:
fs-extra: 10.0.1
jsonfile: 6.1.0
minimist: 1.2.5
+ nanoid: 3.3.1
+ ora: 5.4.1
preferred-pm: 3.0.3
prettier: 2.5.1
prompts: 2.4.2
@@ -23886,11 +23890,6 @@ packages:
resolution: {integrity: sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==}
dev: false
- /nanoid/3.2.0:
- resolution: {integrity: sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==}
- engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
- hasBin: true
-
/nanoid/3.3.1:
resolution: {integrity: sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -27650,7 +27649,7 @@ packages:
resolution: {integrity: sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==}
engines: {node: ^10 || ^12 || >=14}
dependencies:
- nanoid: 3.2.0
+ nanoid: 3.3.1
picocolors: 1.0.0
source-map-js: 1.0.2
diff --git a/scripts/cli.ts b/scripts/cli.ts
index 541bf08..8df2793 100644
--- a/scripts/cli.ts
+++ b/scripts/cli.ts
@@ -9,6 +9,7 @@ import useCreateSimplePackage from './create-package';
import useCopyPackage from './copy-package';
import useCachePackage from './cache-package';
import useRenameWorkspacePackage from './rename-package';
+import useForkWorkspace from './fork-workspace';
const cli = cac('LinbuduLab-Starter');
@@ -22,6 +23,7 @@ useCreateSimplePackage(cli);
useCopyPackage(cli);
useCachePackage(cli);
useRenameWorkspacePackage(cli);
+useForkWorkspace(cli);
cli.help();
cli.parse();
diff --git a/scripts/fork-workspace.ts b/scripts/fork-workspace.ts
new file mode 100644
index 0000000..c15f197
--- /dev/null
+++ b/scripts/fork-workspace.ts
@@ -0,0 +1,155 @@
+import { CAC } from 'cac';
+import fs from 'fs-extra';
+
+import chalk from 'chalk';
+import { CLIUtils, Constants } from './utils';
+import consola from 'consola';
+import path from 'path';
+import ora from 'ora';
+
+export default function useForkWorkspace(cli: CAC) {
+ cli
+ .command('fork [workspaceName]
', 'fork workspace to a new folder')
+ .option('-f, --force', 'rm workspace dir if exists')
+ .action(
+ async (
+ workspaceName: string,
+ dir?: string,
+ options?: {
+ force: boolean;
+ }
+ ) => {
+ const { force = false } = options ?? {};
+
+ const defaultBaseDir = path.dirname(process.cwd());
+
+ const forkedWorkspaceLocation = path.resolve(
+ defaultBaseDir,
+ 'tmp',
+ dir ?? 'forked'
+ );
+
+ consola.info(
+ `Forked workspace will be created in: ${chalk.green(
+ forkedWorkspaceLocation
+ )}`
+ );
+
+ if (fs.existsSync(forkedWorkspaceLocation)) {
+ if (force) {
+ // TODO: confirm
+ consola.warn(`A non-empty dir will be removed.`);
+
+ const confirm = await CLIUtils.createConfirmSelector(
+ 'Confirm Operation?'
+ );
+
+ confirm
+ ? fs.rmSync(forkedWorkspaceLocation, {
+ recursive: true,
+ })
+ : consola.info('Operation Cancelled');
+
+ !confirm && process.exit(0);
+ } else {
+ consola.fatal(
+ `Target workspace dir: ${chalk.green(
+ forkedWorkspaceLocation
+ )} exists, use ${chalk.white('-f, --force')} to overwrite it.`
+ );
+
+ process.exit(0);
+ }
+ }
+
+ const pickedPackages = await CLIUtils.createPackageMultiSelector(
+ 'picked',
+ 'Pick packages to use in forked workspace',
+ false
+ );
+
+ consola.info(
+ `Forking workspace packages: ${chalk.white(
+ pickedPackages.join(', ')
+ )}...`
+ );
+
+ for (const pkg of pickedPackages) {
+ const packageSourcePath = CLIUtils.resolvePackageDir(pkg);
+ const packageDestPath = path.resolve(
+ forkedWorkspaceLocation,
+ 'packages',
+ pkg
+ );
+
+ fs.copySync(packageSourcePath, packageDestPath, {
+ recursive: true,
+ filter: (src, dest) => {
+ const filtered = ['node_modules', 'dist', 'tmp'].every(
+ (pattern) => !src.includes(pattern)
+ );
+
+ return filtered;
+ },
+ });
+ }
+
+ consola.success(`Workspace packages copied.`);
+
+ consola.info(`Forking workspace assets...`);
+
+ const workspaceBase = fs
+ .readdirSync(process.cwd())
+ .filter(
+ (d) =>
+ !['node_modules', 'dist', 'tmp', '.git', 'packages'].includes(d)
+ );
+
+ for (const baseAsset of workspaceBase) {
+ const baseAssetPath = path.resolve(process.cwd(), baseAsset);
+
+ const forkedAssetPath = path.resolve(
+ forkedWorkspaceLocation,
+ baseAsset
+ );
+
+ fs.copySync(baseAssetPath, forkedAssetPath);
+ }
+
+ consola.success(`Workspace assets copied.`);
+
+ consola.success(
+ `Brand new workspace forked to ${chalk.green(
+ forkedWorkspaceLocation
+ )}`
+ );
+
+ console.log('');
+ consola.info(
+ `Executing ${chalk.white('Deps Installation')} and ${chalk.white(
+ 'Env Setup'
+ )}...`
+ );
+
+ const spinner = ora('Installing dependencies...').start();
+
+ CLIUtils.useChildProcess(
+ 'pnpm install --registry=https://registry.npmmirror.com',
+ {
+ cwd: forkedWorkspaceLocation,
+ stdio: 'ignore',
+ }
+ )
+ .then(() => {
+ spinner.succeed('Dependencies installed!');
+
+ return Promise.resolve();
+ })
+ .then(() => {
+ consola.success('Openning workspace in VS Code...');
+ CLIUtils.useChildProcess(`code ${forkedWorkspaceLocation}`);
+ return Promise.resolve();
+ });
+ }
+ );
+}
diff --git a/scripts/utils.ts b/scripts/utils.ts
index f09bf94..750c2be 100644
--- a/scripts/utils.ts
+++ b/scripts/utils.ts
@@ -119,6 +119,16 @@ export class CLIUtils {
return null;
}
+ public static async createConfirmSelector(message: string): Promise {
+ const res = await enquirer.prompt>({
+ type: 'confirm',
+ name: 'confirm',
+ message,
+ });
+
+ return res.confirm;
+ }
+
public static async createPackageMultiSelector(
name: T,
message: string,
@@ -264,7 +274,8 @@ export class CLIUtils {
command: string,
options?: execa.Options
) {
- consola.info(`Executing command: ${command} \n`);
+ console.log('');
+ consola.info(`Executing command: ${chalk.cyan(command)}`);
await execa(command, {
stdio: 'inherit',