@cocreate/cli 1.60.0 → 1.64.0
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/CoCreate.config.js +7 -160
- package/package.json +4 -22
- package/src/commands/link.js +268 -92
- package/src/commands/other/lazyload-modules.js +753 -0
- package/src/commands/storage.js +126 -0
- package/src/commands/upload.js +4 -0
- package/src/commands/fs/automated.js +0 -159
- package/src/commands/fs/config.js +0 -133
- package/src/commands/fs/manual.js +0 -81
- package/src/commands/fs/prettier.config.js +0 -99
- package/src/commands/fs/readme.js +0 -138
- package/src/commands/fs/remove.js +0 -24
- package/src/commands/fs/replace.js +0 -35
package/src/commands/link.js
CHANGED
|
@@ -10,21 +10,20 @@ const { isWindows } = getOS();
|
|
|
10
10
|
* Resolves the configured target node_modules directory path.
|
|
11
11
|
* Targeted check: parses RC files only associated with the active package manager.
|
|
12
12
|
*
|
|
13
|
+
* @param {string} targetDir - Base directory to check for package manager configuration.
|
|
13
14
|
* @param {string} packageManager - The active package manager name (npm, pnpm, yarn-classic, yarn-berry, bun).
|
|
14
15
|
* @returns {string} Fully resolved path to the node_modules folder.
|
|
15
16
|
*/
|
|
16
|
-
function getTargetNodeModulesPath(packageManager) {
|
|
17
|
-
const cwd = process.cwd();
|
|
18
|
-
|
|
17
|
+
function getTargetNodeModulesPath(targetDir, packageManager) {
|
|
19
18
|
// Check .npmrc config if utilizing npm or pnpm
|
|
20
19
|
if (packageManager === "npm" || packageManager === "pnpm") {
|
|
21
|
-
const npmrcPath = path.join(
|
|
20
|
+
const npmrcPath = path.join(targetDir, ".npmrc");
|
|
22
21
|
if (fs.existsSync(npmrcPath)) {
|
|
23
22
|
try {
|
|
24
23
|
const content = fs.readFileSync(npmrcPath, "utf-8");
|
|
25
24
|
const match = content.match(/^\s*modules-dir\s*=\s*["']?([^"'\r\n#;]+)["']?/m);
|
|
26
25
|
if (match && match[1]) {
|
|
27
|
-
return path.resolve(
|
|
26
|
+
return path.resolve(targetDir, match[1].trim());
|
|
28
27
|
}
|
|
29
28
|
} catch (e) {
|
|
30
29
|
// Gracefully ignore reading errors
|
|
@@ -34,13 +33,13 @@ function getTargetNodeModulesPath(packageManager) {
|
|
|
34
33
|
|
|
35
34
|
// Check .yarnrc config if utilizing Yarn (Classic or Berry configured for custom folders)
|
|
36
35
|
if (packageManager === "yarn-classic" || packageManager === "yarn-berry") {
|
|
37
|
-
const yarnrcPath = path.join(
|
|
36
|
+
const yarnrcPath = path.join(targetDir, ".yarnrc");
|
|
38
37
|
if (fs.existsSync(yarnrcPath)) {
|
|
39
38
|
try {
|
|
40
39
|
const content = fs.readFileSync(yarnrcPath, "utf-8");
|
|
41
40
|
const match = content.match(/^\s*--(?:install\.)?modules-folder\s+["']?([^"'\r\n#]+)["']?/m);
|
|
42
41
|
if (match && match[1]) {
|
|
43
|
-
return path.resolve(
|
|
42
|
+
return path.resolve(targetDir, match[1].trim());
|
|
44
43
|
}
|
|
45
44
|
} catch (e) {
|
|
46
45
|
// Gracefully ignore reading errors
|
|
@@ -49,29 +48,221 @@ function getTargetNodeModulesPath(packageManager) {
|
|
|
49
48
|
}
|
|
50
49
|
|
|
51
50
|
// Fallback to default
|
|
52
|
-
return path.resolve(
|
|
51
|
+
return path.resolve(targetDir, "node_modules");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Builds a fast lookup dictionary mapping package names (e.g. "@cocreate/utils")
|
|
56
|
+
* to their absolute local filesystem paths.
|
|
57
|
+
*
|
|
58
|
+
* @param {Array<Object>} repos - Array of repository configurations.
|
|
59
|
+
* @param {string} cwd - Active working directory.
|
|
60
|
+
* @returns {Map<string, Object>} Map of package names to repo objects.
|
|
61
|
+
*/
|
|
62
|
+
function buildWorkspaceMap(repos, cwd) {
|
|
63
|
+
const map = new Map();
|
|
64
|
+
|
|
65
|
+
for (const repo of repos) {
|
|
66
|
+
if (!repo) continue;
|
|
67
|
+
const rawPath = repo.path || repo.absolutePath || repo.directory;
|
|
68
|
+
if (!rawPath) continue;
|
|
69
|
+
|
|
70
|
+
const absolutePath = repo.absolutePath || path.resolve(cwd, rawPath);
|
|
71
|
+
if (!fs.existsSync(absolutePath)) continue;
|
|
72
|
+
|
|
73
|
+
let packageName = repo.packageName;
|
|
74
|
+
const packageJsonPath = path.join(absolutePath, "package.json");
|
|
75
|
+
|
|
76
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
77
|
+
try {
|
|
78
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
79
|
+
packageName = pkg.name || packageName;
|
|
80
|
+
} catch (e) {
|
|
81
|
+
// Ignore parse errors
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
packageName = packageName || path.basename(absolutePath);
|
|
86
|
+
|
|
87
|
+
const repoMeta = {
|
|
88
|
+
...repo,
|
|
89
|
+
packageName,
|
|
90
|
+
absolutePath,
|
|
91
|
+
directory: path.dirname(absolutePath),
|
|
92
|
+
name: repo.name || path.basename(absolutePath)
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
map.set(packageName, repoMeta);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return map;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Reads a directory's package.json and extracts all declared dependencies
|
|
103
|
+
* (dependencies, devDependencies, and peerDependencies).
|
|
104
|
+
*
|
|
105
|
+
* @param {string} repoPath - Absolute path to package repository.
|
|
106
|
+
* @returns {Array<string>} List of declared dependency names.
|
|
107
|
+
*/
|
|
108
|
+
function getPackageDependencies(repoPath) {
|
|
109
|
+
const packageJsonPath = path.join(repoPath, "package.json");
|
|
110
|
+
if (!fs.existsSync(packageJsonPath)) return [];
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
114
|
+
const deps = new Set([
|
|
115
|
+
...Object.keys(pkg.dependencies || {}),
|
|
116
|
+
...Object.keys(pkg.devDependencies || {}),
|
|
117
|
+
...Object.keys(pkg.peerDependencies || {})
|
|
118
|
+
]);
|
|
119
|
+
return Array.from(deps);
|
|
120
|
+
} catch (e) {
|
|
121
|
+
return [];
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Recursively links a local repository and its local sibling dependencies.
|
|
127
|
+
*
|
|
128
|
+
* @param {Object} repo - Target repository object.
|
|
129
|
+
* @param {Map<string, Object>} workspaceMap - Available local workspace repos.
|
|
130
|
+
* @param {Object} options - Command options (useSymlink, packageManager, binName, failed, linkedPairs, depth).
|
|
131
|
+
* @param {Set<string>} visited - Track visited packages to prevent circular loops.
|
|
132
|
+
*/
|
|
133
|
+
async function linkRepoAndDependencies(repo, workspaceMap, options, visited = new Set()) {
|
|
134
|
+
const { useSymlink, packageManager, binName, failed, linkedPairs, stats, depth = 1 } = options;
|
|
135
|
+
|
|
136
|
+
// Circular dependency prevention guard
|
|
137
|
+
if (visited.has(repo.absolutePath)) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
visited.add(repo.absolutePath);
|
|
141
|
+
|
|
142
|
+
const declaredDeps = getPackageDependencies(repo.absolutePath);
|
|
143
|
+
const localDepsToLink = [];
|
|
144
|
+
|
|
145
|
+
// Identify which declared dependencies exist in local workspace
|
|
146
|
+
for (const depName of declaredDeps) {
|
|
147
|
+
if (workspaceMap.has(depName)) {
|
|
148
|
+
const depRepo = workspaceMap.get(depName);
|
|
149
|
+
// Avoid self-linking
|
|
150
|
+
if (depRepo.absolutePath !== repo.absolutePath) {
|
|
151
|
+
localDepsToLink.push(depRepo);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (localDepsToLink.length === 0) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const targetNodeModules = getTargetNodeModulesPath(repo.absolutePath, packageManager);
|
|
161
|
+
const indent = " ".repeat(depth);
|
|
162
|
+
|
|
163
|
+
for (let i = 0; i < localDepsToLink.length; i++) {
|
|
164
|
+
const depRepo = localDepsToLink[i];
|
|
165
|
+
const pairKey = `${repo.packageName}->${depRepo.packageName}`;
|
|
166
|
+
|
|
167
|
+
// Skip re-linking identical pairs to avoid redundant I/O and console clutter
|
|
168
|
+
if (linkedPairs.has(pairKey)) {
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
linkedPairs.add(pairKey);
|
|
172
|
+
|
|
173
|
+
const isLast = i === localDepsToLink.length - 1;
|
|
174
|
+
const branchChar = isLast ? "└─" : "├─";
|
|
175
|
+
|
|
176
|
+
try {
|
|
177
|
+
if (useSymlink) {
|
|
178
|
+
// Direct Symlink Mode
|
|
179
|
+
const linkDestination = path.join(targetNodeModules, depRepo.packageName);
|
|
180
|
+
const sourcePath = path.resolve(depRepo.absolutePath);
|
|
181
|
+
|
|
182
|
+
await fs.promises.mkdir(path.dirname(linkDestination), { recursive: true });
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
const stat = await fs.promises.lstat(linkDestination);
|
|
186
|
+
if (stat.isSymbolicLink() || stat.isFile()) {
|
|
187
|
+
await fs.promises.unlink(linkDestination);
|
|
188
|
+
} else {
|
|
189
|
+
await fs.promises.rm(linkDestination, { recursive: true, force: true });
|
|
190
|
+
}
|
|
191
|
+
} catch (e) {
|
|
192
|
+
// Path does not exist yet
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const type = isWindows ? "junction" : "dir";
|
|
196
|
+
await fs.promises.symlink(sourcePath, linkDestination, type);
|
|
197
|
+
|
|
198
|
+
console.log(`${indent}${branchChar} 🔗 ${depRepo.packageName}`);
|
|
199
|
+
stats.totalSymlinks++;
|
|
200
|
+
} else {
|
|
201
|
+
// Package Manager CLI Link Mode
|
|
202
|
+
if (packageManager === "pnpm" || packageManager === "yarn-berry") {
|
|
203
|
+
let linkCode = await spawn(binName, ["link", depRepo.absolutePath], {
|
|
204
|
+
cwd: repo.absolutePath,
|
|
205
|
+
shell: true,
|
|
206
|
+
stdio: "pipe"
|
|
207
|
+
});
|
|
208
|
+
if (linkCode !== 0) throw new Error(`Link execution failed`);
|
|
209
|
+
} else {
|
|
210
|
+
// 2-Step linking for npm / Yarn Classic / Bun
|
|
211
|
+
let regCode = await spawn(binName, ["link"], {
|
|
212
|
+
cwd: depRepo.absolutePath,
|
|
213
|
+
shell: true,
|
|
214
|
+
stdio: "pipe"
|
|
215
|
+
});
|
|
216
|
+
if (regCode !== 0) throw new Error(`Global registration failed`);
|
|
217
|
+
|
|
218
|
+
let linkCode = await spawn(binName, ["link", depRepo.packageName], {
|
|
219
|
+
cwd: repo.absolutePath,
|
|
220
|
+
shell: true,
|
|
221
|
+
stdio: "pipe"
|
|
222
|
+
});
|
|
223
|
+
if (linkCode !== 0) throw new Error(`Link command failed`);
|
|
224
|
+
}
|
|
225
|
+
console.log(`${indent}${branchChar} 🔗 ${depRepo.packageName}`);
|
|
226
|
+
stats.totalSymlinks++;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Recurse down the dependency tree for the nested dependency
|
|
230
|
+
await linkRepoAndDependencies(depRepo, workspaceMap, {
|
|
231
|
+
...options,
|
|
232
|
+
depth: depth + 1
|
|
233
|
+
}, visited);
|
|
234
|
+
|
|
235
|
+
} catch (err) {
|
|
236
|
+
failed.push({
|
|
237
|
+
name: `${repo.packageName} -> ${depRepo.packageName}`,
|
|
238
|
+
error: err.message
|
|
239
|
+
});
|
|
240
|
+
console.error(`${indent}${branchChar} ❌ ${depRepo.packageName} (${err.message})`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
53
243
|
}
|
|
54
244
|
|
|
55
245
|
/**
|
|
56
246
|
* CLI-compatible link command that establishes local connections using
|
|
57
|
-
* direct symlinking (fast mode) or the host system's package manager
|
|
247
|
+
* direct symlinking (fast mode) or the host system's package manager,
|
|
248
|
+
* recursively traversing and linking local dependencies tree-wide.
|
|
58
249
|
*
|
|
59
250
|
* @param {Array<Object>} repos - Array of repository configurations.
|
|
60
251
|
* @param {Array<string>} args - Process arguments passed to the CLI command.
|
|
61
252
|
* @returns {Promise<Array<Object>>} List of packages that encountered real errors.
|
|
62
253
|
*/
|
|
63
254
|
module.exports = async (repos, args) => {
|
|
255
|
+
const startTime = Date.now();
|
|
64
256
|
const failed = [];
|
|
65
257
|
const packageManager = getPackageManager();
|
|
66
258
|
const cwd = process.cwd();
|
|
67
|
-
|
|
68
|
-
// Convert generic internal yarn manager labels to
|
|
259
|
+
|
|
260
|
+
// Convert generic internal yarn manager labels to standard executable binary name
|
|
69
261
|
const binName = (packageManager === "yarn-classic" || packageManager === "yarn-berry")
|
|
70
262
|
? "yarn"
|
|
71
263
|
: packageManager;
|
|
72
|
-
|
|
264
|
+
|
|
73
265
|
const useSymlink = args && args.includes("--symlink");
|
|
74
|
-
let targetNodeModules = null;
|
|
75
266
|
|
|
76
267
|
// --- PLUG'N'PLAY DETECTION & SHORT-CIRCUIT ---
|
|
77
268
|
const isPnp = packageManager === "yarn-berry" && (
|
|
@@ -85,20 +276,17 @@ module.exports = async (repos, args) => {
|
|
|
85
276
|
return failed;
|
|
86
277
|
}
|
|
87
278
|
|
|
88
|
-
console.log(
|
|
279
|
+
console.log(`\n==================================================`);
|
|
280
|
+
console.log(` Active Package Manager: ${packageManager.toUpperCase()}`);
|
|
281
|
+
console.log(` Linking Strategy: ${useSymlink ? "Direct Symlink (Fast)" : "Package Manager CLI"}`);
|
|
282
|
+
console.log(`==================================================\n`);
|
|
89
283
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
console.log(`[Symlink Mode] Target: ${relativeTargetDir}\n`);
|
|
284
|
+
const workspaceMap = buildWorkspaceMap(repos, cwd);
|
|
285
|
+
const linkedPairs = new Set();
|
|
286
|
+
const stats = { primaryPackages: 0, totalSymlinks: 0 };
|
|
95
287
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
} else {
|
|
100
|
-
console.log("");
|
|
101
|
-
}
|
|
288
|
+
const filterableRepos = repos.filter(r => r && (!r.exclude || !r.exclude.includes("link")));
|
|
289
|
+
let currentIdx = 0;
|
|
102
290
|
|
|
103
291
|
for (let repo of repos) {
|
|
104
292
|
if (!repo) continue;
|
|
@@ -107,42 +295,33 @@ module.exports = async (repos, args) => {
|
|
|
107
295
|
const rawPath = repo.path || repo.absolutePath || repo.directory;
|
|
108
296
|
if (!rawPath) continue;
|
|
109
297
|
|
|
110
|
-
|
|
111
|
-
repo.absolutePath = repo.absolutePath || path.resolve(cwd, rawPath);
|
|
112
|
-
repo.directory = repo.directory || path.dirname(repo.absolutePath);
|
|
113
|
-
repo.name = repo.name || path.basename(repo.absolutePath);
|
|
298
|
+
const absolutePath = repo.absolutePath || path.resolve(cwd, rawPath);
|
|
114
299
|
|
|
115
|
-
// Do not process current execution folder inside
|
|
116
|
-
if (cwd ===
|
|
300
|
+
// Do not process current execution folder directly inside root loop
|
|
301
|
+
if (cwd === absolutePath) continue;
|
|
117
302
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
// Verify package directory exists on local disk
|
|
121
|
-
if (!fs.existsSync(repo.absolutePath)) {
|
|
122
|
-
console.log(`Skipped (not found): ${relativeRepoPath}`);
|
|
303
|
+
if (!fs.existsSync(absolutePath)) {
|
|
304
|
+
console.log(`Skipped (not found): ${path.relative(cwd, absolutePath)}`);
|
|
123
305
|
continue;
|
|
124
306
|
}
|
|
125
307
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
repo.packageName = packageObj.name;
|
|
133
|
-
} catch (e) {
|
|
134
|
-
// Ignore reading errors
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
repo.packageName = repo.packageName || repo.name;
|
|
138
|
-
}
|
|
308
|
+
currentIdx++;
|
|
309
|
+
const repoMeta = workspaceMap.get(repo.packageName) || {
|
|
310
|
+
...repo,
|
|
311
|
+
absolutePath,
|
|
312
|
+
packageName: repo.packageName || path.basename(absolutePath)
|
|
313
|
+
};
|
|
139
314
|
|
|
315
|
+
stats.primaryPackages++;
|
|
316
|
+
console.log(`[${currentIdx}/${filterableRepos.length}] 📦 ${repoMeta.packageName}`);
|
|
317
|
+
|
|
318
|
+
// Perform top-level link into current workspace root
|
|
140
319
|
try {
|
|
320
|
+
const rootNodeModules = getTargetNodeModulesPath(cwd, packageManager);
|
|
141
321
|
if (useSymlink) {
|
|
142
|
-
const linkDestination = path.join(
|
|
143
|
-
const sourcePath = path.resolve(repo.absolutePath);
|
|
144
|
-
|
|
322
|
+
const linkDestination = path.join(rootNodeModules, repoMeta.packageName);
|
|
145
323
|
await fs.promises.mkdir(path.dirname(linkDestination), { recursive: true });
|
|
324
|
+
|
|
146
325
|
try {
|
|
147
326
|
const stat = await fs.promises.lstat(linkDestination);
|
|
148
327
|
if (stat.isSymbolicLink() || stat.isFile()) {
|
|
@@ -153,65 +332,62 @@ module.exports = async (repos, args) => {
|
|
|
153
332
|
} catch (e) {}
|
|
154
333
|
|
|
155
334
|
const type = isWindows ? "junction" : "dir";
|
|
156
|
-
await fs.promises.symlink(
|
|
157
|
-
|
|
158
|
-
console.log(`Successfully symlinked: ${relativeRepoPath} -> node_modules/${repo.packageName}`);
|
|
335
|
+
await fs.promises.symlink(repoMeta.absolutePath, linkDestination, type);
|
|
336
|
+
stats.totalSymlinks++;
|
|
159
337
|
} else {
|
|
160
|
-
|
|
161
|
-
// --- 1-STEP DIRECT PATH LINKING (pnpm & Yarn Berry) ---
|
|
162
338
|
if (packageManager === "pnpm" || packageManager === "yarn-berry") {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
let linkCode = await spawn(binName, ["link", repo.absolutePath], {
|
|
166
|
-
cwd: cwd,
|
|
339
|
+
let linkCode = await spawn(binName, ["link", repoMeta.absolutePath], {
|
|
340
|
+
cwd,
|
|
167
341
|
shell: true,
|
|
168
|
-
stdio: "
|
|
342
|
+
stdio: "pipe"
|
|
169
343
|
});
|
|
170
|
-
|
|
171
|
-
if (linkCode !== 0) {
|
|
172
|
-
throw new Error(`Execution failed`);
|
|
173
|
-
}
|
|
174
|
-
|
|
344
|
+
if (linkCode !== 0) throw new Error("Execution failed");
|
|
175
345
|
} else {
|
|
176
|
-
// --- 2-STEP GLOBAL REGISTRY LINKING (npm, Yarn Classic, Bun) ---
|
|
177
|
-
console.log(`Registering: ${repo.packageName}...`);
|
|
178
|
-
|
|
179
346
|
let regCode = await spawn(binName, ["link"], {
|
|
180
|
-
cwd:
|
|
347
|
+
cwd: repoMeta.absolutePath,
|
|
181
348
|
shell: true,
|
|
182
|
-
stdio: "
|
|
349
|
+
stdio: "pipe"
|
|
183
350
|
});
|
|
351
|
+
if (regCode !== 0) throw new Error("Global registration failed");
|
|
184
352
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
console.log(`Linking: ${repo.packageName}...`);
|
|
190
|
-
|
|
191
|
-
let linkCode = await spawn(binName, ["link", repo.packageName], {
|
|
192
|
-
cwd: cwd,
|
|
353
|
+
let linkCode = await spawn(binName, ["link", repoMeta.packageName], {
|
|
354
|
+
cwd,
|
|
193
355
|
shell: true,
|
|
194
|
-
stdio: "
|
|
356
|
+
stdio: "pipe"
|
|
195
357
|
});
|
|
196
|
-
|
|
197
|
-
if (linkCode !== 0) {
|
|
198
|
-
throw new Error(`Host linkage failed`);
|
|
199
|
-
}
|
|
358
|
+
if (linkCode !== 0) throw new Error("Host linkage failed");
|
|
200
359
|
}
|
|
201
|
-
|
|
202
|
-
console.log(`Successfully linked: ${repo.packageName}`);
|
|
203
|
-
console.log("");
|
|
360
|
+
stats.totalSymlinks++;
|
|
204
361
|
}
|
|
205
|
-
|
|
206
362
|
} catch (err) {
|
|
207
|
-
// Log failure message and append package metadata for downstream retrying steps
|
|
208
363
|
failed.push({
|
|
209
|
-
name:
|
|
364
|
+
name: repoMeta.packageName,
|
|
210
365
|
error: err.message
|
|
211
366
|
});
|
|
212
|
-
console.error(`Failed
|
|
367
|
+
console.error(` ❌ Failed primary link: ${repoMeta.packageName} (${err.message})`);
|
|
213
368
|
}
|
|
369
|
+
|
|
370
|
+
const visited = new Set();
|
|
371
|
+
await linkRepoAndDependencies(repoMeta, workspaceMap, {
|
|
372
|
+
useSymlink,
|
|
373
|
+
packageManager,
|
|
374
|
+
binName,
|
|
375
|
+
failed,
|
|
376
|
+
linkedPairs,
|
|
377
|
+
stats,
|
|
378
|
+
depth: 1
|
|
379
|
+
}, visited);
|
|
214
380
|
}
|
|
215
381
|
|
|
382
|
+
const durationSec = ((Date.now() - startTime) / 1000).toFixed(2);
|
|
383
|
+
|
|
384
|
+
console.log(`\n--------------------------------------------------`);
|
|
385
|
+
console.log(`✨ Linking Complete!`);
|
|
386
|
+
console.log(` Primary Packages Processed: ${stats.primaryPackages}`);
|
|
387
|
+
console.log(` Total Connections Linked: ${stats.totalSymlinks}`);
|
|
388
|
+
console.log(` Errors Encountered: ${failed.length}`);
|
|
389
|
+
console.log(` Time Elapsed: ${durationSec}s`);
|
|
390
|
+
console.log(`--------------------------------------------------\n`);
|
|
391
|
+
|
|
216
392
|
return failed;
|
|
217
393
|
};
|