Monorepo for Aesthetic.Computer
aesthetic.computer
1import fs from "fs";
2import path from "path";
3import { spawn } from "child_process";
4import { fileURLToPath } from "url";
5import { dirname } from "path";
6
7// Helper function to get __dirname in ES module
8const __filename = fileURLToPath(import.meta.url);
9const __dirname = dirname(__filename);
10
11// Function to check if directory has node_modules
12const hasNodeModules = (dir) => {
13 const nodeModulesPath = path.join(dir, "node_modules");
14 try {
15 const stat = fs.statSync(nodeModulesPath);
16 if (!stat.isDirectory()) return false;
17 const contents = fs.readdirSync(nodeModulesPath);
18 return contents.length > 0;
19 } catch (err) {
20 return false;
21 }
22};
23
24// Function to execute npm install using spawn for real-time output
25const runNpmInstall = (dir) => {
26 return new Promise((resolve, reject) => {
27 // Check if already has node_modules
28 if (hasNodeModules(dir)) {
29 console.log(`✅ ${path.basename(dir)} already has node_modules, skipping`);
30 resolve();
31 return;
32 }
33
34 console.log(`📦 Installing dependencies in ${path.basename(dir)}...`);
35
36 // Try npm ci first (faster for clean installs)
37 let childProcess = spawn("npm", ["ci", "--no-fund", "--no-audit", "--silent"], {
38 cwd: dir,
39 stdio: ["ignore", "pipe", "pipe"],
40 });
41
42 let output = "";
43 let errorOutput = "";
44
45 childProcess.stdout?.on("data", (data) => {
46 output += data.toString();
47 });
48
49 childProcess.stderr?.on("data", (data) => {
50 errorOutput += data.toString();
51 });
52
53 childProcess.on("close", (code) => {
54 if (code === 0) {
55 console.log(`✅ npm install completed in ${path.basename(dir)}`);
56 resolve();
57 } else {
58 console.log(`⚠️ npm ci failed in ${path.basename(dir)}, trying npm install...`);
59
60 // Fallback to npm install
61 const fallbackProcess = spawn("npm", ["install", "--no-fund", "--no-audit", "--silent"], {
62 cwd: dir,
63 stdio: ["ignore", "pipe", "pipe"],
64 });
65
66 let fallbackOutput = "";
67 let fallbackErrorOutput = "";
68
69 fallbackProcess.stdout?.on("data", (data) => {
70 fallbackOutput += data.toString();
71 });
72
73 fallbackProcess.stderr?.on("data", (data) => {
74 fallbackErrorOutput += data.toString();
75 });
76
77 fallbackProcess.on("close", (fallbackCode) => {
78 if (fallbackCode === 0) {
79 console.log(`✅ npm install completed in ${path.basename(dir)}`);
80 resolve();
81 } else {
82 console.error(`❌ npm install failed in ${path.basename(dir)} with exit code ${fallbackCode}`);
83 if (fallbackErrorOutput) {
84 console.error("Error output:", fallbackErrorOutput);
85 }
86 reject(new Error(`Process exited with code ${fallbackCode}`));
87 }
88 });
89 }
90 });
91 });
92};
93
94// Function to recursively find all directories with package.json
95const findPackageJsonDirectories = (basePath, maxDepth = 2) => {
96 const results = [];
97
98 const scanDirectory = (currentPath, depth) => {
99 if (depth > maxDepth) return;
100
101 try {
102 const entries = fs.readdirSync(currentPath, { withFileTypes: true });
103
104 // Check if current directory has package.json
105 if (entries.some(entry => entry.name === "package.json")) {
106 results.push(currentPath);
107 }
108
109 // Recursively scan subdirectories (avoiding node_modules and other common exclusions)
110 for (const entry of entries) {
111 if (entry.isDirectory() &&
112 !entry.name.startsWith('.') &&
113 entry.name !== 'node_modules' &&
114 entry.name !== 'target' &&
115 entry.name !== 'dist' &&
116 entry.name !== 'build' &&
117 entry.name !== 'archive') { // Skip archive directory
118 scanDirectory(path.join(currentPath, entry.name), depth + 1);
119 }
120 }
121 } catch (err) {
122 // Skip directories we can't read
123 console.log(`⚠️ Skipping ${currentPath}: ${err.message}`);
124 }
125 };
126
127 scanDirectory(basePath, 0);
128 return results;
129};
130
131// Main function to loop through directories with package.json
132const installDependenciesInDirectories = async () => {
133 console.log("🔍 Finding all directories with package.json files...");
134 const packageJsonDirs = findPackageJsonDirectories(__dirname);
135
136 console.log(`📋 Found ${packageJsonDirs.length} directories with package.json:`);
137 packageJsonDirs.forEach(dir => {
138 const relativePath = path.relative(__dirname, dir);
139 console.log(` ${relativePath || '.'}`);
140 });
141
142 let successCount = 0;
143 let skippedCount = 0;
144 let failureCount = 0;
145
146 for (const dir of packageJsonDirs) {
147 const relativePath = path.relative(__dirname, dir) || '.';
148 try {
149 if (hasNodeModules(dir)) {
150 skippedCount++;
151 continue;
152 }
153 await runNpmInstall(dir);
154 successCount++;
155 } catch (error) {
156 console.error(`❌ Failed to run npm install in ${relativePath}: ${error.message}`);
157 failureCount++;
158 }
159 }
160
161 console.log("\n📊 Installation Summary:");
162 console.log(` ✅ Successful installations: ${successCount}`);
163 console.log(` ⏭️ Skipped (already installed): ${skippedCount}`);
164 console.log(` ❌ Failed installations: ${failureCount}`);
165};
166
167// Run the main function
168installDependenciesInDirectories();