react-apps-ui 1.0.11 → 1.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/index.js +117 -47
- package/package.json +1 -1
- package/src/index.ts +176 -79
package/README.md
CHANGED
|
@@ -64,11 +64,11 @@ The code is now yours! You will find it beautifully organized in your project fo
|
|
|
64
64
|
import { ActionButton } from "@/components/ui/action-button";
|
|
65
65
|
|
|
66
66
|
export default function App() {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
return (
|
|
68
|
+
<ActionButton onPress={() => console.log("Pressed!")}>
|
|
69
|
+
Click Me
|
|
70
|
+
</ActionButton>
|
|
71
|
+
);
|
|
72
72
|
}
|
|
73
73
|
```
|
|
74
74
|
|
package/dist/index.js
CHANGED
|
@@ -17,7 +17,49 @@ program
|
|
|
17
17
|
.name("react-apps-ui")
|
|
18
18
|
.description("Add high-quality components to your React Native app")
|
|
19
19
|
.version("1.0.0");
|
|
20
|
+
// Helper to filter out packages that are already in package.json
|
|
21
|
+
function filterMissingDeps(deps) {
|
|
22
|
+
const packageJsonPath = path_1.default.join(process.cwd(), "package.json");
|
|
23
|
+
if (!fs_1.default.existsSync(packageJsonPath))
|
|
24
|
+
return deps;
|
|
25
|
+
try {
|
|
26
|
+
const pkg = JSON.parse(fs_1.default.readFileSync(packageJsonPath, "utf-8"));
|
|
27
|
+
const installed = {
|
|
28
|
+
...(pkg.dependencies || {}),
|
|
29
|
+
...(pkg.devDependencies || {}),
|
|
30
|
+
};
|
|
31
|
+
return deps.filter((dep) => {
|
|
32
|
+
let pkgName = dep;
|
|
33
|
+
if (dep.startsWith("@")) {
|
|
34
|
+
pkgName = "@" + dep.slice(1).split("@")[0];
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
pkgName = dep.split("@")[0];
|
|
38
|
+
}
|
|
39
|
+
return !installed[pkgName];
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return deps;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
20
46
|
// --- THE INIT COMMAND ---
|
|
47
|
+
// 1. Define the foundational architecture for each engine
|
|
48
|
+
const BASE_DEPS = {
|
|
49
|
+
"mobile-nativewind": {
|
|
50
|
+
npm: [
|
|
51
|
+
"class-variance-authority",
|
|
52
|
+
"tailwind-merge",
|
|
53
|
+
"clsx",
|
|
54
|
+
"lucide-react-native", // Added for the IconName type
|
|
55
|
+
],
|
|
56
|
+
registry: ["theme", "utils"], // Pulls your cn() utility and theme
|
|
57
|
+
},
|
|
58
|
+
"mobile-stylesheet": {
|
|
59
|
+
npm: ["lucide-react-native"], // Added for the IconName type
|
|
60
|
+
registry: ["theme", "utils"],
|
|
61
|
+
},
|
|
62
|
+
};
|
|
21
63
|
program
|
|
22
64
|
.command("init")
|
|
23
65
|
.description("Configure your Expo project and install the ThemeProvider")
|
|
@@ -43,6 +85,8 @@ program
|
|
|
43
85
|
console.log(chalk_1.default.red("Initialization cancelled."));
|
|
44
86
|
return;
|
|
45
87
|
}
|
|
88
|
+
const engineKey = response.engine;
|
|
89
|
+
const setup = BASE_DEPS[engineKey];
|
|
46
90
|
// 2. USE THE REGISTRY_URL to fetch the correct JSON manifest
|
|
47
91
|
const manifestUrl = `${REGISTRY_URL}/${response.engine}.json`;
|
|
48
92
|
console.log(chalk_1.default.dim(`\nFetching registry from GitHub...`));
|
|
@@ -51,59 +95,79 @@ program
|
|
|
51
95
|
if (!res.ok)
|
|
52
96
|
throw new Error(`Failed to fetch registry: ${res.statusText}`);
|
|
53
97
|
const registry = await res.json();
|
|
54
|
-
// 3. Find the "theme" component inside the giant JSON
|
|
55
|
-
const themeComponent = registry.find((item) => item.name === "theme");
|
|
56
|
-
if (!themeComponent) {
|
|
57
|
-
console.log(chalk_1.default.red("Error: Could not find 'theme' in the registry."));
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
console.log(chalk_1.default.green(`✓ Found theme provider. Installing...`));
|
|
61
98
|
// Check if the user's project uses a 'src' directory
|
|
62
99
|
const hasSrcDir = fs_1.default.existsSync(path_1.default.join(process.cwd(), "src"));
|
|
63
|
-
//
|
|
64
|
-
for (const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const isRootConfig = safeTarget.includes("tailwind") ||
|
|
70
|
-
safeTarget.endsWith(".config.js") ||
|
|
71
|
-
safeTarget.endsWith(".json");
|
|
72
|
-
if (hasSrcDir && !isRootConfig) {
|
|
73
|
-
finalTargetPath = path_1.default.join(process.cwd(), "src", safeTarget);
|
|
100
|
+
// 3. Loop through the required BASE REGISTRY components (theme, utils, etc.)
|
|
101
|
+
for (const compName of setup.registry) {
|
|
102
|
+
const componentData = registry.find((item) => item.name === compName);
|
|
103
|
+
if (!componentData) {
|
|
104
|
+
console.log(chalk_1.default.red(`Error: Could not find '${compName}' in the registry.`));
|
|
105
|
+
continue;
|
|
74
106
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
107
|
+
console.log(chalk_1.default.green(`✓ Found ${compName}. Installing...`));
|
|
108
|
+
// 4. Loop through the files and write them smartly
|
|
109
|
+
for (const file of componentData.files) {
|
|
110
|
+
// A. Force the target to be a string so it can never be undefined
|
|
111
|
+
const safeTarget = String(file.target || file.name || "unknown-file");
|
|
112
|
+
let finalTargetPath = path_1.default.join(process.cwd(), safeTarget);
|
|
113
|
+
//B. Safely check includes on the guaranteed string
|
|
114
|
+
const isRootConfig = safeTarget.includes("tailwind") ||
|
|
115
|
+
safeTarget.endsWith(".config.js") ||
|
|
116
|
+
safeTarget.endsWith(".json");
|
|
117
|
+
if (hasSrcDir && !isRootConfig) {
|
|
118
|
+
finalTargetPath = path_1.default.join(process.cwd(), "src", safeTarget);
|
|
119
|
+
}
|
|
120
|
+
// Ensure the folder exists
|
|
121
|
+
fs_1.default.mkdirSync(path_1.default.dirname(finalTargetPath), {
|
|
122
|
+
recursive: true,
|
|
123
|
+
});
|
|
124
|
+
// SAFE WRITE: Check if the file already exists
|
|
125
|
+
if (fs_1.default.existsSync(finalTargetPath)) {
|
|
126
|
+
if (file.type === "css" ||
|
|
127
|
+
finalTargetPath.endsWith(".css")) {
|
|
128
|
+
console.log(chalk_1.default.yellow(` ⚠️ ${file.target} already exists. Appending theme variables safely...`));
|
|
129
|
+
try {
|
|
130
|
+
// C. Read the file and forcefully convert it to a String
|
|
131
|
+
const rawContent = fs_1.default.readFileSync(finalTargetPath, "utf-8");
|
|
132
|
+
const safeExistingContent = String(rawContent || "");
|
|
133
|
+
// D. Safely check includes (This line can no longer crash!)
|
|
134
|
+
if (!safeExistingContent.includes("--background:")) {
|
|
135
|
+
fs_1.default.appendFileSync(finalTargetPath, `\n/* React Apps UI Theme */\n${file.content || ""}`, "utf-8");
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
console.log(chalk_1.default.red(` ❌ Error reading or appending to ${safeTarget}`));
|
|
91
140
|
}
|
|
92
141
|
}
|
|
93
|
-
|
|
94
|
-
console.log(chalk_1.default.
|
|
142
|
+
else {
|
|
143
|
+
console.log(chalk_1.default.yellow(` ⚠️ ${file.target} already exists. Skipping to prevent overwrite.`));
|
|
95
144
|
}
|
|
96
145
|
}
|
|
97
146
|
else {
|
|
98
|
-
|
|
147
|
+
// File doesn't exist, safe to write normally
|
|
148
|
+
fs_1.default.writeFileSync(finalTargetPath, file.content, "utf-8");
|
|
149
|
+
console.log(chalk_1.default.green(` Created ${safeTarget}`));
|
|
99
150
|
}
|
|
100
151
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
152
|
+
}
|
|
153
|
+
// 5. INSTALL FOUNDATIONAL NPM DEPENDENCIES (Skipping already installed)
|
|
154
|
+
const missingBaseDeps = filterMissingDeps(setup.npm);
|
|
155
|
+
if (missingBaseDeps.length > 0) {
|
|
156
|
+
const depList = missingBaseDeps.join(" ");
|
|
157
|
+
console.log(chalk_1.default.blue(`\n📦 Installing missing foundational NPM dependencies: ${depList}...`));
|
|
158
|
+
try {
|
|
159
|
+
(0, child_process_1.execSync)(`npm install ${depList} --legacy-peer-deps`, {
|
|
160
|
+
stdio: "inherit",
|
|
161
|
+
});
|
|
162
|
+
console.log(chalk_1.default.green("✓ Dependencies installed successfully."));
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
console.log(chalk_1.default.red("❌ Failed to install dependencies. You may need to install them manually."));
|
|
105
166
|
}
|
|
106
167
|
}
|
|
168
|
+
else {
|
|
169
|
+
console.log(chalk_1.default.green("\n✓ All foundational NPM dependencies are already installed. Skipping."));
|
|
170
|
+
}
|
|
107
171
|
console.log(chalk_1.default.blue("\n🎉 Initialization complete!"));
|
|
108
172
|
console.log(chalk_1.default.dim("Wrap your app in the <ThemeProvider> to get started."));
|
|
109
173
|
}
|
|
@@ -179,7 +243,7 @@ program
|
|
|
179
243
|
}
|
|
180
244
|
}
|
|
181
245
|
}
|
|
182
|
-
// 5. INSTALL NPM DEPENDENCIES
|
|
246
|
+
// 5. INSTALL NPM DEPENDENCIES (Skipping already installed)
|
|
183
247
|
const depsToInstall = new Set();
|
|
184
248
|
// Collect all dependencies from the components we just added
|
|
185
249
|
for (const compName of componentsToAdd) {
|
|
@@ -188,18 +252,24 @@ program
|
|
|
188
252
|
compData.dependencies.forEach((dep) => depsToInstall.add(dep));
|
|
189
253
|
}
|
|
190
254
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
255
|
+
// Filter out anything already installed in user's package.json
|
|
256
|
+
const missingDeps = filterMissingDeps(Array.from(depsToInstall));
|
|
257
|
+
if (missingDeps.length > 0) {
|
|
258
|
+
const depList = missingDeps.join(" ");
|
|
259
|
+
console.log(chalk_1.default.blue(`\n📦 Installing missing NPM dependencies: ${depList}...`));
|
|
194
260
|
try {
|
|
195
|
-
|
|
196
|
-
|
|
261
|
+
(0, child_process_1.execSync)(`npm install ${depList} --legacy-peer-deps`, {
|
|
262
|
+
stdio: "inherit",
|
|
263
|
+
});
|
|
197
264
|
console.log(chalk_1.default.green("✓ Dependencies installed successfully."));
|
|
198
265
|
}
|
|
199
266
|
catch (err) {
|
|
200
267
|
console.log(chalk_1.default.red("❌ Failed to install dependencies. You may need to install them manually."));
|
|
201
268
|
}
|
|
202
269
|
}
|
|
270
|
+
else if (depsToInstall.size > 0) {
|
|
271
|
+
console.log(chalk_1.default.green("\n✓ Required NPM dependencies are already installed. Skipping."));
|
|
272
|
+
}
|
|
203
273
|
console.log(chalk_1.default.blue("\n🎉 Components installed successfully!"));
|
|
204
274
|
}
|
|
205
275
|
catch (error) {
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -17,7 +17,51 @@ program
|
|
|
17
17
|
.description("Add high-quality components to your React Native app")
|
|
18
18
|
.version("1.0.0");
|
|
19
19
|
|
|
20
|
+
// Helper to filter out packages that are already in package.json
|
|
21
|
+
function filterMissingDeps(deps: string[]): string[] {
|
|
22
|
+
const packageJsonPath = path.join(process.cwd(), "package.json");
|
|
23
|
+
if (!fs.existsSync(packageJsonPath)) return deps;
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
27
|
+
const installed = {
|
|
28
|
+
...(pkg.dependencies || {}),
|
|
29
|
+
...(pkg.devDependencies || {}),
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
return deps.filter((dep) => {
|
|
33
|
+
let pkgName = dep;
|
|
34
|
+
if (dep.startsWith("@")) {
|
|
35
|
+
pkgName = "@" + dep.slice(1).split("@")[0];
|
|
36
|
+
} else {
|
|
37
|
+
pkgName = dep.split("@")[0];
|
|
38
|
+
}
|
|
39
|
+
return !installed[pkgName];
|
|
40
|
+
});
|
|
41
|
+
} catch {
|
|
42
|
+
return deps;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
20
46
|
// --- THE INIT COMMAND ---
|
|
47
|
+
|
|
48
|
+
// 1. Define the foundational architecture for each engine
|
|
49
|
+
const BASE_DEPS: Record<string, { npm: string[]; registry: string[] }> = {
|
|
50
|
+
"mobile-nativewind": {
|
|
51
|
+
npm: [
|
|
52
|
+
"class-variance-authority",
|
|
53
|
+
"tailwind-merge",
|
|
54
|
+
"clsx",
|
|
55
|
+
"lucide-react-native", // Added for the IconName type
|
|
56
|
+
],
|
|
57
|
+
registry: ["theme", "utils"], // Pulls your cn() utility and theme
|
|
58
|
+
},
|
|
59
|
+
"mobile-stylesheet": {
|
|
60
|
+
npm: ["lucide-react-native"], // Added for the IconName type
|
|
61
|
+
registry: ["theme", "utils"],
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
21
65
|
program
|
|
22
66
|
.command("init")
|
|
23
67
|
.description("Configure your Expo project and install the ThemeProvider")
|
|
@@ -46,6 +90,9 @@ program
|
|
|
46
90
|
return;
|
|
47
91
|
}
|
|
48
92
|
|
|
93
|
+
const engineKey = response.engine as keyof typeof BASE_DEPS;
|
|
94
|
+
const setup = BASE_DEPS[engineKey];
|
|
95
|
+
|
|
49
96
|
// 2. USE THE REGISTRY_URL to fetch the correct JSON manifest
|
|
50
97
|
const manifestUrl = `${REGISTRY_URL}/${response.engine}.json`;
|
|
51
98
|
console.log(chalk.dim(`\nFetching registry from GitHub...`));
|
|
@@ -56,104 +103,145 @@ program
|
|
|
56
103
|
throw new Error(`Failed to fetch registry: ${res.statusText}`);
|
|
57
104
|
|
|
58
105
|
const registry = await res.json();
|
|
59
|
-
|
|
60
|
-
// 3. Find the "theme" component inside the giant JSON
|
|
61
|
-
const themeComponent = registry.find(
|
|
62
|
-
(item: any) => item.name === "theme",
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
if (!themeComponent) {
|
|
66
|
-
console.log(
|
|
67
|
-
chalk.red("Error: Could not find 'theme' in the registry."),
|
|
68
|
-
);
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
console.log(chalk.green(`✓ Found theme provider. Installing...`));
|
|
73
|
-
|
|
74
106
|
// Check if the user's project uses a 'src' directory
|
|
75
107
|
const hasSrcDir = fs.existsSync(path.join(process.cwd(), "src"));
|
|
76
108
|
|
|
77
|
-
//
|
|
78
|
-
for (const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
file.target || file.name || "unknown-file",
|
|
109
|
+
// 3. Loop through the required BASE REGISTRY components (theme, utils, etc.)
|
|
110
|
+
for (const compName of setup.registry) {
|
|
111
|
+
const componentData = registry.find(
|
|
112
|
+
(item: any) => item.name === compName,
|
|
82
113
|
);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
safeTarget.endsWith(".json");
|
|
90
|
-
|
|
91
|
-
if (hasSrcDir && !isRootConfig) {
|
|
92
|
-
finalTargetPath = path.join(
|
|
93
|
-
process.cwd(),
|
|
94
|
-
"src",
|
|
95
|
-
safeTarget,
|
|
114
|
+
|
|
115
|
+
if (!componentData) {
|
|
116
|
+
console.log(
|
|
117
|
+
chalk.red(
|
|
118
|
+
`Error: Could not find '${compName}' in the registry.`,
|
|
119
|
+
),
|
|
96
120
|
);
|
|
121
|
+
continue;
|
|
97
122
|
}
|
|
98
123
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
124
|
+
console.log(chalk.green(`✓ Found ${compName}. Installing...`));
|
|
125
|
+
|
|
126
|
+
// 4. Loop through the files and write them smartly
|
|
127
|
+
for (const file of componentData.files) {
|
|
128
|
+
// A. Force the target to be a string so it can never be undefined
|
|
129
|
+
const safeTarget = String(
|
|
130
|
+
file.target || file.name || "unknown-file",
|
|
131
|
+
);
|
|
132
|
+
let finalTargetPath = path.join(process.cwd(), safeTarget);
|
|
133
|
+
|
|
134
|
+
//B. Safely check includes on the guaranteed string
|
|
135
|
+
const isRootConfig =
|
|
136
|
+
safeTarget.includes("tailwind") ||
|
|
137
|
+
safeTarget.endsWith(".config.js") ||
|
|
138
|
+
safeTarget.endsWith(".json");
|
|
139
|
+
|
|
140
|
+
if (hasSrcDir && !isRootConfig) {
|
|
141
|
+
finalTargetPath = path.join(
|
|
142
|
+
process.cwd(),
|
|
143
|
+
"src",
|
|
144
|
+
safeTarget,
|
|
114
145
|
);
|
|
146
|
+
}
|
|
115
147
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
148
|
+
// Ensure the folder exists
|
|
149
|
+
fs.mkdirSync(path.dirname(finalTargetPath), {
|
|
150
|
+
recursive: true,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// SAFE WRITE: Check if the file already exists
|
|
154
|
+
if (fs.existsSync(finalTargetPath)) {
|
|
155
|
+
if (
|
|
156
|
+
file.type === "css" ||
|
|
157
|
+
finalTargetPath.endsWith(".css")
|
|
158
|
+
) {
|
|
159
|
+
console.log(
|
|
160
|
+
chalk.yellow(
|
|
161
|
+
` ⚠️ ${file.target} already exists. Appending theme variables safely...`,
|
|
162
|
+
),
|
|
124
163
|
);
|
|
125
164
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
) {
|
|
130
|
-
fs.appendFileSync(
|
|
165
|
+
try {
|
|
166
|
+
// C. Read the file and forcefully convert it to a String
|
|
167
|
+
const rawContent = fs.readFileSync(
|
|
131
168
|
finalTargetPath,
|
|
132
|
-
`\n/* React Apps UI Theme */\n${file.content || ""}`,
|
|
133
169
|
"utf-8",
|
|
134
170
|
);
|
|
171
|
+
const safeExistingContent = String(
|
|
172
|
+
rawContent || "",
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
// D. Safely check includes (This line can no longer crash!)
|
|
176
|
+
if (
|
|
177
|
+
!safeExistingContent.includes(
|
|
178
|
+
"--background:",
|
|
179
|
+
)
|
|
180
|
+
) {
|
|
181
|
+
fs.appendFileSync(
|
|
182
|
+
finalTargetPath,
|
|
183
|
+
`\n/* React Apps UI Theme */\n${file.content || ""}`,
|
|
184
|
+
"utf-8",
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
} catch (err) {
|
|
188
|
+
console.log(
|
|
189
|
+
chalk.red(
|
|
190
|
+
` ❌ Error reading or appending to ${safeTarget}`,
|
|
191
|
+
),
|
|
192
|
+
);
|
|
135
193
|
}
|
|
136
|
-
}
|
|
194
|
+
} else {
|
|
137
195
|
console.log(
|
|
138
|
-
chalk.
|
|
139
|
-
`
|
|
196
|
+
chalk.yellow(
|
|
197
|
+
` ⚠️ ${file.target} already exists. Skipping to prevent overwrite.`,
|
|
140
198
|
),
|
|
141
199
|
);
|
|
142
200
|
}
|
|
143
201
|
} else {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
202
|
+
// File doesn't exist, safe to write normally
|
|
203
|
+
fs.writeFileSync(
|
|
204
|
+
finalTargetPath,
|
|
205
|
+
file.content,
|
|
206
|
+
"utf-8",
|
|
148
207
|
);
|
|
208
|
+
console.log(chalk.green(` Created ${safeTarget}`));
|
|
149
209
|
}
|
|
150
|
-
} else {
|
|
151
|
-
// File doesn't exist, safe to write normally
|
|
152
|
-
fs.writeFileSync(finalTargetPath, file.content, "utf-8");
|
|
153
|
-
console.log(chalk.green(` Created ${safeTarget}`));
|
|
154
210
|
}
|
|
155
211
|
}
|
|
156
212
|
|
|
213
|
+
// 5. INSTALL FOUNDATIONAL NPM DEPENDENCIES (Skipping already installed)
|
|
214
|
+
const missingBaseDeps = filterMissingDeps(setup.npm);
|
|
215
|
+
|
|
216
|
+
if (missingBaseDeps.length > 0) {
|
|
217
|
+
const depList = missingBaseDeps.join(" ");
|
|
218
|
+
console.log(
|
|
219
|
+
chalk.blue(
|
|
220
|
+
`\n📦 Installing missing foundational NPM dependencies: ${depList}...`,
|
|
221
|
+
),
|
|
222
|
+
);
|
|
223
|
+
try {
|
|
224
|
+
execSync(`npm install ${depList} --legacy-peer-deps`, {
|
|
225
|
+
stdio: "inherit",
|
|
226
|
+
});
|
|
227
|
+
console.log(
|
|
228
|
+
chalk.green("✓ Dependencies installed successfully."),
|
|
229
|
+
);
|
|
230
|
+
} catch (err) {
|
|
231
|
+
console.log(
|
|
232
|
+
chalk.red(
|
|
233
|
+
"❌ Failed to install dependencies. You may need to install them manually.",
|
|
234
|
+
),
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
} else {
|
|
238
|
+
console.log(
|
|
239
|
+
chalk.green(
|
|
240
|
+
"\n✓ All foundational NPM dependencies are already installed. Skipping.",
|
|
241
|
+
),
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
157
245
|
console.log(chalk.blue("\n🎉 Initialization complete!"));
|
|
158
246
|
console.log(
|
|
159
247
|
chalk.dim(
|
|
@@ -279,7 +367,7 @@ program
|
|
|
279
367
|
}
|
|
280
368
|
}
|
|
281
369
|
|
|
282
|
-
// 5. INSTALL NPM DEPENDENCIES
|
|
370
|
+
// 5. INSTALL NPM DEPENDENCIES (Skipping already installed)
|
|
283
371
|
const depsToInstall = new Set<string>();
|
|
284
372
|
|
|
285
373
|
// Collect all dependencies from the components we just added
|
|
@@ -292,16 +380,19 @@ program
|
|
|
292
380
|
}
|
|
293
381
|
}
|
|
294
382
|
|
|
295
|
-
|
|
296
|
-
|
|
383
|
+
// Filter out anything already installed in user's package.json
|
|
384
|
+
const missingDeps = filterMissingDeps(Array.from(depsToInstall));
|
|
385
|
+
if (missingDeps.length > 0) {
|
|
386
|
+
const depList = missingDeps.join(" ");
|
|
297
387
|
console.log(
|
|
298
388
|
chalk.blue(
|
|
299
|
-
`\n📦 Installing NPM dependencies: ${depList}...`,
|
|
389
|
+
`\n📦 Installing missing NPM dependencies: ${depList}...`,
|
|
300
390
|
),
|
|
301
391
|
);
|
|
302
392
|
try {
|
|
303
|
-
|
|
304
|
-
|
|
393
|
+
execSync(`npm install ${depList} --legacy-peer-deps`, {
|
|
394
|
+
stdio: "inherit",
|
|
395
|
+
});
|
|
305
396
|
console.log(
|
|
306
397
|
chalk.green("✓ Dependencies installed successfully."),
|
|
307
398
|
);
|
|
@@ -312,6 +403,12 @@ program
|
|
|
312
403
|
),
|
|
313
404
|
);
|
|
314
405
|
}
|
|
406
|
+
} else if (depsToInstall.size > 0) {
|
|
407
|
+
console.log(
|
|
408
|
+
chalk.green(
|
|
409
|
+
"\n✓ Required NPM dependencies are already installed. Skipping.",
|
|
410
|
+
),
|
|
411
|
+
);
|
|
315
412
|
}
|
|
316
413
|
|
|
317
414
|
console.log(chalk.blue("\n🎉 Components installed successfully!"));
|