@ayushmxxn/serenity-ui
Version:
A CLI tool for integrating Serenity UI components into your Next.js projects.
174 lines (147 loc) • 4.89 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",
"book-testimonial-3D",
"typewriter-testimonial",
"image-carousel",
"video-carousel",
"tubelight-navbar",
"spotlightcard",
"swipecard",
"glowcard",
"dock",
"image-gallery",
"shortcut-modal",
"brandsection",
"toast",
"flipcard3d",
"carousel360",
];
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;