UNPKG

bigblocks

Version:

Complete Bitcoin UI component library - authentication, social, wallet, market, inscriptions, and blockchain interactions for React

165 lines (164 loc) 6.16 kB
import { execSync } from "node:child_process"; import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; import { dirname, join } from "node:path"; import chalk from "chalk"; import prompts from "prompts"; import { loadComponent } from "./registry.js"; // Load config from components.json function loadConfig() { const configPath = join(process.cwd(), "components.json"); if (!existsSync(configPath)) { console.log(chalk.yellow("No components.json found. Run 'bigblocks init' first.")); process.exit(1); } const config = JSON.parse(readFileSync(configPath, "utf-8")); return config; } // Transform content with template placeholders function transformContent(content, config) { return content.replace(/<%- config\.aliases\.(\w+) %>/g, (match, alias) => { return config.aliases[alias] || match; }); } // Resolve target path function resolveTargetPath(target, config) { const transformed = transformContent(target, config); const fileName = transformed.split("/").pop() || ""; if (transformed.startsWith(config.aliases.ui)) { return join(process.cwd(), "src/components/ui", fileName); } if (transformed.startsWith(config.aliases.utils)) { return join(process.cwd(), "src/lib", fileName); } if (transformed.startsWith(config.aliases.hooks)) { return join(process.cwd(), "src/hooks", fileName); } if (transformed.startsWith(config.aliases.components)) { return join(process.cwd(), "src/components", fileName); } if (transformed.startsWith(config.aliases.lib)) { return join(process.cwd(), "src/lib", fileName); } return join(process.cwd(), "src/components", fileName); } // Detect package manager function detectPackageManager() { if (existsSync(join(process.cwd(), "bun.lockb"))) return "bun"; if (existsSync(join(process.cwd(), "pnpm-lock.yaml"))) return "pnpm"; if (existsSync(join(process.cwd(), "yarn.lock"))) return "yarn"; return "npm"; } // Check if a shadcn component exists locally function isShadcnComponentInstalled(name) { const possiblePaths = [ join(process.cwd(), "src/components/ui", `${name}.tsx`), join(process.cwd(), "components/ui", `${name}.tsx`), join(process.cwd(), "app/components/ui", `${name}.tsx`), ]; return possiblePaths.some((path) => existsSync(path)); } // Install a shadcn component function installShadcnComponent(name) { console.log(chalk.cyan(`Installing shadcn component: ${name}...`)); const pm = detectPackageManager(); const cmd = pm === "npm" ? `npx shadcn@latest add ${name} --yes` : `${pm} dlx shadcn@latest add ${name} --yes`; try { execSync(cmd, { stdio: "inherit" }); console.log(chalk.green(`✓ Installed shadcn component: ${name}`)); } catch (error) { throw new Error(`Failed to install shadcn component ${name}`); } } export async function installComponent(name, options, installedSet, allDependencies, spinner) { if (installedSet.has(name)) return; const config = loadConfig(); const component = await loadComponent(name); if (!component) { // Not in our registry - try shadcn console.log(chalk.gray(`Component "${name}" not found in BigBlocks registry, checking shadcn...`)); if (isShadcnComponentInstalled(name)) { console.log(chalk.green(`✓ shadcn component "${name}" already installed`)); installedSet.add(name); return; } try { installShadcnComponent(name); installedSet.add(name); return; } catch (error) { throw new Error(`Component "${name}" not found in BigBlocks or shadcn registry`); } } // Install registry dependencies first if (component.registryDependencies) { for (const dep of component.registryDependencies) { await installComponent(dep, options, installedSet, allDependencies, spinner); } } spinner.start(`Installing ${name}...`); // Install component files for (const file of component.files) { let content = ""; if (file.content) { content = file.content; } else { // Read from source file const sourcePath = join(__dirname, "..", "..", "src", file.path); if (existsSync(sourcePath)) { content = readFileSync(sourcePath, "utf-8"); } else { throw new Error(`Source file not found: ${file.path}`); } } const transformedContent = transformContent(content, config); const targetPath = file.target ? resolveTargetPath(file.target, config) : resolveTargetPath(file.path, config); // Create directory if needed const targetDir = dirname(targetPath); if (!existsSync(targetDir)) { mkdirSync(targetDir, { recursive: true }); } // Check if file exists if (existsSync(targetPath) && !options.overwrite) { const { overwrite } = await prompts({ type: "confirm", name: "overwrite", message: `File exists: ${targetPath}. Overwrite?`, initial: false, }); if (!overwrite) { spinner.info(chalk.yellow(`Skipped ${targetPath}`)); continue; } } // Write file writeFileSync(targetPath, transformedContent); spinner.info(chalk.green(`✓ ${targetPath}`)); } // Collect dependencies if (!options.skipDeps) { if (component.dependencies) { for (const dep of component.dependencies) { allDependencies.deps.add(dep); } } if (component.devDependencies) { for (const dep of component.devDependencies) { allDependencies.devDeps.add(dep); } } } spinner.succeed(`Installed ${chalk.cyan(name)}`); installedSet.add(name); }