@ayushmxxn/serenity-ui
Version:
A CLI tool for integrating Serenity UI components into your Next.js projects.
196 lines (168 loc) • 5.46 kB
JavaScript
import inquirer from 'inquirer';
import fs from 'fs-jetpack';
import path from 'path';
import { fileURLToPath } from 'url';
import { execSync } from 'child_process';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const components = [
'voice-testimonial',
'voice-testimonial-animate',
'star-rating-testimonial',
'username-testimonial',
'book-testimonial-3D',
'typewriter-testimonial',
'pricing-section-white',
'pricing-section-black',
'pricing-section-blue',
'sign-up-form',
'sign-up-form-v2',
'sign-in-form',
'forgot-password',
'email-form',
'otp-form',
'create-new-password-form',
'password-changed-form',
'image-carousel',
'video-carousel',
'tubelight-navbar',
'spotlightcard',
'swipecard',
'glowcard',
'dock',
'codeblock',
'image-gallery',
'shortcut-modal',
'steps',
'brandsection',
'star-rating',
'projectcard-black',
'projectcard-slate',
'projectcard-glass',
'newsletter',
'cookie',
'waitlist',
'techstack',
'toast',
'tooltip',
'flipcard3d',
'drawer',
'carousel360',
'filmroll',
'featuresection'
];
const toPascalCase = (str) => {
return str
.split('-')
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join('');
};
const extractDependencies = (filePath) => {
const content = fs.read(filePath);
const dependencies = [];
const importRegex = /import\s+(?:.*?\s+from\s+)?['"](.*?)['"]/g;
let match;
while ((match = importRegex.exec(content)) !== null) {
const importedModule = match[1];
if (importedModule.startsWith('react')) {
continue; // Ignore react imports
}
const packageName = importedModule.startsWith('@')
? importedModule.split('/').slice(0, 2).join('/')
: importedModule.split('/')[0];
dependencies.push(packageName);
}
return dependencies;
};
const checkInstalledDependencies = (dependencies) => {
const packageJsonPath = path.join(process.cwd(), 'package.json');
if (!fs.exists(packageJsonPath)) {
console.error('package.json not found in the project directory.');
return dependencies;
}
const packageJson = fs.read(packageJsonPath, 'json');
const installedDependencies = new Set([
...Object.keys(packageJson.dependencies || {}),
...Object.keys(packageJson.devDependencies || {})
]);
return dependencies.filter(dep => !installedDependencies.has(dep));
};
const installDependencies = (dependencies) => {
if (dependencies.length > 0) {
console.log('Installing missing dependencies...');
try {
execSync(`npm install ${dependencies.join(' ')} --save`, { stdio: 'inherit' });
} catch (err) {
console.error('Failed to install dependencies:', err.message);
}
}
};
const add = async (component) => {
if (!component) {
const answer = await inquirer.prompt([
{
type: 'checkbox',
name: 'components',
message: 'Which components would you like to add?',
choices: components,
},
]);
component = answer.components;
} else {
component = [component];
}
const projectDir = process.cwd();
let destination;
// Check for `app/components/ui` directory
const appDir = path.join(projectDir, 'app', 'components', 'ui');
const srcAppDir = path.join(projectDir, 'src', 'app', 'components', 'ui');
const rootDir = path.join(projectDir, 'components', 'ui');
if (fs.exists(path.join(projectDir, 'app'))) {
destination = appDir;
} else if (fs.exists(path.join(projectDir, 'src'))) {
destination = srcAppDir;
} else {
destination = rootDir;
}
// Ensure destination directory exists
fs.dir(destination);
const requiredDependencies = new Set();
for (const comp of component) {
const pascalCaseName = toPascalCase(comp);
const compPath = path.join(__dirname, `../components/${pascalCaseName}.tsx`);
const destPath = path.join(destination, `${pascalCaseName}.tsx`);
if (fs.exists(compPath)) {
if (fs.exists(destPath)) {
// Prompt user if file already exists in destination
const { overwrite } = await inquirer.prompt([
{
type: 'confirm',
name: 'overwrite',
message: `The component ${pascalCaseName} already exists. Do you want to overwrite it?`,
default: false,
},
]);
if (!overwrite) {
console.log(`Skipped ${pascalCaseName}.`);
continue;
}
}
try {
fs.copy(compPath, destPath, { overwrite: true });
console.log(`${pascalCaseName} component added successfully.`);
} catch (err) {
console.error(`Failed to copy ${pascalCaseName}: ${err.message}`);
}
// Extract required dependencies for this component
const dependencies = extractDependencies(compPath);
dependencies.forEach(dep => requiredDependencies.add(dep));
} else {
console.error(`Component not found.`);
}
}
// Check which dependencies need to be installed
const dependenciesToInstall = checkInstalledDependencies(Array.from(requiredDependencies));
// Install missing dependencies
installDependencies(dependenciesToInstall);
};
export default add;