UNPKG

@craftled/comp

Version:

A CLI tool to initialize a component app

192 lines (166 loc) • 5.12 kB
#!/usr/bin/env node const { execSync } = require('child_process'); const readline = require('readline'); const path = require('path'); const fs = require('fs'); // Function to check if a command exists function commandExists(command) { try { execSync(`command -v ${command}`, { stdio: 'ignore' }); return true; } catch (error) { return false; } } // Function to prompt the user for input function promptUser(query) { const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); return new Promise((resolve) => { rl.question(query, (answer) => { rl.close(); resolve(answer); }); }); } // Determine the best runner to use, prioritizing: bunx > pnpm dlx > npx let runner; if (commandExists('bunx')) { runner = 'bunx'; } else if (commandExists('pnpm')) { runner = 'pnpm dlx'; } else { runner = 'npx'; } async function initCommand() { try { // Prompt the user for the project name const projectName = await promptUser( 'Enter project \x1b[36mfolder name\x1b[0m: ' ); if (!projectName || projectName.trim() === '') { console.error( 'Error: Project folder name cannot be empty.' ); process.exit(1); } // Define the commands to run const createCommand = `${runner} create-next-app@latest ${projectName} --ts --tailwind --eslint --app --no-src-dir --no-import-alias --use-bun --turbopack --empty`; const initCommand = `${runner} shadcn init`; const addCommand = `${runner} shadcn add https://comp-registry.vercel.app/r/new.json --overwrite`; // Step 1: Create the Next.js project console.log(`Running: \x1b[36m${createCommand}\x1b[0m`); execSync(createCommand, { stdio: 'inherit' }); // Step 2: Navigate into the project directory console.log( `Navigating into project directory: \x1b[36m${projectName}\x1b[0m` ); process.chdir(projectName); // Step 3: Initialize shadcn/ui console.log(`Running: \x1b[36m${initCommand}\x1b[0m`); execSync(initCommand, { stdio: 'inherit' }); // Step 4: Add components console.log(`Running: \x1b[36m${addCommand}\x1b[0m`); execSync(addCommand, { stdio: 'inherit' }); // Step 5: Inform the user how to proceed console.log( `\nšŸŽ‰ Project \x1b[36m${projectName}\x1b[0m set up successfully!` ); console.log( `To start working on your project, navigate into the directory:` ); console.log(` \x1b[36mcd ${projectName}\x1b[0m`); console.log( `Then, install dependencies and start the development server:` ); console.log(` \x1b[36mbun i\x1b[0m`); console.log(` \x1b[36mbun run dev\x1b[0m`); } catch (error) { console.error( `Error executing command with ${runner}:`, error.message ); process.exit(1); } } async function addCommand(componentName) { try { if (!componentName) { console.error('Error: Component name is required.'); console.log('Usage: comp add <component-name>'); process.exit(1); } // Check if we're in a Next.js project if (!fs.existsSync('./package.json')) { console.error( 'Error: Not in a project directory. Run this command from your project root.' ); process.exit(1); } const packageJson = JSON.parse( fs.readFileSync('./package.json', 'utf8') ); if ( !packageJson.dependencies || !packageJson.dependencies.next ) { console.warn( "Warning: This doesn't appear to be a Next.js project." ); } // Add the component const addComponentCommand = `${runner} shadcn add https://comp-registry.vercel.app/r/${componentName}.json --overwrite`; console.log( `Adding component: \x1b[36m${componentName}\x1b[0m` ); console.log( `Running: \x1b[36m${addComponentCommand}\x1b[0m` ); execSync(addComponentCommand, { stdio: 'inherit' }); console.log( `\nāœ… Component \x1b[36m${componentName}\x1b[0m added successfully!` ); } catch (error) { console.error(`Error adding component:`, error.message); process.exit(1); } } async function listCommand() { // list manually all possible components console.log('Available components:'); console.log( ' - \x1b[36mpayload\x1b[0m - Add Payload CMS to your project' ); } // Main function to parse arguments and execute commands async function main() { const args = process.argv.slice(2); const command = args[0]; switch (command) { case 'init': await initCommand(); break; case 'add': await addCommand(args[1]); break; case 'list': await listCommand(); break; default: console.log('Usage:'); console.log( ' @craftled/comp init - Initialize a new app' ); console.log( ' @craftled/comp add <component-name> - Add a component to your project' ); console.log( ' @craftled/comp list - List available components' ); process.exit(0); } } // Run the main function main();