@yabasha/gex 1.0.0 → 1.1.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/dist/cli-bun.mjs +660 -0
- package/dist/cli-bun.mjs.map +1 -0
- package/dist/cli-node.cjs +572 -0
- package/dist/cli-node.cjs.map +1 -0
- package/dist/cli-node.mjs +540 -0
- package/dist/cli-node.mjs.map +1 -0
- package/dist/cli.cjs +170 -101
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +168 -100
- package/dist/cli.mjs.map +1 -1
- package/dist/index.cjs +18 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +18 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -2
package/dist/cli-bun.mjs
ADDED
|
@@ -0,0 +1,660 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
4
|
+
}) : x)(function(x) {
|
|
5
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
6
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
// src/runtimes/bun/commands.ts
|
|
10
|
+
import path7 from "path";
|
|
11
|
+
import { Command } from "commander";
|
|
12
|
+
|
|
13
|
+
// src/shared/cli/install.ts
|
|
14
|
+
var INSTALL_COMMANDS = {
|
|
15
|
+
npm: {
|
|
16
|
+
global: ["i", "-g"],
|
|
17
|
+
local: ["i"],
|
|
18
|
+
dev: ["i", "-D"]
|
|
19
|
+
},
|
|
20
|
+
bun: {
|
|
21
|
+
global: ["add", "-g"],
|
|
22
|
+
local: ["add"],
|
|
23
|
+
dev: ["add", "-d"]
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var MAX_BUFFER = 10 * 1024 * 1024;
|
|
27
|
+
function formatSpec(pkg) {
|
|
28
|
+
return pkg.version ? `${pkg.name}@${pkg.version}` : pkg.name;
|
|
29
|
+
}
|
|
30
|
+
async function getExecFileAsync() {
|
|
31
|
+
const { execFile } = await import("child_process");
|
|
32
|
+
const { promisify } = await import("util");
|
|
33
|
+
return promisify(execFile);
|
|
34
|
+
}
|
|
35
|
+
async function installFromReport(report, options) {
|
|
36
|
+
const opts = typeof options === "string" ? { cwd: options } : options;
|
|
37
|
+
const { cwd, packageManager = "npm" } = opts;
|
|
38
|
+
const globalPkgs = report.global_packages.map(formatSpec).filter(Boolean);
|
|
39
|
+
const localPkgs = report.local_dependencies.map(formatSpec).filter(Boolean);
|
|
40
|
+
const devPkgs = report.local_dev_dependencies.map(formatSpec).filter(Boolean);
|
|
41
|
+
if (globalPkgs.length === 0 && localPkgs.length === 0 && devPkgs.length === 0) {
|
|
42
|
+
console.log("No packages to install from report.");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const execFileAsync = await getExecFileAsync();
|
|
46
|
+
const cmd = INSTALL_COMMANDS[packageManager];
|
|
47
|
+
const binary = packageManager === "bun" ? "bun" : "npm";
|
|
48
|
+
if (globalPkgs.length > 0) {
|
|
49
|
+
console.log(`Installing global: ${globalPkgs.join(" ")}`);
|
|
50
|
+
await execFileAsync(binary, [...cmd.global, ...globalPkgs], { cwd, maxBuffer: MAX_BUFFER });
|
|
51
|
+
}
|
|
52
|
+
if (localPkgs.length > 0) {
|
|
53
|
+
console.log(`Installing local deps: ${localPkgs.join(" ")}`);
|
|
54
|
+
await execFileAsync(binary, [...cmd.local, ...localPkgs], { cwd, maxBuffer: MAX_BUFFER });
|
|
55
|
+
}
|
|
56
|
+
if (devPkgs.length > 0) {
|
|
57
|
+
console.log(`Installing local devDeps: ${devPkgs.join(" ")}`);
|
|
58
|
+
await execFileAsync(binary, [...cmd.dev, ...devPkgs], { cwd, maxBuffer: MAX_BUFFER });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function printFromReport(report) {
|
|
62
|
+
const lines = [];
|
|
63
|
+
if (report.global_packages.length > 0) {
|
|
64
|
+
lines.push("Global Packages:");
|
|
65
|
+
for (const p of report.global_packages) {
|
|
66
|
+
lines.push(`- ${p.name}@${p.version}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (report.local_dependencies.length > 0) {
|
|
70
|
+
if (lines.length) lines.push("");
|
|
71
|
+
lines.push("Local Dependencies:");
|
|
72
|
+
for (const p of report.local_dependencies) {
|
|
73
|
+
lines.push(`- ${p.name}@${p.version}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (report.local_dev_dependencies.length > 0) {
|
|
77
|
+
if (lines.length) lines.push("");
|
|
78
|
+
lines.push("Local Dev Dependencies:");
|
|
79
|
+
for (const p of report.local_dev_dependencies) {
|
|
80
|
+
lines.push(`- ${p.name}@${p.version}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (lines.length === 0) {
|
|
84
|
+
lines.push("(no packages found in report)");
|
|
85
|
+
}
|
|
86
|
+
console.log(lines.join("\n"));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// src/shared/cli/output.ts
|
|
90
|
+
import path from "path";
|
|
91
|
+
|
|
92
|
+
// src/shared/report/json.ts
|
|
93
|
+
function renderJson(report) {
|
|
94
|
+
const r = {
|
|
95
|
+
...report,
|
|
96
|
+
global_packages: [...report.global_packages].sort((a, b) => a.name.localeCompare(b.name)),
|
|
97
|
+
local_dependencies: [...report.local_dependencies].sort((a, b) => a.name.localeCompare(b.name)),
|
|
98
|
+
local_dev_dependencies: [...report.local_dev_dependencies].sort(
|
|
99
|
+
(a, b) => a.name.localeCompare(b.name)
|
|
100
|
+
)
|
|
101
|
+
};
|
|
102
|
+
return JSON.stringify(r, null, 2);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// src/shared/report/md.ts
|
|
106
|
+
function table(headers, rows) {
|
|
107
|
+
const header = `| ${headers.join(" | ")} |`;
|
|
108
|
+
const sep = `| ${headers.map(() => "---").join(" | ")} |`;
|
|
109
|
+
const body = rows.map((r) => `| ${r.join(" | ")} |`).join("\n");
|
|
110
|
+
return [header, sep, body].filter(Boolean).join("\n");
|
|
111
|
+
}
|
|
112
|
+
function renderMarkdown(report) {
|
|
113
|
+
const lines = [];
|
|
114
|
+
lines.push("# GEX Report");
|
|
115
|
+
lines.push("");
|
|
116
|
+
if (report.project_name || report.project_version || report.project_description || report.project_homepage || report.project_bugs) {
|
|
117
|
+
lines.push("## Project Metadata");
|
|
118
|
+
if (report.project_name) lines.push(`- Name: ${report.project_name}`);
|
|
119
|
+
if (report.project_version) lines.push(`- Version: ${report.project_version}`);
|
|
120
|
+
if (report.project_description)
|
|
121
|
+
lines.push(`- Description: ${report.project_description}`);
|
|
122
|
+
if (report.project_homepage)
|
|
123
|
+
lines.push(`- Homepage: ${report.project_homepage}`);
|
|
124
|
+
if (report.project_bugs) lines.push(`- Bugs: ${report.project_bugs}`);
|
|
125
|
+
lines.push("");
|
|
126
|
+
}
|
|
127
|
+
if (report.global_packages.length > 0) {
|
|
128
|
+
lines.push("## Global Packages");
|
|
129
|
+
const rows = report.global_packages.map((p) => [p.name, p.version || "", p.resolved_path || ""]);
|
|
130
|
+
lines.push(table(["Name", "Version", "Path"], rows));
|
|
131
|
+
lines.push("");
|
|
132
|
+
}
|
|
133
|
+
if (report.local_dependencies.length > 0) {
|
|
134
|
+
lines.push("## Local Dependencies");
|
|
135
|
+
const rows = report.local_dependencies.map((p) => [
|
|
136
|
+
p.name,
|
|
137
|
+
p.version || "",
|
|
138
|
+
p.resolved_path || ""
|
|
139
|
+
]);
|
|
140
|
+
lines.push(table(["Name", "Version", "Path"], rows));
|
|
141
|
+
lines.push("");
|
|
142
|
+
}
|
|
143
|
+
if (report.local_dev_dependencies.length > 0) {
|
|
144
|
+
lines.push("## Local Dev Dependencies");
|
|
145
|
+
const rows = report.local_dev_dependencies.map((p) => [
|
|
146
|
+
p.name,
|
|
147
|
+
p.version || "",
|
|
148
|
+
p.resolved_path || ""
|
|
149
|
+
]);
|
|
150
|
+
lines.push(table(["Name", "Version", "Path"], rows));
|
|
151
|
+
lines.push("");
|
|
152
|
+
}
|
|
153
|
+
lines.push("---");
|
|
154
|
+
lines.push("_Generated by GEX_");
|
|
155
|
+
return lines.join("\n");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// src/shared/cli/output.ts
|
|
159
|
+
async function outputReport(report, format, outFile, markdownExtras) {
|
|
160
|
+
const content = format === "json" ? renderJson(report) : renderMarkdown({ ...report, ...markdownExtras || {} });
|
|
161
|
+
if (outFile) {
|
|
162
|
+
const outDir = path.dirname(outFile);
|
|
163
|
+
const { mkdir, writeFile } = await import("fs/promises");
|
|
164
|
+
await mkdir(outDir, { recursive: true });
|
|
165
|
+
await writeFile(outFile, content, "utf8");
|
|
166
|
+
console.log(`Wrote report to ${outFile}`);
|
|
167
|
+
} else {
|
|
168
|
+
console.log(content);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// src/shared/cli/parser.ts
|
|
173
|
+
import { readFile } from "fs/promises";
|
|
174
|
+
import path2 from "path";
|
|
175
|
+
function isMarkdownReportFile(filePath) {
|
|
176
|
+
const ext = path2.extname(filePath).toLowerCase();
|
|
177
|
+
return ext === ".md" || ext === ".markdown";
|
|
178
|
+
}
|
|
179
|
+
function parseMarkdownPackagesTable(lines, startIndex) {
|
|
180
|
+
const rows = [];
|
|
181
|
+
if (!lines[startIndex] || !lines[startIndex].trim().startsWith("|")) return rows;
|
|
182
|
+
let i = startIndex + 2;
|
|
183
|
+
while (i < lines.length && lines[i].trim().startsWith("|")) {
|
|
184
|
+
const cols = lines[i].split("|").map((c) => c.trim()).filter((_, idx, arr) => !(idx === 0 || idx === arr.length - 1));
|
|
185
|
+
const [name = "", version = "", resolved_path = ""] = cols;
|
|
186
|
+
if (name) rows.push({ name, version, resolved_path });
|
|
187
|
+
i++;
|
|
188
|
+
}
|
|
189
|
+
return rows;
|
|
190
|
+
}
|
|
191
|
+
function parseMarkdownReport(md) {
|
|
192
|
+
const lines = md.split(/\r?\n/);
|
|
193
|
+
const findSection = (title) => lines.findIndex((l) => l.trim().toLowerCase() === `## ${title}`.toLowerCase());
|
|
194
|
+
const parseSection = (idx) => {
|
|
195
|
+
if (idx < 0) return [];
|
|
196
|
+
let i = idx + 1;
|
|
197
|
+
while (i < lines.length && !lines[i].trim().startsWith("|")) i++;
|
|
198
|
+
return parseMarkdownPackagesTable(lines, i);
|
|
199
|
+
};
|
|
200
|
+
const global_packages = parseSection(findSection("Global Packages"));
|
|
201
|
+
const local_dependencies = parseSection(findSection("Local Dependencies"));
|
|
202
|
+
const local_dev_dependencies = parseSection(findSection("Local Dev Dependencies"));
|
|
203
|
+
const report = {
|
|
204
|
+
report_version: "1.0",
|
|
205
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
206
|
+
tool_version: "unknown",
|
|
207
|
+
global_packages,
|
|
208
|
+
local_dependencies,
|
|
209
|
+
local_dev_dependencies
|
|
210
|
+
};
|
|
211
|
+
return report;
|
|
212
|
+
}
|
|
213
|
+
async function loadReportFromFile(reportPath) {
|
|
214
|
+
const raw = await readFile(reportPath, "utf8");
|
|
215
|
+
if (isMarkdownReportFile(reportPath) || raw.startsWith("# GEX Report")) {
|
|
216
|
+
return parseMarkdownReport(raw);
|
|
217
|
+
}
|
|
218
|
+
return JSON.parse(raw);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// src/shared/cli/utils.ts
|
|
222
|
+
import { existsSync } from "fs";
|
|
223
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
224
|
+
import path3 from "path";
|
|
225
|
+
import { fileURLToPath } from "url";
|
|
226
|
+
function getPkgJsonPath() {
|
|
227
|
+
let startDir;
|
|
228
|
+
try {
|
|
229
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
230
|
+
startDir = path3.dirname(__filename);
|
|
231
|
+
} catch {
|
|
232
|
+
startDir = typeof __dirname !== "undefined" ? __dirname : process.cwd();
|
|
233
|
+
}
|
|
234
|
+
return findPackageJson(startDir);
|
|
235
|
+
}
|
|
236
|
+
function findPackageJson(startDir) {
|
|
237
|
+
let current = startDir;
|
|
238
|
+
const maxDepth = 6;
|
|
239
|
+
for (let i = 0; i < maxDepth; i++) {
|
|
240
|
+
const candidate = path3.resolve(current, "package.json");
|
|
241
|
+
if (existsSync(candidate)) {
|
|
242
|
+
return candidate;
|
|
243
|
+
}
|
|
244
|
+
const parent = path3.dirname(current);
|
|
245
|
+
if (parent === current) break;
|
|
246
|
+
current = parent;
|
|
247
|
+
}
|
|
248
|
+
return path3.resolve(process.cwd(), "package.json");
|
|
249
|
+
}
|
|
250
|
+
async function getToolVersion() {
|
|
251
|
+
try {
|
|
252
|
+
const pkgPath = getPkgJsonPath();
|
|
253
|
+
const raw = await readFile2(pkgPath, "utf8");
|
|
254
|
+
const pkg = JSON.parse(raw);
|
|
255
|
+
return pkg.version || "0.0.0";
|
|
256
|
+
} catch {
|
|
257
|
+
return "0.0.0";
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
var ASCII_BANNER = String.raw`
|
|
261
|
+
________ __
|
|
262
|
+
/ _____/ ____ _____/ |_ ____ ____
|
|
263
|
+
/ \ ___ / _ \ / _ \ __\/ __ \ / \
|
|
264
|
+
\ \_\ ( <_> | <_> ) | \ ___/| | \
|
|
265
|
+
\______ /\____/ \____/|__| \___ >___| /
|
|
266
|
+
\/ \/ \/
|
|
267
|
+
GEX
|
|
268
|
+
`;
|
|
269
|
+
|
|
270
|
+
// src/runtimes/bun/report.ts
|
|
271
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
272
|
+
import path6 from "path";
|
|
273
|
+
|
|
274
|
+
// src/shared/transform.ts
|
|
275
|
+
import path4 from "path";
|
|
276
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
277
|
+
function toPkgArray(obj) {
|
|
278
|
+
if (!obj) return [];
|
|
279
|
+
return Object.keys(obj).map((name) => ({ name, node: obj[name] })).filter((p) => p && p.node);
|
|
280
|
+
}
|
|
281
|
+
async function buildReportFromNpmTree(tree, opts) {
|
|
282
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
283
|
+
const report = {
|
|
284
|
+
report_version: "1.0",
|
|
285
|
+
timestamp,
|
|
286
|
+
tool_version: opts.toolVersion,
|
|
287
|
+
global_packages: [],
|
|
288
|
+
local_dependencies: [],
|
|
289
|
+
local_dev_dependencies: []
|
|
290
|
+
};
|
|
291
|
+
if (opts.context === "local") {
|
|
292
|
+
let pkgMeta = null;
|
|
293
|
+
try {
|
|
294
|
+
const pkgJsonPath = path4.join(opts.cwd || process.cwd(), "package.json");
|
|
295
|
+
const raw = await readFile3(pkgJsonPath, "utf8");
|
|
296
|
+
pkgMeta = JSON.parse(raw);
|
|
297
|
+
} catch {
|
|
298
|
+
}
|
|
299
|
+
if (pkgMeta?.name) report.project_name = pkgMeta.name;
|
|
300
|
+
if (pkgMeta?.version) report.project_version = pkgMeta.version;
|
|
301
|
+
const depsObj = tree?.dependencies;
|
|
302
|
+
const devDepsObj = tree?.devDependencies;
|
|
303
|
+
const prodItems = toPkgArray(depsObj);
|
|
304
|
+
const treeDevItems = toPkgArray(devDepsObj);
|
|
305
|
+
if (treeDevItems.length > 0) {
|
|
306
|
+
for (const { name, node } of treeDevItems) {
|
|
307
|
+
const version = node && node.version || "";
|
|
308
|
+
const resolvedPath = node && node.path || path4.join(opts.cwd || process.cwd(), "node_modules", name);
|
|
309
|
+
report.local_dev_dependencies.push({ name, version, resolved_path: resolvedPath });
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
const devKeys = treeDevItems.length > 0 ? new Set(treeDevItems.map((entry) => entry.name)) : new Set(Object.keys(pkgMeta?.devDependencies || {}));
|
|
313
|
+
for (const { name, node } of prodItems) {
|
|
314
|
+
const version = node && node.version || "";
|
|
315
|
+
const resolvedPath = node && node.path || path4.join(opts.cwd || process.cwd(), "node_modules", name);
|
|
316
|
+
const pkg = { name, version, resolved_path: resolvedPath };
|
|
317
|
+
if (!treeDevItems.length && devKeys.has(name)) {
|
|
318
|
+
report.local_dev_dependencies.push(pkg);
|
|
319
|
+
} else {
|
|
320
|
+
report.local_dependencies.push(pkg);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
report.local_dependencies.sort((a, b) => a.name.localeCompare(b.name));
|
|
324
|
+
report.local_dev_dependencies.sort((a, b) => a.name.localeCompare(b.name));
|
|
325
|
+
} else if (opts.context === "global") {
|
|
326
|
+
const depsObj = tree?.dependencies;
|
|
327
|
+
const items = toPkgArray(depsObj);
|
|
328
|
+
for (const { name, node } of items) {
|
|
329
|
+
const version = node && node.version || "";
|
|
330
|
+
const resolvedPath = node && node.path || path4.join(opts.globalRoot || "", name);
|
|
331
|
+
const pkg = { name, version, resolved_path: resolvedPath };
|
|
332
|
+
report.global_packages.push(pkg);
|
|
333
|
+
}
|
|
334
|
+
report.global_packages.sort((a, b) => a.name.localeCompare(b.name));
|
|
335
|
+
}
|
|
336
|
+
if (opts.includeTree) {
|
|
337
|
+
report.tree = tree;
|
|
338
|
+
}
|
|
339
|
+
return report;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// src/runtimes/bun/package-manager.ts
|
|
343
|
+
import path5 from "path";
|
|
344
|
+
import { constants as fsConstants } from "fs";
|
|
345
|
+
import { access, readFile as readFile4, readdir, stat } from "fs/promises";
|
|
346
|
+
var IGNORED_ENTRIES = /* @__PURE__ */ new Set([".bin"]);
|
|
347
|
+
async function bunPmLs(options = {}) {
|
|
348
|
+
if (options.global) {
|
|
349
|
+
const root = await bunPmRootGlobal();
|
|
350
|
+
const manifest2 = await readJson(path5.join(path5.dirname(root), "package.json"));
|
|
351
|
+
const selections2 = buildSelections(manifest2, { includeDev: false });
|
|
352
|
+
const dependencies2 = selections2.prod.size > 0 ? await collectPackagesForNames(root, mapSelections(selections2.prod)) : await collectPackagesFromNodeModules(root);
|
|
353
|
+
return { dependencies: dependencies2, node_modules_path: root };
|
|
354
|
+
}
|
|
355
|
+
const cwd = options.cwd || process.cwd();
|
|
356
|
+
const nodeModulesPath = await bunPmRootLocal(cwd);
|
|
357
|
+
const manifest = await readJson(path5.join(cwd, "package.json"));
|
|
358
|
+
const includeDev = !options.omitDev;
|
|
359
|
+
const selections = buildSelections(manifest, { includeDev });
|
|
360
|
+
const dependencies = selections.prod.size > 0 ? await collectPackagesForNames(nodeModulesPath, mapSelections(selections.prod)) : await collectPackagesFromNodeModules(nodeModulesPath);
|
|
361
|
+
let devDependencies;
|
|
362
|
+
if (includeDev) {
|
|
363
|
+
if (selections.dev.size > 0) {
|
|
364
|
+
devDependencies = await collectPackagesForNames(
|
|
365
|
+
nodeModulesPath,
|
|
366
|
+
mapSelections(selections.dev)
|
|
367
|
+
);
|
|
368
|
+
} else {
|
|
369
|
+
devDependencies = {};
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
return { dependencies, devDependencies, node_modules_path: nodeModulesPath };
|
|
373
|
+
}
|
|
374
|
+
async function bunPmRootGlobal() {
|
|
375
|
+
if (process.env.GEX_BUN_GLOBAL_ROOT) {
|
|
376
|
+
return process.env.GEX_BUN_GLOBAL_ROOT;
|
|
377
|
+
}
|
|
378
|
+
const candidates = getGlobalRootCandidates();
|
|
379
|
+
for (const candidate of candidates) {
|
|
380
|
+
if (candidate && await pathExists(candidate)) {
|
|
381
|
+
return candidate;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return candidates.find((c) => Boolean(c)) || path5.join(process.env.HOME || process.cwd(), ".bun", "install", "global", "node_modules");
|
|
385
|
+
}
|
|
386
|
+
async function bunPmRootLocal(cwd = process.cwd()) {
|
|
387
|
+
if (process.env.GEX_BUN_LOCAL_ROOT) {
|
|
388
|
+
return process.env.GEX_BUN_LOCAL_ROOT;
|
|
389
|
+
}
|
|
390
|
+
return path5.join(cwd, "node_modules");
|
|
391
|
+
}
|
|
392
|
+
async function collectPackagesForNames(nodeModulesPath, packages) {
|
|
393
|
+
const result = {};
|
|
394
|
+
await Promise.all(
|
|
395
|
+
packages.map(async ({ name, declared }) => {
|
|
396
|
+
const pkgDir = packageDir(nodeModulesPath, name);
|
|
397
|
+
const manifest = await readJson(path5.join(pkgDir, "package.json"));
|
|
398
|
+
const pkgName = typeof manifest?.name === "string" ? manifest.name : name;
|
|
399
|
+
const version = typeof manifest?.version === "string" ? manifest.version : declared || "";
|
|
400
|
+
result[pkgName] = { version, path: pkgDir };
|
|
401
|
+
})
|
|
402
|
+
);
|
|
403
|
+
return result;
|
|
404
|
+
}
|
|
405
|
+
async function collectPackagesFromNodeModules(root) {
|
|
406
|
+
const result = {};
|
|
407
|
+
const entries = await safeReadDir(root);
|
|
408
|
+
for (const entry of entries) {
|
|
409
|
+
if (!entry || !entry.name || entry.name.startsWith(".") || IGNORED_ENTRIES.has(entry.name)) {
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
412
|
+
const entryPath = path5.join(root, entry.name);
|
|
413
|
+
if (!await isDir(entry, entryPath)) continue;
|
|
414
|
+
if (entry.name.startsWith("@")) {
|
|
415
|
+
const scopedEntries = await safeReadDir(entryPath);
|
|
416
|
+
for (const scopedEntry of scopedEntries) {
|
|
417
|
+
if (!scopedEntry || !scopedEntry.name || scopedEntry.name.startsWith(".")) continue;
|
|
418
|
+
const scopedPath = path5.join(entryPath, scopedEntry.name);
|
|
419
|
+
if (!await isDir(scopedEntry, scopedPath)) continue;
|
|
420
|
+
const manifest = await readJson(path5.join(scopedPath, "package.json"));
|
|
421
|
+
const pkgName = typeof manifest?.name === "string" ? manifest.name : `${entry.name}/${scopedEntry.name}`;
|
|
422
|
+
const version = typeof manifest?.version === "string" ? manifest.version : "";
|
|
423
|
+
result[pkgName] = { version, path: scopedPath };
|
|
424
|
+
}
|
|
425
|
+
} else {
|
|
426
|
+
const manifest = await readJson(path5.join(entryPath, "package.json"));
|
|
427
|
+
const pkgName = typeof manifest?.name === "string" ? manifest.name : entry.name;
|
|
428
|
+
const version = typeof manifest?.version === "string" ? manifest.version : "";
|
|
429
|
+
result[pkgName] = { version, path: entryPath };
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
return result;
|
|
433
|
+
}
|
|
434
|
+
async function readJson(file) {
|
|
435
|
+
try {
|
|
436
|
+
const raw = await readFile4(file, "utf8");
|
|
437
|
+
return JSON.parse(raw);
|
|
438
|
+
} catch {
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
function packageDir(root, packageName) {
|
|
443
|
+
const segments = packageName.startsWith("@") ? packageName.split("/") : [packageName];
|
|
444
|
+
return path5.join(root, ...segments);
|
|
445
|
+
}
|
|
446
|
+
function buildSelections(manifest, { includeDev }) {
|
|
447
|
+
const prod = /* @__PURE__ */ new Map();
|
|
448
|
+
const dev = /* @__PURE__ */ new Map();
|
|
449
|
+
const addAll = (target, record) => {
|
|
450
|
+
if (!record) return;
|
|
451
|
+
for (const [name, range] of Object.entries(record)) {
|
|
452
|
+
if (!target.has(name)) {
|
|
453
|
+
target.set(name, range);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
addAll(prod, manifest?.dependencies);
|
|
458
|
+
addAll(prod, manifest?.optionalDependencies);
|
|
459
|
+
if (includeDev) addAll(dev, manifest?.devDependencies);
|
|
460
|
+
return { prod, dev };
|
|
461
|
+
}
|
|
462
|
+
function mapSelections(map) {
|
|
463
|
+
return Array.from(map.entries()).map(([name, declared]) => ({ name, declared }));
|
|
464
|
+
}
|
|
465
|
+
async function safeReadDir(dir) {
|
|
466
|
+
try {
|
|
467
|
+
return await readdir(dir, { withFileTypes: true });
|
|
468
|
+
} catch {
|
|
469
|
+
return [];
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
async function isDir(entry, fullPath) {
|
|
473
|
+
if (entry.isDirectory()) return true;
|
|
474
|
+
if (entry.isSymbolicLink()) {
|
|
475
|
+
try {
|
|
476
|
+
const stats = await stat(fullPath);
|
|
477
|
+
return stats.isDirectory();
|
|
478
|
+
} catch {
|
|
479
|
+
return false;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return false;
|
|
483
|
+
}
|
|
484
|
+
async function pathExists(target) {
|
|
485
|
+
try {
|
|
486
|
+
await access(target, fsConstants.R_OK);
|
|
487
|
+
return true;
|
|
488
|
+
} catch {
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
function getGlobalRootCandidates() {
|
|
493
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
494
|
+
const bunInstall = process.env.BUN_INSTALL || (process.env.HOME ? path5.join(process.env.HOME, ".bun") : void 0);
|
|
495
|
+
const maybeAdd = (value) => {
|
|
496
|
+
if (value) candidates.add(value);
|
|
497
|
+
};
|
|
498
|
+
if (bunInstall) {
|
|
499
|
+
maybeAdd(path5.join(bunInstall, "install", "global", "node_modules"));
|
|
500
|
+
maybeAdd(path5.join(bunInstall, "global", "node_modules"));
|
|
501
|
+
}
|
|
502
|
+
if (process.env.XDG_DATA_HOME) {
|
|
503
|
+
maybeAdd(path5.join(process.env.XDG_DATA_HOME, "bun", "install", "global", "node_modules"));
|
|
504
|
+
}
|
|
505
|
+
maybeAdd("/usr/local/share/bun/global/node_modules");
|
|
506
|
+
maybeAdd("/opt/homebrew/var/bun/install/global/node_modules");
|
|
507
|
+
return Array.from(candidates);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// src/runtimes/bun/report.ts
|
|
511
|
+
async function produceReport(ctx, options) {
|
|
512
|
+
const toolVersion = await getToolVersion();
|
|
513
|
+
const cwd = options.cwd || process.cwd();
|
|
514
|
+
const tree = await bunPmLs({
|
|
515
|
+
global: ctx === "global",
|
|
516
|
+
omitDev: ctx === "local" ? Boolean(options.omitDev) : false,
|
|
517
|
+
cwd
|
|
518
|
+
});
|
|
519
|
+
const nodeModulesPath = tree?.node_modules_path;
|
|
520
|
+
let project_description;
|
|
521
|
+
let project_homepage;
|
|
522
|
+
let project_bugs;
|
|
523
|
+
if (ctx === "local") {
|
|
524
|
+
try {
|
|
525
|
+
const pkgRaw = await readFile5(path6.join(cwd, "package.json"), "utf8");
|
|
526
|
+
const pkg = JSON.parse(pkgRaw);
|
|
527
|
+
project_description = pkg.description;
|
|
528
|
+
project_homepage = pkg.homepage;
|
|
529
|
+
if (typeof pkg.bugs === "string") project_bugs = pkg.bugs;
|
|
530
|
+
else if (pkg.bugs && typeof pkg.bugs.url === "string") project_bugs = pkg.bugs.url;
|
|
531
|
+
} catch {
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
const resolvedRoot = nodeModulesPath ? nodeModulesPath : ctx === "global" ? await bunPmRootGlobal().catch(() => void 0) : await bunPmRootLocal(cwd).catch(() => `${cwd}/node_modules`);
|
|
535
|
+
const report = await buildReportFromNpmTree(tree, {
|
|
536
|
+
context: ctx,
|
|
537
|
+
includeTree: Boolean(options.fullTree),
|
|
538
|
+
omitDev: Boolean(options.omitDev),
|
|
539
|
+
cwd,
|
|
540
|
+
toolVersion,
|
|
541
|
+
globalRoot: resolvedRoot
|
|
542
|
+
});
|
|
543
|
+
const markdownExtras = { project_description, project_homepage, project_bugs };
|
|
544
|
+
return { report, markdownExtras };
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// src/runtimes/bun/commands.ts
|
|
548
|
+
function addCommonOptions(cmd, { allowOmitDev }) {
|
|
549
|
+
cmd.option(
|
|
550
|
+
"-f, --output-format <format>",
|
|
551
|
+
"Output format: md or json",
|
|
552
|
+
(val) => val === "md" ? "md" : "json",
|
|
553
|
+
"json"
|
|
554
|
+
).option("-o, --out-file <path>", "Write report to file").option("--full-tree", "Include full bun pm ls tree (when available)", false);
|
|
555
|
+
if (allowOmitDev) {
|
|
556
|
+
cmd.option("--omit-dev", "Exclude devDependencies (local only)", false);
|
|
557
|
+
}
|
|
558
|
+
return cmd;
|
|
559
|
+
}
|
|
560
|
+
function createLocalCommand(program) {
|
|
561
|
+
const localCmd = program.command("local", { isDefault: true }).description("Generate a report for the current Bun project's dependencies");
|
|
562
|
+
addCommonOptions(localCmd, { allowOmitDev: true });
|
|
563
|
+
localCmd.action(async (opts) => {
|
|
564
|
+
const outputFormat = opts.outputFormat ?? "json";
|
|
565
|
+
const outFile = opts.outFile;
|
|
566
|
+
const fullTree = Boolean(opts.fullTree);
|
|
567
|
+
const omitDev = Boolean(opts.omitDev);
|
|
568
|
+
const finalOutFile = outFile;
|
|
569
|
+
const { report, markdownExtras } = await produceReport("local", {
|
|
570
|
+
outputFormat,
|
|
571
|
+
outFile: finalOutFile,
|
|
572
|
+
fullTree,
|
|
573
|
+
omitDev
|
|
574
|
+
});
|
|
575
|
+
await outputReport(report, outputFormat, finalOutFile, markdownExtras);
|
|
576
|
+
});
|
|
577
|
+
return localCmd;
|
|
578
|
+
}
|
|
579
|
+
function createGlobalCommand(program) {
|
|
580
|
+
const globalCmd = program.command("global").description("Generate a report of globally installed Bun packages");
|
|
581
|
+
addCommonOptions(globalCmd, { allowOmitDev: false });
|
|
582
|
+
globalCmd.action(async (opts) => {
|
|
583
|
+
const outputFormat = opts.outputFormat ?? "json";
|
|
584
|
+
const outFile = opts.outFile;
|
|
585
|
+
const fullTree = Boolean(opts.fullTree);
|
|
586
|
+
const finalOutFile = outFile;
|
|
587
|
+
const { report, markdownExtras } = await produceReport("global", {
|
|
588
|
+
outputFormat,
|
|
589
|
+
outFile: finalOutFile,
|
|
590
|
+
fullTree
|
|
591
|
+
});
|
|
592
|
+
await outputReport(report, outputFormat, finalOutFile, markdownExtras);
|
|
593
|
+
});
|
|
594
|
+
return globalCmd;
|
|
595
|
+
}
|
|
596
|
+
function createReadCommand(program) {
|
|
597
|
+
const readCmd = program.command("read").description(
|
|
598
|
+
"Read a previously generated report (JSON or Markdown) and either print package names or install them"
|
|
599
|
+
).argument("[report]", "Path to report file (JSON or Markdown)", "bun-report.json").option("-r, --report <path>", "Path to report file (JSON or Markdown)").option("-p, --print", "Print package names/versions from the report (default)", false).option("-i, --install", "Install packages from the report using Bun", false);
|
|
600
|
+
readCmd.action(async (reportArg, opts) => {
|
|
601
|
+
const chosen = opts.report || reportArg || "bun-report.json";
|
|
602
|
+
const reportPath = path7.resolve(process.cwd(), chosen);
|
|
603
|
+
try {
|
|
604
|
+
const parsed = await loadReportFromFile(reportPath);
|
|
605
|
+
const doInstall = Boolean(opts.install);
|
|
606
|
+
const doPrint = Boolean(opts.print) || !doInstall;
|
|
607
|
+
if (doPrint) {
|
|
608
|
+
printFromReport(parsed);
|
|
609
|
+
}
|
|
610
|
+
if (doInstall) {
|
|
611
|
+
await installFromReport(parsed, { cwd: process.cwd(), packageManager: "bun" });
|
|
612
|
+
}
|
|
613
|
+
} catch (err) {
|
|
614
|
+
const isMd = isMarkdownReportFile(reportPath);
|
|
615
|
+
const hint = isMd ? "Try generating a JSON report with: gex-bun global -f json -o global.json, then: gex-bun read global.json" : "Specify a report path with: gex-bun read <path-to-report.json>";
|
|
616
|
+
console.error(`Failed to read report at ${reportPath}: ${err?.message || err}`);
|
|
617
|
+
console.error(hint);
|
|
618
|
+
process.exitCode = 1;
|
|
619
|
+
}
|
|
620
|
+
});
|
|
621
|
+
return readCmd;
|
|
622
|
+
}
|
|
623
|
+
async function createProgram() {
|
|
624
|
+
const program = new Command().name("gex-bun").description("GEX: Dependency auditing and documentation for Bun (local and global).").version(await getToolVersion());
|
|
625
|
+
program.addHelpText("beforeAll", `
|
|
626
|
+
${ASCII_BANNER}`);
|
|
627
|
+
createLocalCommand(program);
|
|
628
|
+
createGlobalCommand(program);
|
|
629
|
+
createReadCommand(program);
|
|
630
|
+
return program;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// src/runtimes/bun/cli.ts
|
|
634
|
+
async function run(argv = process.argv) {
|
|
635
|
+
const program = await createProgram();
|
|
636
|
+
await program.parseAsync(argv);
|
|
637
|
+
}
|
|
638
|
+
var isMainModule = (() => {
|
|
639
|
+
try {
|
|
640
|
+
if (typeof __require !== "undefined" && typeof module !== "undefined") {
|
|
641
|
+
return __require.main === module;
|
|
642
|
+
}
|
|
643
|
+
if (typeof import.meta !== "undefined") {
|
|
644
|
+
return import.meta.url === `file://${process.argv[1]}`;
|
|
645
|
+
}
|
|
646
|
+
return false;
|
|
647
|
+
} catch {
|
|
648
|
+
return false;
|
|
649
|
+
}
|
|
650
|
+
})();
|
|
651
|
+
if (isMainModule) {
|
|
652
|
+
run().catch((error) => {
|
|
653
|
+
console.error("Bun CLI error:", error);
|
|
654
|
+
process.exitCode = 1;
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
export {
|
|
658
|
+
run
|
|
659
|
+
};
|
|
660
|
+
//# sourceMappingURL=cli-bun.mjs.map
|