mirror of
https://github.com/moumen-soliman/uitripled
synced 2026-04-21 13:37:20 +00:00
355 lines
10 KiB
JavaScript
355 lines
10 KiB
JavaScript
const fs = require("fs");
|
|
const path = require("path");
|
|
|
|
const COMPONENTS_REGISTRY_PATH = path.join(
|
|
__dirname,
|
|
"../lib/components-registry.tsx"
|
|
);
|
|
const REGISTRY_JSON_PATH = path.join(__dirname, "../registry.json");
|
|
|
|
// Category to registry type mapping
|
|
const CATEGORY_TO_TYPE = {
|
|
microinteractions: "registry:ui",
|
|
components: "registry:component",
|
|
page: "registry:page",
|
|
data: "registry:ui",
|
|
decorative: "registry:ui",
|
|
blocks: "registry:block",
|
|
"motion-core": "registry:lib",
|
|
};
|
|
|
|
// Category to registry category mapping
|
|
const CATEGORY_MAPPING = {
|
|
microinteractions: "micro",
|
|
components: "components",
|
|
page: "page",
|
|
data: "data",
|
|
decorative: "decorative",
|
|
blocks: "sections",
|
|
"motion-core": "motion-core",
|
|
};
|
|
|
|
// Common dependencies based on imports
|
|
const DEFAULT_DEPENDENCIES = {
|
|
framer: ["framer-motion"],
|
|
lucide: ["lucide-react"],
|
|
react: ["react"],
|
|
};
|
|
|
|
/**
|
|
* Extract component imports and registry entries from components-registry.tsx
|
|
*/
|
|
function parseComponentsRegistry() {
|
|
const content = fs.readFileSync(COMPONENTS_REGISTRY_PATH, "utf-8");
|
|
|
|
// Extract component imports - handle both single and multiple imports
|
|
const componentImports = {};
|
|
const importRegex =
|
|
/import\s+{\s*([^}]+)\s*}\s+from\s+["']@\/components\/([^"']+)["']/g;
|
|
let match;
|
|
|
|
while ((match = importRegex.exec(content)) !== null) {
|
|
const imports = match[1].split(",").map((i) => i.trim());
|
|
const importPath = match[2];
|
|
|
|
imports.forEach((imp) => {
|
|
// Extract component name (remove type annotations if any)
|
|
const componentName = imp.split(":")[0].trim();
|
|
componentImports[componentName] = importPath;
|
|
});
|
|
}
|
|
|
|
// Extract componentsRegistry entries
|
|
const registryStart = content.indexOf(
|
|
"export const componentsRegistry: Component[] = ["
|
|
);
|
|
const registryEnd = content.lastIndexOf("];", content.length);
|
|
|
|
if (registryStart === -1 || registryEnd === -1) {
|
|
throw new Error(
|
|
"Could not find componentsRegistry in components-registry.tsx"
|
|
);
|
|
}
|
|
|
|
const registryContent = content.substring(registryStart, registryEnd);
|
|
|
|
// Parse entries - split by entry boundaries
|
|
const entries = [];
|
|
const entryPattern = /\{\s*id:\s*"([^"]+)"/g;
|
|
let lastIndex = 0;
|
|
const entryIndices = [];
|
|
|
|
while ((match = entryPattern.exec(registryContent)) !== null) {
|
|
entryIndices.push(match.index);
|
|
}
|
|
|
|
// Parse each entry
|
|
for (let i = 0; i < entryIndices.length; i++) {
|
|
const start = entryIndices[i];
|
|
const end =
|
|
i < entryIndices.length - 1
|
|
? entryIndices[i + 1]
|
|
: registryContent.length;
|
|
const entryText = registryContent.substring(start, end);
|
|
|
|
// Extract id
|
|
const idMatch = entryText.match(/id:\s*"([^"]+)"/);
|
|
if (!idMatch) continue;
|
|
|
|
const id = idMatch[1];
|
|
|
|
// Extract category
|
|
const categoryMatch = entryText.match(/category:\s*"([^"]+)"/);
|
|
if (!categoryMatch) continue;
|
|
|
|
const category = categoryMatch[1];
|
|
|
|
// Extract component name
|
|
const componentMatch = entryText.match(/component:\s*(\w+)/);
|
|
if (!componentMatch) continue;
|
|
|
|
const componentName = componentMatch[1];
|
|
const componentPath = componentImports[componentName];
|
|
|
|
if (componentPath) {
|
|
entries.push({
|
|
id,
|
|
category,
|
|
componentName,
|
|
componentPath,
|
|
});
|
|
} else {
|
|
console.warn(
|
|
`⚠️ Could not find import path for component: ${componentName}`
|
|
);
|
|
}
|
|
}
|
|
|
|
return entries;
|
|
}
|
|
|
|
/**
|
|
* Convert component path to registry path format
|
|
* Example: page/about/about-us-page -> components/page/about/about-us-page.tsx
|
|
* Preserves the full path structure from the component directory
|
|
*/
|
|
function convertToRegistryPath(componentPath) {
|
|
// componentPath is already without @/components/ prefix (from import parsing)
|
|
// Just add the components/ prefix and .tsx extension
|
|
return `components/${componentPath}.tsx`;
|
|
}
|
|
|
|
/**
|
|
* Determine registry dependencies based on component path and category
|
|
*/
|
|
function getRegistryDependencies(componentPath, category) {
|
|
const deps = [];
|
|
|
|
// Common shadcn components that might be used
|
|
const shadcnComponents = [
|
|
"button",
|
|
"card",
|
|
"badge",
|
|
"input",
|
|
"textarea",
|
|
"label",
|
|
"checkbox",
|
|
"radio",
|
|
"select",
|
|
"tabs",
|
|
"dialog",
|
|
"dropdown-menu",
|
|
"avatar",
|
|
"scroll-area",
|
|
"separator",
|
|
"switch",
|
|
];
|
|
|
|
// Check if path suggests use of shadcn components
|
|
// This is a heuristic - you might need to adjust based on actual usage
|
|
if (category === "components" || category === "blocks") {
|
|
// Most components use button and card
|
|
if (!componentPath.includes("micro/buttons")) {
|
|
deps.push("button");
|
|
}
|
|
if (componentPath.includes("cards") || componentPath.includes("card")) {
|
|
deps.push("card");
|
|
}
|
|
}
|
|
|
|
return deps;
|
|
}
|
|
|
|
/**
|
|
* Determine dependencies based on imports in the file
|
|
*/
|
|
function getDependencies(componentPath) {
|
|
const deps = ["framer-motion"]; // Almost all components use framer-motion
|
|
|
|
// Check if likely to use lucide-react
|
|
if (
|
|
componentPath.includes("icons") ||
|
|
componentPath.includes("navigation") ||
|
|
componentPath.includes("tooltips")
|
|
) {
|
|
deps.push("lucide-react");
|
|
}
|
|
|
|
// React is always needed
|
|
deps.push("react");
|
|
|
|
return [...new Set(deps)]; // Remove duplicates
|
|
}
|
|
|
|
/**
|
|
* Determine subcategory based on component path
|
|
*/
|
|
function getSubcategory(componentPath, category) {
|
|
if (category === "micro") {
|
|
if (componentPath.includes("buttons")) return "buttons";
|
|
if (componentPath.includes("toggles")) return "toggles";
|
|
if (componentPath.includes("icons")) return "icons";
|
|
if (componentPath.includes("badges")) return "badges";
|
|
if (componentPath.includes("links")) return "links";
|
|
}
|
|
|
|
if (category === "components") {
|
|
if (componentPath.includes("cards")) return "cards";
|
|
if (componentPath.includes("modal") || componentPath.includes("dialog"))
|
|
return "modal";
|
|
if (componentPath.includes("dropdown")) return "dropdown";
|
|
if (componentPath.includes("inputs") || componentPath.includes("input"))
|
|
return "inputs";
|
|
if (componentPath.includes("tabs")) return "tabs";
|
|
if (componentPath.includes("lists") || componentPath.includes("list"))
|
|
return "lists";
|
|
if (componentPath.includes("chat")) return "chat";
|
|
if (componentPath.includes("notifications")) return "notifications";
|
|
if (componentPath.includes("forms")) return "forms";
|
|
}
|
|
|
|
if (category === "page") {
|
|
if (componentPath.includes("hero")) return "hero";
|
|
if (componentPath.includes("about")) return "about";
|
|
if (componentPath.includes("notifications")) return "notifications";
|
|
}
|
|
|
|
if (category === "data") {
|
|
if (componentPath.includes("progress")) return "progress";
|
|
if (componentPath.includes("charts") || componentPath.includes("chart"))
|
|
return "charts";
|
|
}
|
|
|
|
if (category === "decorative") {
|
|
if (componentPath.includes("text")) return "text";
|
|
if (componentPath.includes("background")) return "background";
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Create registry entry from component data
|
|
*/
|
|
function createRegistryEntry(componentData) {
|
|
const { id, name, category, componentPath } = componentData;
|
|
const registryCategory = CATEGORY_MAPPING[category] || category;
|
|
const registryType = CATEGORY_TO_TYPE[category] || "registry:component";
|
|
|
|
return {
|
|
name: id,
|
|
type: registryType,
|
|
registryDependencies: getRegistryDependencies(componentPath, category),
|
|
dependencies: getDependencies(componentPath),
|
|
files: [
|
|
{
|
|
path: convertToRegistryPath(componentPath),
|
|
type: registryType,
|
|
},
|
|
],
|
|
category: registryCategory,
|
|
subcategory: getSubcategory(componentPath, registryCategory),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Update registry.json with components from components-registry.tsx
|
|
*/
|
|
function syncRegistry() {
|
|
try {
|
|
console.log("🔄 Syncing registry.json with components-registry.tsx...");
|
|
|
|
// Parse components registry
|
|
const components = parseComponentsRegistry();
|
|
console.log(`📦 Found ${components.length} components in registry`);
|
|
|
|
// Read existing registry.json
|
|
const registry = JSON.parse(fs.readFileSync(REGISTRY_JSON_PATH, "utf-8"));
|
|
const existingItems = registry.items || [];
|
|
const existingItemsMap = new Map(
|
|
existingItems.map((item) => [item.name, item])
|
|
);
|
|
|
|
// Create/update entries
|
|
let added = 0;
|
|
let updated = 0;
|
|
|
|
for (const component of components) {
|
|
const registryEntry = createRegistryEntry(component);
|
|
const existing = existingItemsMap.get(component.id);
|
|
|
|
if (existing) {
|
|
// Update existing entry - always update path, preserve dependencies if they exist
|
|
const updatedEntry = {
|
|
...existing,
|
|
type: registryEntry.type,
|
|
files: registryEntry.files, // Always update path
|
|
category: registryEntry.category,
|
|
subcategory: registryEntry.subcategory,
|
|
// Preserve existing dependencies if they exist, otherwise use defaults
|
|
dependencies:
|
|
existing.dependencies?.length > 0
|
|
? existing.dependencies
|
|
: registryEntry.dependencies,
|
|
registryDependencies:
|
|
existing.registryDependencies?.length > 0
|
|
? existing.registryDependencies
|
|
: registryEntry.registryDependencies,
|
|
};
|
|
|
|
existingItemsMap.set(component.id, updatedEntry);
|
|
updated++;
|
|
} else {
|
|
// Add new entry
|
|
existingItemsMap.set(component.id, registryEntry);
|
|
added++;
|
|
}
|
|
}
|
|
|
|
// Update registry
|
|
registry.items = Array.from(existingItemsMap.values());
|
|
|
|
// Sort items by name for consistency
|
|
registry.items.sort((a, b) => a.name.localeCompare(b.name));
|
|
|
|
// Write back to file
|
|
fs.writeFileSync(
|
|
REGISTRY_JSON_PATH,
|
|
JSON.stringify(registry, null, 2) + "\n",
|
|
"utf-8"
|
|
);
|
|
|
|
console.log(`✅ Registry synced! Added: ${added}, Updated: ${updated}`);
|
|
console.log(`📊 Total items in registry: ${registry.items.length}`);
|
|
} catch (error) {
|
|
console.error("❌ Error syncing registry:", error);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
// Run if called directly
|
|
if (require.main === module) {
|
|
syncRegistry();
|
|
}
|
|
|
|
module.exports = { syncRegistry };
|