@reliverse/dler 2.3.3 → 2.3.4
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/dist/cmds/add/cmd.d.ts +2 -0
- package/dist/cmds/add/cmd.js +153 -0
- package/dist/cmds/add/impl.d.ts +19 -0
- package/dist/cmds/add/impl.js +515 -0
- package/dist/cmds/clean/presets.js +7 -0
- package/dist/cmds/rm/cmd.d.ts +2 -0
- package/dist/cmds/rm/cmd.js +133 -0
- package/dist/cmds/rm/impl.d.ts +17 -0
- package/dist/cmds/rm/impl.js +509 -0
- package/dist/cmds/tsc/cache.d.ts +0 -1
- package/dist/cmds/tsc/cache.js +8 -19
- package/dist/cmds/tsc/impl.js +2 -6
- package/dist/cmds/unused/cmd.d.ts +2 -0
- package/dist/cmds/unused/cmd.js +105 -0
- package/dist/cmds/unused/impl.d.ts +16 -0
- package/dist/cmds/unused/impl.js +415 -0
- package/dist/cmds/update/cmd.js +113 -36
- package/dist/cmds/update/impl.d.ts +8 -2
- package/dist/cmds/update/impl.js +69 -8
- package/dist/cmds/update/utils.d.ts +19 -2
- package/dist/cmds/update/utils.js +149 -61
- package/dist/utils/cache.d.ts +31 -0
- package/dist/utils/cache.js +60 -0
- package/package.json +19 -18
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { logger } from "@reliverse/relinka";
|
|
2
|
+
import { defineCommand, option } from "@reliverse/rempts-core";
|
|
3
|
+
import { type } from "arktype";
|
|
4
|
+
import { addDependency } from "./impl.js";
|
|
5
|
+
export default defineCommand({
|
|
6
|
+
description: "Add dependencies to package.json files with catalog support",
|
|
7
|
+
options: {
|
|
8
|
+
// Target package selection
|
|
9
|
+
target: option(type("string | undefined"), {
|
|
10
|
+
short: "t",
|
|
11
|
+
description: "Target workspace package(s) (from workspaces.packages). Use '.' for current directory package. Supports multiple packages (space-separated) and glob patterns."
|
|
12
|
+
}),
|
|
13
|
+
package: option(type("string | undefined"), {
|
|
14
|
+
description: "Target workspace package(s) (alias for --target). Use '.' for current directory package. Supports multiple packages (space-separated) and glob patterns."
|
|
15
|
+
}),
|
|
16
|
+
pkg: option(type("string | undefined"), {
|
|
17
|
+
description: "Target workspace package(s) (alias for --target). Use '.' for current directory package. Supports multiple packages (space-separated) and glob patterns."
|
|
18
|
+
}),
|
|
19
|
+
w: option(type("boolean | undefined"), {
|
|
20
|
+
description: "Add dependency to root package.json"
|
|
21
|
+
}),
|
|
22
|
+
// Catalog options
|
|
23
|
+
catalog: option(type("string | boolean | undefined"), {
|
|
24
|
+
short: "c",
|
|
25
|
+
description: "Use catalog mode. Can be 'true', 'false', or a catalog name (e.g., 'testing')",
|
|
26
|
+
default: true
|
|
27
|
+
}),
|
|
28
|
+
// Dependency scope/type
|
|
29
|
+
scope: option(type("'dev'|'prod'|'peer'|'optional' | undefined"), {
|
|
30
|
+
short: "s",
|
|
31
|
+
description: "Dependency scope: dev, prod, peer, optional"
|
|
32
|
+
}),
|
|
33
|
+
dev: option(type("boolean | undefined"), {
|
|
34
|
+
short: "D",
|
|
35
|
+
description: "Add as devDependency (shorthand for --scope dev)"
|
|
36
|
+
}),
|
|
37
|
+
prod: option(type("boolean | undefined"), {
|
|
38
|
+
short: "P",
|
|
39
|
+
description: "Add as dependency (shorthand for --scope prod)"
|
|
40
|
+
}),
|
|
41
|
+
peer: option(type("boolean | undefined"), {
|
|
42
|
+
short: "R",
|
|
43
|
+
description: "Add as peerDependency (shorthand for --scope peer)"
|
|
44
|
+
}),
|
|
45
|
+
optional: option(type("boolean | undefined"), {
|
|
46
|
+
short: "O",
|
|
47
|
+
description: "Add as optionalDependency (shorthand for --scope optional)"
|
|
48
|
+
}),
|
|
49
|
+
// Version prefix
|
|
50
|
+
prefix: option(type("string | undefined"), {
|
|
51
|
+
short: "p",
|
|
52
|
+
description: "Version prefix (default: '^')"
|
|
53
|
+
}),
|
|
54
|
+
// Other options
|
|
55
|
+
install: option(type("boolean | undefined"), {
|
|
56
|
+
description: "Run install after adding dependencies (default: true)",
|
|
57
|
+
short: "i",
|
|
58
|
+
default: true
|
|
59
|
+
}),
|
|
60
|
+
cwd: option(type("string | undefined"), {
|
|
61
|
+
description: "Working directory (monorepo root)"
|
|
62
|
+
}),
|
|
63
|
+
dryRun: option(type("boolean | undefined"), {
|
|
64
|
+
short: "n",
|
|
65
|
+
description: "Show what would be done without making changes"
|
|
66
|
+
}),
|
|
67
|
+
verbose: option(type("boolean | undefined"), {
|
|
68
|
+
short: "v",
|
|
69
|
+
description: "Verbose output"
|
|
70
|
+
})
|
|
71
|
+
},
|
|
72
|
+
handler: async ({ flags, positional }) => {
|
|
73
|
+
try {
|
|
74
|
+
if (typeof process.versions.bun === "undefined") {
|
|
75
|
+
logger.error("\u274C This command requires Bun runtime.");
|
|
76
|
+
logger.error("Please run this command using Bun: bun dler add <package>");
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
if (positional.length === 0) {
|
|
80
|
+
logger.error("\u274C No package names provided.");
|
|
81
|
+
logger.log("Usage: dler add <package> [package2...] [options]");
|
|
82
|
+
logger.log("");
|
|
83
|
+
logger.log("Examples:");
|
|
84
|
+
logger.log(" dler add lodash");
|
|
85
|
+
logger.log(" dler add typescript --dev");
|
|
86
|
+
logger.log(" dler add react react-dom --target @scope/ui");
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
const packageList = positional.join(", ");
|
|
90
|
+
logger.log(`\u{1F4E6} Adding dependencies: ${packageList}`);
|
|
91
|
+
if (flags.dryRun) {
|
|
92
|
+
logger.log("\u{1F50D} Running in dry-run mode (no changes will be made)");
|
|
93
|
+
}
|
|
94
|
+
const packageSpecs = [];
|
|
95
|
+
for (const packageArg of positional) {
|
|
96
|
+
const lastAtIndex = packageArg.lastIndexOf("@");
|
|
97
|
+
let packageName;
|
|
98
|
+
let versionSpec;
|
|
99
|
+
if (lastAtIndex > 0) {
|
|
100
|
+
packageName = packageArg.substring(0, lastAtIndex);
|
|
101
|
+
versionSpec = packageArg.substring(lastAtIndex + 1);
|
|
102
|
+
} else {
|
|
103
|
+
packageName = packageArg;
|
|
104
|
+
versionSpec = void 0;
|
|
105
|
+
}
|
|
106
|
+
packageSpecs.push({ name: packageName, versionSpec });
|
|
107
|
+
}
|
|
108
|
+
const packageNames = packageSpecs.map((spec) => spec.name);
|
|
109
|
+
const packageVersionSpecs = packageSpecs.map((spec) => spec.versionSpec);
|
|
110
|
+
let scope = "prod";
|
|
111
|
+
if (flags.scope) {
|
|
112
|
+
scope = flags.scope;
|
|
113
|
+
} else if (flags.dev) {
|
|
114
|
+
scope = "dev";
|
|
115
|
+
} else if (flags.peer) {
|
|
116
|
+
scope = "peer";
|
|
117
|
+
} else if (flags.optional) {
|
|
118
|
+
scope = "optional";
|
|
119
|
+
}
|
|
120
|
+
let catalogMode = flags.catalog ?? true;
|
|
121
|
+
if (typeof flags.catalog === "string") {
|
|
122
|
+
catalogMode = flags.catalog;
|
|
123
|
+
}
|
|
124
|
+
const options = {
|
|
125
|
+
target: flags.target || flags.package || flags.pkg,
|
|
126
|
+
w: flags.w,
|
|
127
|
+
catalog: catalogMode,
|
|
128
|
+
scope,
|
|
129
|
+
prefix: flags.prefix || "^",
|
|
130
|
+
install: flags.install ?? true,
|
|
131
|
+
cwd: flags.cwd || void 0,
|
|
132
|
+
dryRun: flags.dryRun ?? false,
|
|
133
|
+
verbose: flags.verbose ?? false,
|
|
134
|
+
versionSpec: packageVersionSpecs.some((spec) => spec !== void 0) ? packageVersionSpecs.filter((spec) => spec !== void 0) : void 0
|
|
135
|
+
};
|
|
136
|
+
await addDependency(packageNames, options);
|
|
137
|
+
} catch (error) {
|
|
138
|
+
logger.error("\n\u274C Failed to add dependencies:");
|
|
139
|
+
if (error instanceof Error) {
|
|
140
|
+
logger.error(error.message);
|
|
141
|
+
} else {
|
|
142
|
+
logger.error(String(error));
|
|
143
|
+
}
|
|
144
|
+
logger.log("");
|
|
145
|
+
logger.log("\u{1F4A1} Tips:");
|
|
146
|
+
logger.log(" \u2022 Check if the package names are spelled correctly");
|
|
147
|
+
logger.log(" \u2022 Ensure you're in a valid project directory with package.json");
|
|
148
|
+
logger.log(" \u2022 Use --verbose flag for more detailed output");
|
|
149
|
+
logger.log(" \u2022 Use --dry-run flag to see what would be changed without making changes");
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface AddOptions {
|
|
2
|
+
target?: string;
|
|
3
|
+
w?: boolean;
|
|
4
|
+
catalog: boolean | string;
|
|
5
|
+
scope: "dev" | "prod" | "peer" | "optional";
|
|
6
|
+
prefix: string;
|
|
7
|
+
install: boolean;
|
|
8
|
+
cwd?: string;
|
|
9
|
+
dryRun: boolean;
|
|
10
|
+
verbose: boolean;
|
|
11
|
+
versionSpec?: string | string[];
|
|
12
|
+
}
|
|
13
|
+
export interface MonorepoInfo {
|
|
14
|
+
isMonorepo: boolean;
|
|
15
|
+
rootPath: string;
|
|
16
|
+
rootPackageJson: any;
|
|
17
|
+
workspacePackages?: string[];
|
|
18
|
+
}
|
|
19
|
+
export declare function addDependency(packageNames: string | string[], options: AddOptions): Promise<boolean>;
|
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { relative, resolve } from "node:path";
|
|
3
|
+
import { createIncludeFilter } from "@reliverse/matcha";
|
|
4
|
+
import path from "@reliverse/pathkit";
|
|
5
|
+
import { logger } from "@reliverse/relinka";
|
|
6
|
+
import { hasWorkspaces, readPackageJSON, writePackageJSON } from "@reliverse/typerso";
|
|
7
|
+
import { getLatestVersion, runInstallCommand } from "../update/utils.js";
|
|
8
|
+
const monorepoCache = /* @__PURE__ */ new Map();
|
|
9
|
+
async function detectMonorepo(startDir) {
|
|
10
|
+
const cwd = resolve(startDir ?? process.cwd());
|
|
11
|
+
if (monorepoCache.has(cwd)) {
|
|
12
|
+
return monorepoCache.get(cwd);
|
|
13
|
+
}
|
|
14
|
+
let currentDir = cwd;
|
|
15
|
+
while (true) {
|
|
16
|
+
const packageJsonPath2 = path.join(currentDir, "package.json");
|
|
17
|
+
if (existsSync(packageJsonPath2)) {
|
|
18
|
+
const packageJson2 = await readPackageJSON(currentDir);
|
|
19
|
+
if (packageJson2 && hasWorkspaces(packageJson2)) {
|
|
20
|
+
const workspacePackages = await discoverWorkspacePackages(currentDir, packageJson2);
|
|
21
|
+
const result2 = {
|
|
22
|
+
isMonorepo: true,
|
|
23
|
+
rootPath: currentDir,
|
|
24
|
+
rootPackageJson: packageJson2,
|
|
25
|
+
workspacePackages
|
|
26
|
+
};
|
|
27
|
+
monorepoCache.set(cwd, result2);
|
|
28
|
+
return result2;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const parentDir = path.dirname(currentDir);
|
|
32
|
+
if (parentDir === currentDir) {
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
currentDir = parentDir;
|
|
36
|
+
}
|
|
37
|
+
const packageJsonPath = path.join(cwd, "package.json");
|
|
38
|
+
if (!existsSync(packageJsonPath)) {
|
|
39
|
+
throw new Error("No package.json found in current directory or any parent directory");
|
|
40
|
+
}
|
|
41
|
+
const packageJson = await readPackageJSON(cwd);
|
|
42
|
+
if (!packageJson) {
|
|
43
|
+
throw new Error("Could not read package.json");
|
|
44
|
+
}
|
|
45
|
+
const result = {
|
|
46
|
+
isMonorepo: false,
|
|
47
|
+
rootPath: cwd,
|
|
48
|
+
rootPackageJson: packageJson
|
|
49
|
+
};
|
|
50
|
+
monorepoCache.set(cwd, result);
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
const workspaceCache = /* @__PURE__ */ new Map();
|
|
54
|
+
async function discoverWorkspacePackages(monorepoRoot, rootPackageJson) {
|
|
55
|
+
if (workspaceCache.has(monorepoRoot)) {
|
|
56
|
+
return workspaceCache.get(monorepoRoot);
|
|
57
|
+
}
|
|
58
|
+
const packages = [];
|
|
59
|
+
if (!rootPackageJson.workspaces?.packages) {
|
|
60
|
+
workspaceCache.set(monorepoRoot, packages);
|
|
61
|
+
return packages;
|
|
62
|
+
}
|
|
63
|
+
const patterns = Array.isArray(rootPackageJson.workspaces.packages) ? rootPackageJson.workspaces.packages : [];
|
|
64
|
+
const packagePaths = [];
|
|
65
|
+
const validationPromises = [];
|
|
66
|
+
for (const pattern of patterns) {
|
|
67
|
+
if (pattern.includes("*")) {
|
|
68
|
+
const glob = new Bun.Glob(pattern);
|
|
69
|
+
const matches = glob.scanSync({ cwd: monorepoRoot, onlyFiles: false });
|
|
70
|
+
for (const match of matches) {
|
|
71
|
+
const packagePath = resolve(monorepoRoot, match);
|
|
72
|
+
packagePaths.push(packagePath);
|
|
73
|
+
validationPromises.push(isValidWorkspacePackage(packagePath));
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
const packagePath = resolve(monorepoRoot, pattern);
|
|
77
|
+
packagePaths.push(packagePath);
|
|
78
|
+
validationPromises.push(isValidWorkspacePackage(packagePath));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const validationResults = await Promise.all(validationPromises);
|
|
82
|
+
for (let i = 0; i < packagePaths.length; i++) {
|
|
83
|
+
if (validationResults[i]) {
|
|
84
|
+
packages.push(packagePaths[i]);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
workspaceCache.set(monorepoRoot, packages);
|
|
88
|
+
return packages;
|
|
89
|
+
}
|
|
90
|
+
async function isValidWorkspacePackage(packagePath) {
|
|
91
|
+
const packageJsonPath = path.join(packagePath, "package.json");
|
|
92
|
+
if (!existsSync(packageJsonPath)) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
const packageJson = await readPackageJSON(packagePath);
|
|
96
|
+
return !!packageJson?.name;
|
|
97
|
+
}
|
|
98
|
+
function resolveCatalog(monorepoInfo, catalogOption) {
|
|
99
|
+
if (!monorepoInfo.isMonorepo) {
|
|
100
|
+
return { catalogName: null, catalogPath: null };
|
|
101
|
+
}
|
|
102
|
+
const workspaces = monorepoInfo.rootPackageJson.workspaces;
|
|
103
|
+
if (catalogOption === false) {
|
|
104
|
+
return { catalogName: null, catalogPath: null };
|
|
105
|
+
}
|
|
106
|
+
let catalogName;
|
|
107
|
+
if (typeof catalogOption === "string") {
|
|
108
|
+
catalogName = catalogOption;
|
|
109
|
+
} else {
|
|
110
|
+
catalogName = "catalog";
|
|
111
|
+
}
|
|
112
|
+
const catalogExists = workspaces[catalogName];
|
|
113
|
+
if (!catalogExists) {
|
|
114
|
+
if (typeof catalogOption === "string") {
|
|
115
|
+
throw new Error(`Catalog '${catalogName}' not found in workspaces configuration`);
|
|
116
|
+
}
|
|
117
|
+
return { catalogName: null, catalogPath: null };
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
catalogName,
|
|
121
|
+
catalogPath: catalogName
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function containsGlobPattern(str) {
|
|
125
|
+
return str.includes("*") || str.includes("?") || str.includes("[") || str.includes("{");
|
|
126
|
+
}
|
|
127
|
+
function containsMultipleTargets(str) {
|
|
128
|
+
return str.includes(" ") && str.trim().split(/\s+/).length > 1;
|
|
129
|
+
}
|
|
130
|
+
const packageInfoCache = /* @__PURE__ */ new Map();
|
|
131
|
+
async function getWorkspacePackageInfos(monorepoInfo) {
|
|
132
|
+
if (packageInfoCache.has(monorepoInfo.rootPath)) {
|
|
133
|
+
return packageInfoCache.get(monorepoInfo.rootPath);
|
|
134
|
+
}
|
|
135
|
+
if (!monorepoInfo.workspacePackages) {
|
|
136
|
+
const empty = [];
|
|
137
|
+
packageInfoCache.set(monorepoInfo.rootPath, empty);
|
|
138
|
+
return empty;
|
|
139
|
+
}
|
|
140
|
+
const packageInfos = [];
|
|
141
|
+
const readPromises = monorepoInfo.workspacePackages.map(async (pkgPath) => {
|
|
142
|
+
const packageJson = await readPackageJSON(pkgPath);
|
|
143
|
+
if (packageJson?.name) {
|
|
144
|
+
return {
|
|
145
|
+
name: packageJson.name,
|
|
146
|
+
path: pkgPath,
|
|
147
|
+
json: packageJson
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
return null;
|
|
151
|
+
});
|
|
152
|
+
const results = await Promise.all(readPromises);
|
|
153
|
+
for (const result of results) {
|
|
154
|
+
if (result) {
|
|
155
|
+
packageInfos.push(result);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
packageInfoCache.set(monorepoInfo.rootPath, packageInfos);
|
|
159
|
+
return packageInfos;
|
|
160
|
+
}
|
|
161
|
+
async function resolveTargetPackage(monorepoInfo, options) {
|
|
162
|
+
const { target, w } = options;
|
|
163
|
+
if (w) {
|
|
164
|
+
return {
|
|
165
|
+
packagePath: monorepoInfo.rootPath,
|
|
166
|
+
packageJson: monorepoInfo.rootPackageJson
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
if (target) {
|
|
170
|
+
if (!monorepoInfo.isMonorepo) {
|
|
171
|
+
throw new Error("--target can only be used in monorepo environments");
|
|
172
|
+
}
|
|
173
|
+
if (target === ".") {
|
|
174
|
+
const cwd = resolve(options.cwd ?? process.cwd());
|
|
175
|
+
if (path.relative(monorepoInfo.rootPath, cwd) === "") {
|
|
176
|
+
return {
|
|
177
|
+
packagePath: monorepoInfo.rootPath,
|
|
178
|
+
packageJson: monorepoInfo.rootPackageJson
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
const workspacePackage = monorepoInfo.workspacePackages?.find(
|
|
182
|
+
(pkgPath) => path.relative(pkgPath, cwd) === "" || cwd === pkgPath || cwd.startsWith(pkgPath + path.sep)
|
|
183
|
+
);
|
|
184
|
+
if (workspacePackage) {
|
|
185
|
+
const packageInfos2 = await getWorkspacePackageInfos(monorepoInfo);
|
|
186
|
+
const cachedInfo = packageInfos2.find((info) => info.path === workspacePackage);
|
|
187
|
+
if (cachedInfo) {
|
|
188
|
+
return {
|
|
189
|
+
packagePath: workspacePackage,
|
|
190
|
+
packageJson: cachedInfo.json
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
const packageJson = await readPackageJSON(workspacePackage);
|
|
194
|
+
if (!packageJson) {
|
|
195
|
+
throw new Error(`Could not read package.json from ${workspacePackage}`);
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
packagePath: workspacePackage,
|
|
199
|
+
packageJson
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
throw new Error(`Current directory is not a workspace package and not the monorepo root`);
|
|
203
|
+
}
|
|
204
|
+
if (containsMultipleTargets(target)) {
|
|
205
|
+
const targetNames = target.trim().split(/\s+/);
|
|
206
|
+
const packageInfos2 = await getWorkspacePackageInfos(monorepoInfo);
|
|
207
|
+
const targets = [];
|
|
208
|
+
for (const targetName of targetNames) {
|
|
209
|
+
if (targetName === "*") {
|
|
210
|
+
targets.push(
|
|
211
|
+
...packageInfos2.map((pkg) => ({
|
|
212
|
+
packagePath: pkg.path,
|
|
213
|
+
packageJson: pkg.json
|
|
214
|
+
}))
|
|
215
|
+
);
|
|
216
|
+
} else if (containsGlobPattern(targetName)) {
|
|
217
|
+
const includeFilter = createIncludeFilter(targetName);
|
|
218
|
+
const matchingPackages = includeFilter(packageInfos2);
|
|
219
|
+
if (matchingPackages.length === 0) {
|
|
220
|
+
throw new Error(`No workspace packages match pattern '${targetName}'`);
|
|
221
|
+
}
|
|
222
|
+
targets.push(
|
|
223
|
+
...matchingPackages.map((pkg) => ({
|
|
224
|
+
packagePath: pkg.path,
|
|
225
|
+
packageJson: pkg.json
|
|
226
|
+
}))
|
|
227
|
+
);
|
|
228
|
+
} else {
|
|
229
|
+
const matchingPackage2 = packageInfos2.find((info) => info.name === targetName);
|
|
230
|
+
if (!matchingPackage2) {
|
|
231
|
+
throw new Error(`Workspace package '${targetName}' not found`);
|
|
232
|
+
}
|
|
233
|
+
targets.push({
|
|
234
|
+
packagePath: matchingPackage2.path,
|
|
235
|
+
packageJson: matchingPackage2.json
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
const uniqueTargets = targets.filter(
|
|
240
|
+
(target2, index, self) => index === self.findIndex((t) => t.packagePath === target2.packagePath)
|
|
241
|
+
);
|
|
242
|
+
return {
|
|
243
|
+
targets: uniqueTargets,
|
|
244
|
+
isMultiple: true
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
if (target === "*") {
|
|
248
|
+
const packageInfos2 = await getWorkspacePackageInfos(monorepoInfo);
|
|
249
|
+
const targets = packageInfos2.map((pkg) => ({
|
|
250
|
+
packagePath: pkg.path,
|
|
251
|
+
packageJson: pkg.json
|
|
252
|
+
}));
|
|
253
|
+
return {
|
|
254
|
+
targets,
|
|
255
|
+
isMultiple: true
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
const packageInfos = await getWorkspacePackageInfos(monorepoInfo);
|
|
259
|
+
const matchingPackage = packageInfos.find((info) => info.name === target);
|
|
260
|
+
if (!matchingPackage) {
|
|
261
|
+
throw new Error(`Workspace package '${target}' not found`);
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
packagePath: matchingPackage.path,
|
|
265
|
+
packageJson: matchingPackage.json
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
if (monorepoInfo.isMonorepo) {
|
|
269
|
+
return {
|
|
270
|
+
packagePath: monorepoInfo.rootPath,
|
|
271
|
+
packageJson: monorepoInfo.rootPackageJson
|
|
272
|
+
};
|
|
273
|
+
} else {
|
|
274
|
+
return {
|
|
275
|
+
packagePath: monorepoInfo.rootPath,
|
|
276
|
+
packageJson: monorepoInfo.rootPackageJson
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
async function addDependencyToPackage(packagePath, packageJson, packageName, versionSpec, scope, dryRun, verbose) {
|
|
281
|
+
const packageJsonPath = path.join(packagePath, "package.json");
|
|
282
|
+
const fieldName = getDependencyFieldName(scope);
|
|
283
|
+
const relativePath = relative(process.cwd(), packageJsonPath) || "package.json";
|
|
284
|
+
if (packageJson[fieldName]?.[packageName]) {
|
|
285
|
+
if (verbose) {
|
|
286
|
+
logger.info(`\u2139\uFE0F ${packageName} already exists in ${fieldName} of ${relativePath}`);
|
|
287
|
+
}
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
290
|
+
if (!packageJson[fieldName]) {
|
|
291
|
+
packageJson[fieldName] = {};
|
|
292
|
+
}
|
|
293
|
+
packageJson[fieldName][packageName] = versionSpec;
|
|
294
|
+
if (dryRun) {
|
|
295
|
+
if (verbose) {
|
|
296
|
+
logger.log(`\u{1F4DD} Would add ${packageName}@${versionSpec} to ${fieldName} in ${relativePath}`);
|
|
297
|
+
}
|
|
298
|
+
} else {
|
|
299
|
+
await writePackageJSON(packageJsonPath, packageJson);
|
|
300
|
+
}
|
|
301
|
+
return true;
|
|
302
|
+
}
|
|
303
|
+
async function addDependencyToCatalog(monorepoInfo, catalogInfo, packageName, versionSpec, dryRun, verbose) {
|
|
304
|
+
const workspaces = monorepoInfo.rootPackageJson.workspaces;
|
|
305
|
+
const catalogExists = workspaces[catalogInfo.catalogName];
|
|
306
|
+
if (!catalogExists) {
|
|
307
|
+
throw new Error(`Catalog '${catalogInfo.catalogName}' not found`);
|
|
308
|
+
}
|
|
309
|
+
if (catalogExists[packageName]) {
|
|
310
|
+
if (verbose) {
|
|
311
|
+
logger.info(`\u2139\uFE0F ${packageName} already exists in catalog '${catalogInfo.catalogName}'`);
|
|
312
|
+
}
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
if (dryRun) {
|
|
316
|
+
if (verbose) {
|
|
317
|
+
logger.log(
|
|
318
|
+
`\u{1F4DD} Would add ${packageName}@${versionSpec} to catalog '${catalogInfo.catalogName}'`
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
} else {
|
|
322
|
+
catalogExists[packageName] = versionSpec;
|
|
323
|
+
await writePackageJSON(
|
|
324
|
+
path.join(monorepoInfo.rootPath, "package.json"),
|
|
325
|
+
monorepoInfo.rootPackageJson
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
return true;
|
|
329
|
+
}
|
|
330
|
+
function getDependencyFieldName(scope) {
|
|
331
|
+
switch (scope) {
|
|
332
|
+
case "dev":
|
|
333
|
+
return "devDependencies";
|
|
334
|
+
case "prod":
|
|
335
|
+
return "dependencies";
|
|
336
|
+
case "peer":
|
|
337
|
+
return "peerDependencies";
|
|
338
|
+
case "optional":
|
|
339
|
+
return "optionalDependencies";
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
async function resolveVersionSpec(packageName, versionSpec, prefix) {
|
|
343
|
+
if (versionSpec) {
|
|
344
|
+
if (prefix === "none") {
|
|
345
|
+
return versionSpec;
|
|
346
|
+
}
|
|
347
|
+
return `${prefix}${versionSpec}`;
|
|
348
|
+
}
|
|
349
|
+
try {
|
|
350
|
+
const latestVersion = await getLatestVersion(packageName);
|
|
351
|
+
if (prefix === "none") {
|
|
352
|
+
return latestVersion;
|
|
353
|
+
}
|
|
354
|
+
return `${prefix}${latestVersion}`;
|
|
355
|
+
} catch (error) {
|
|
356
|
+
logger.warn(`Failed to fetch latest version for ${packageName}, using 'latest': ${error}`);
|
|
357
|
+
return "latest";
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
async function resolvePackageVersionSpec(packageName, packageIndex, versionSpecs, prefix) {
|
|
361
|
+
let versionSpec;
|
|
362
|
+
if (Array.isArray(versionSpecs)) {
|
|
363
|
+
versionSpec = versionSpecs[packageIndex];
|
|
364
|
+
} else {
|
|
365
|
+
versionSpec = versionSpecs;
|
|
366
|
+
}
|
|
367
|
+
return await resolveVersionSpec(packageName, versionSpec, prefix);
|
|
368
|
+
}
|
|
369
|
+
export async function addDependency(packageNames, options) {
|
|
370
|
+
const packageNameArray = Array.isArray(packageNames) ? packageNames : [packageNames];
|
|
371
|
+
let totalChangesMade = false;
|
|
372
|
+
const addedPackages = [];
|
|
373
|
+
const monorepoInfo = await detectMonorepo(options.cwd);
|
|
374
|
+
logger.log(
|
|
375
|
+
`\u{1F4E6} Detected ${monorepoInfo.isMonorepo ? "monorepo" : "single package"} at ${monorepoInfo.rootPath}`
|
|
376
|
+
);
|
|
377
|
+
const catalogInfo = resolveCatalog(monorepoInfo, options.catalog);
|
|
378
|
+
if (catalogInfo.catalogName) {
|
|
379
|
+
logger.log(`\u{1F4DA} Using catalog '${catalogInfo.catalogName}'`);
|
|
380
|
+
}
|
|
381
|
+
const targetResult = await resolveTargetPackage(monorepoInfo, options);
|
|
382
|
+
if ("isMultiple" in targetResult && targetResult.isMultiple) {
|
|
383
|
+
if (options.verbose) {
|
|
384
|
+
logger.log(`\u{1F3AF} Target packages (${targetResult.targets.length}):`);
|
|
385
|
+
for (const target of targetResult.targets) {
|
|
386
|
+
const relativePath = relative(process.cwd(), target.packagePath) || "package.json";
|
|
387
|
+
logger.log(` \u2022 ${relativePath}`);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
for (const packageName of packageNameArray) {
|
|
391
|
+
let changesMade = false;
|
|
392
|
+
const packageIndex = packageNameArray.indexOf(packageName);
|
|
393
|
+
const versionSpec = await resolvePackageVersionSpec(
|
|
394
|
+
packageName,
|
|
395
|
+
packageIndex,
|
|
396
|
+
options.versionSpec,
|
|
397
|
+
options.prefix
|
|
398
|
+
);
|
|
399
|
+
if (catalogInfo.catalogName && monorepoInfo.isMonorepo) {
|
|
400
|
+
const catalogChanged = await addDependencyToCatalog(
|
|
401
|
+
monorepoInfo,
|
|
402
|
+
catalogInfo,
|
|
403
|
+
packageName,
|
|
404
|
+
versionSpec,
|
|
405
|
+
options.dryRun,
|
|
406
|
+
options.verbose
|
|
407
|
+
);
|
|
408
|
+
changesMade = changesMade || catalogChanged;
|
|
409
|
+
const catalogRef = `catalog:${catalogInfo.catalogName === "catalog" ? "" : catalogInfo.catalogName}`;
|
|
410
|
+
for (const target of targetResult.targets) {
|
|
411
|
+
const packageChanged = await addDependencyToPackage(
|
|
412
|
+
target.packagePath,
|
|
413
|
+
target.packageJson,
|
|
414
|
+
packageName,
|
|
415
|
+
catalogRef,
|
|
416
|
+
options.scope,
|
|
417
|
+
options.dryRun,
|
|
418
|
+
options.verbose
|
|
419
|
+
);
|
|
420
|
+
changesMade = changesMade || packageChanged;
|
|
421
|
+
}
|
|
422
|
+
} else {
|
|
423
|
+
for (const target of targetResult.targets) {
|
|
424
|
+
const packageChanged = await addDependencyToPackage(
|
|
425
|
+
target.packagePath,
|
|
426
|
+
target.packageJson,
|
|
427
|
+
packageName,
|
|
428
|
+
versionSpec,
|
|
429
|
+
options.scope,
|
|
430
|
+
options.dryRun,
|
|
431
|
+
options.verbose
|
|
432
|
+
);
|
|
433
|
+
changesMade = changesMade || packageChanged;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
if (changesMade) {
|
|
437
|
+
addedPackages.push(packageName);
|
|
438
|
+
}
|
|
439
|
+
totalChangesMade = totalChangesMade || changesMade;
|
|
440
|
+
}
|
|
441
|
+
} else {
|
|
442
|
+
const targetInfo = targetResult;
|
|
443
|
+
const relativePath = relative(process.cwd(), targetInfo.packagePath) || "package.json";
|
|
444
|
+
logger.log(`\u{1F3AF} Target package: ${relativePath}`);
|
|
445
|
+
for (const packageName of packageNameArray) {
|
|
446
|
+
let changesMade = false;
|
|
447
|
+
const packageIndex = packageNameArray.indexOf(packageName);
|
|
448
|
+
const versionSpec = await resolvePackageVersionSpec(
|
|
449
|
+
packageName,
|
|
450
|
+
packageIndex,
|
|
451
|
+
options.versionSpec,
|
|
452
|
+
options.prefix
|
|
453
|
+
);
|
|
454
|
+
if (catalogInfo.catalogName && monorepoInfo.isMonorepo) {
|
|
455
|
+
const catalogChanged = await addDependencyToCatalog(
|
|
456
|
+
monorepoInfo,
|
|
457
|
+
catalogInfo,
|
|
458
|
+
packageName,
|
|
459
|
+
versionSpec,
|
|
460
|
+
options.dryRun,
|
|
461
|
+
options.verbose
|
|
462
|
+
);
|
|
463
|
+
changesMade = changesMade || catalogChanged;
|
|
464
|
+
const catalogRef = `catalog:${catalogInfo.catalogName === "catalog" ? "" : catalogInfo.catalogName}`;
|
|
465
|
+
const packageChanged = await addDependencyToPackage(
|
|
466
|
+
targetInfo.packagePath,
|
|
467
|
+
targetInfo.packageJson,
|
|
468
|
+
packageName,
|
|
469
|
+
catalogRef,
|
|
470
|
+
options.scope,
|
|
471
|
+
options.dryRun,
|
|
472
|
+
options.verbose
|
|
473
|
+
);
|
|
474
|
+
changesMade = changesMade || packageChanged;
|
|
475
|
+
} else {
|
|
476
|
+
const packageChanged = await addDependencyToPackage(
|
|
477
|
+
targetInfo.packagePath,
|
|
478
|
+
targetInfo.packageJson,
|
|
479
|
+
packageName,
|
|
480
|
+
versionSpec,
|
|
481
|
+
options.scope,
|
|
482
|
+
options.dryRun,
|
|
483
|
+
options.verbose
|
|
484
|
+
);
|
|
485
|
+
changesMade = changesMade || packageChanged;
|
|
486
|
+
}
|
|
487
|
+
if (changesMade) {
|
|
488
|
+
addedPackages.push(packageName);
|
|
489
|
+
}
|
|
490
|
+
totalChangesMade = totalChangesMade || changesMade;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
if (addedPackages.length > 0) {
|
|
494
|
+
if (options.dryRun) {
|
|
495
|
+
logger.log(`\u{1F4DD} Would add dependencies: ${addedPackages.join(", ")}`);
|
|
496
|
+
} else {
|
|
497
|
+
logger.success(`\u2705 Added dependencies: ${addedPackages.join(", ")}`);
|
|
498
|
+
}
|
|
499
|
+
} else {
|
|
500
|
+
logger.log("\u2139\uFE0F No dependencies to add");
|
|
501
|
+
}
|
|
502
|
+
if (totalChangesMade && options.install && !options.dryRun) {
|
|
503
|
+
try {
|
|
504
|
+
logger.log("Applying changes (bun install)...");
|
|
505
|
+
await runInstallCommand(options.verbose);
|
|
506
|
+
logger.log("Installation completed successfully");
|
|
507
|
+
} catch (error) {
|
|
508
|
+
logger.warn(`Install failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
509
|
+
logger.log("Run 'bun install' manually to apply the changes");
|
|
510
|
+
}
|
|
511
|
+
} else if (!(options.dryRun || options.install)) {
|
|
512
|
+
logger.log("Run 'bun install' to install the new dependencies");
|
|
513
|
+
}
|
|
514
|
+
return totalChangesMade;
|
|
515
|
+
}
|
|
@@ -48,6 +48,13 @@ export const PRESET_CATEGORIES = {
|
|
|
48
48
|
patterns: [".turbo/", ".vercel/", ".wrangler/"],
|
|
49
49
|
order: 7
|
|
50
50
|
},
|
|
51
|
+
// Dler caches
|
|
52
|
+
"dler-cache": {
|
|
53
|
+
name: "dler-cache",
|
|
54
|
+
description: "Dler command caches",
|
|
55
|
+
patterns: ["node_modules/.cache/dler/"],
|
|
56
|
+
order: 8
|
|
57
|
+
},
|
|
51
58
|
// Dependencies (deleted last)
|
|
52
59
|
deps: {
|
|
53
60
|
name: "deps",
|