@yabasha/gex 1.3.4 → 1.3.6
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 +45 -26
- package/dist/cli.cjs +39 -725
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +38 -720
- package/dist/cli.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -6,707 +6,49 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
6
6
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
7
|
});
|
|
8
8
|
|
|
9
|
-
// src/
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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: promisify2 } = await import("util");
|
|
33
|
-
return promisify2(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/npm-cli.ts
|
|
222
|
-
import { promisify } from "util";
|
|
223
|
-
async function getExecFileAsync2() {
|
|
224
|
-
const { execFile } = await import("child_process");
|
|
225
|
-
return promisify(execFile);
|
|
226
|
-
}
|
|
227
|
-
async function npmOutdated(options = {}) {
|
|
228
|
-
const args = ["outdated", "--json"];
|
|
229
|
-
if (options.global) args.push("--global");
|
|
230
|
-
try {
|
|
231
|
-
const execFileAsync = await getExecFileAsync2();
|
|
232
|
-
const { stdout } = await execFileAsync("npm", args, {
|
|
233
|
-
cwd: options.cwd,
|
|
234
|
-
maxBuffer: 10 * 1024 * 1024
|
|
235
|
-
});
|
|
236
|
-
return normalizeOutdated(stdout);
|
|
237
|
-
} catch (error) {
|
|
238
|
-
const stdout = typeof error?.stdout === "string" ? error.stdout : "";
|
|
239
|
-
if (stdout.trim()) {
|
|
240
|
-
return normalizeOutdated(stdout);
|
|
241
|
-
}
|
|
242
|
-
throw formatNpmError(error, "npm outdated");
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
async function npmUpdate(options) {
|
|
246
|
-
const args = ["update"];
|
|
247
|
-
if (options.global) args.push("-g");
|
|
248
|
-
if (options.packages && options.packages.length > 0) args.push(...options.packages);
|
|
249
|
-
try {
|
|
250
|
-
const execFileAsync = await getExecFileAsync2();
|
|
251
|
-
await execFileAsync("npm", args, {
|
|
252
|
-
cwd: options.cwd,
|
|
253
|
-
maxBuffer: 10 * 1024 * 1024
|
|
254
|
-
});
|
|
255
|
-
} catch (error) {
|
|
256
|
-
throw formatNpmError(error, "npm update");
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
function normalizeOutdated(stdout) {
|
|
260
|
-
if (!stdout.trim()) return [];
|
|
261
|
-
let data;
|
|
262
|
-
try {
|
|
263
|
-
data = JSON.parse(stdout);
|
|
264
|
-
} catch {
|
|
265
|
-
return [];
|
|
266
|
-
}
|
|
267
|
-
if (!data) return [];
|
|
268
|
-
return Object.entries(data).map(([name, info]) => ({
|
|
269
|
-
name,
|
|
270
|
-
current: info?.current ? String(info.current) : "",
|
|
271
|
-
wanted: info?.wanted ? String(info.wanted) : "",
|
|
272
|
-
latest: info?.latest ? String(info.latest) : "",
|
|
273
|
-
type: info?.type ? String(info.type) : void 0
|
|
274
|
-
}));
|
|
275
|
-
}
|
|
276
|
-
function formatNpmError(error, commandLabel) {
|
|
277
|
-
const stderr = typeof error?.stderr === "string" ? error.stderr.trim() : "";
|
|
278
|
-
const message = stderr || error?.message || `${commandLabel} failed`;
|
|
279
|
-
return new Error(`${commandLabel} failed: ${message}`);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// src/shared/cli/loader.ts
|
|
283
|
-
var frames = ["-", "\\", "|", "/"];
|
|
284
|
-
function createLoader(message) {
|
|
285
|
-
if (!process.stdout.isTTY) {
|
|
286
|
-
console.log(`${message}...`);
|
|
287
|
-
return {
|
|
288
|
-
stop(finalMessage) {
|
|
289
|
-
if (finalMessage) console.log(finalMessage);
|
|
290
|
-
}
|
|
291
|
-
};
|
|
292
|
-
}
|
|
293
|
-
let index = 0;
|
|
294
|
-
const interval = globalThis.setInterval(() => {
|
|
295
|
-
const frame = frames[index % frames.length];
|
|
296
|
-
index += 1;
|
|
297
|
-
process.stdout.write(`\r${message} ${frame}`);
|
|
298
|
-
}, 80);
|
|
299
|
-
return {
|
|
300
|
-
stop(finalMessage) {
|
|
301
|
-
globalThis.clearInterval(interval);
|
|
302
|
-
process.stdout.write("\r");
|
|
303
|
-
if (finalMessage) {
|
|
304
|
-
console.log(finalMessage);
|
|
305
|
-
} else {
|
|
306
|
-
process.stdout.write("\x1B[2K");
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// src/shared/cli/outdated.ts
|
|
313
|
-
function normalizeUpdateSelection(value) {
|
|
314
|
-
if (value === void 0) {
|
|
315
|
-
return { shouldUpdate: false, updateAll: false, packages: [] };
|
|
316
|
-
}
|
|
317
|
-
if (value === true) {
|
|
318
|
-
return { shouldUpdate: true, updateAll: true, packages: [] };
|
|
319
|
-
}
|
|
320
|
-
const packages = Array.isArray(value) ? value : typeof value === "string" ? [value] : [];
|
|
321
|
-
const normalized = packages.flatMap(
|
|
322
|
-
(entry) => String(entry).split(",").map((part) => part.trim())
|
|
323
|
-
).filter(Boolean);
|
|
324
|
-
return {
|
|
325
|
-
shouldUpdate: true,
|
|
326
|
-
updateAll: false,
|
|
327
|
-
packages: normalized
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
function formatOutdatedTable(entries) {
|
|
331
|
-
const headers = ["Name", "Current", "Wanted", "Latest", "Type"];
|
|
332
|
-
const rows = entries.map((entry) => [
|
|
333
|
-
entry.name,
|
|
334
|
-
entry.current || "-",
|
|
335
|
-
entry.wanted || "-",
|
|
336
|
-
entry.latest || "-",
|
|
337
|
-
entry.type || "-"
|
|
338
|
-
]);
|
|
339
|
-
const widths = headers.map(
|
|
340
|
-
(header, index) => Math.max(header.length, ...rows.map((row) => row[index].length))
|
|
341
|
-
);
|
|
342
|
-
const formatRow = (columns) => columns.map((col, idx) => col.padEnd(widths[idx], " ")).join(" ");
|
|
343
|
-
const lines = [formatRow(headers), formatRow(widths.map((w) => "-".repeat(w)))];
|
|
344
|
-
for (const row of rows) {
|
|
345
|
-
lines.push(formatRow(row));
|
|
346
|
-
}
|
|
347
|
-
return lines.join("\n");
|
|
348
|
-
}
|
|
349
|
-
async function handleOutdatedWorkflow(opts) {
|
|
350
|
-
if (!opts.checkOutdated && !opts.selection.shouldUpdate) {
|
|
351
|
-
return { proceed: true, outdated: [] };
|
|
352
|
-
}
|
|
353
|
-
let fetchLoader;
|
|
354
|
-
if (opts.checkOutdated || opts.selection.shouldUpdate) {
|
|
355
|
-
fetchLoader = createLoader("Checking for outdated packages");
|
|
356
|
-
}
|
|
357
|
-
const outdated = await opts.fetchOutdated();
|
|
358
|
-
fetchLoader?.stop("Finished checking outdated packages.");
|
|
359
|
-
if (opts.selection.shouldUpdate && opts.updateRunner) {
|
|
360
|
-
const packagesToUpdate = opts.selection.updateAll ? outdated.map((entry) => entry.name) : opts.selection.packages;
|
|
361
|
-
if (!packagesToUpdate || packagesToUpdate.length === 0) {
|
|
362
|
-
if (opts.selection.updateAll) {
|
|
363
|
-
console.log("No outdated packages to update.");
|
|
364
|
-
} else {
|
|
365
|
-
console.log("No packages were specified for updating.");
|
|
366
|
-
}
|
|
367
|
-
} else {
|
|
368
|
-
const updateLoader = createLoader("Updating packages");
|
|
369
|
-
await opts.updateRunner(packagesToUpdate);
|
|
370
|
-
updateLoader.stop("Finished updating packages.");
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
const proceed = !((opts.checkOutdated || opts.selection.shouldUpdate) && !opts.outFile);
|
|
374
|
-
return { proceed, outdated };
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// src/shared/cli/utils.ts
|
|
378
|
-
import { existsSync } from "fs";
|
|
379
|
-
import { readFile as readFile2 } from "fs/promises";
|
|
380
|
-
import path3 from "path";
|
|
381
|
-
import { fileURLToPath } from "url";
|
|
382
|
-
function getPkgJsonPath() {
|
|
383
|
-
let startDir;
|
|
384
|
-
try {
|
|
385
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
386
|
-
startDir = path3.dirname(__filename);
|
|
387
|
-
} catch {
|
|
388
|
-
startDir = typeof __dirname !== "undefined" ? __dirname : process.cwd();
|
|
389
|
-
}
|
|
390
|
-
return findPackageJson(startDir);
|
|
391
|
-
}
|
|
392
|
-
function findPackageJson(startDir) {
|
|
393
|
-
let current = startDir;
|
|
394
|
-
const maxDepth = 6;
|
|
395
|
-
for (let i = 0; i < maxDepth; i++) {
|
|
396
|
-
const candidate = path3.resolve(current, "package.json");
|
|
397
|
-
if (existsSync(candidate)) {
|
|
398
|
-
return candidate;
|
|
399
|
-
}
|
|
400
|
-
const parent = path3.dirname(current);
|
|
401
|
-
if (parent === current) break;
|
|
402
|
-
current = parent;
|
|
403
|
-
}
|
|
404
|
-
return path3.resolve(process.cwd(), "package.json");
|
|
405
|
-
}
|
|
406
|
-
async function getToolVersion() {
|
|
407
|
-
try {
|
|
408
|
-
const pkgPath = getPkgJsonPath();
|
|
409
|
-
const raw = await readFile2(pkgPath, "utf8");
|
|
410
|
-
const pkg = JSON.parse(raw);
|
|
411
|
-
return pkg.version || "0.0.0";
|
|
412
|
-
} catch {
|
|
413
|
-
return "0.0.0";
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
var ASCII_BANNER = String.raw`
|
|
417
|
-
________ __
|
|
418
|
-
/ _____/ ____ _____/ |_ ____ ____
|
|
419
|
-
/ \ ___ / _ \ / _ \ __\/ __ \ / \
|
|
420
|
-
\ \_\ ( <_> | <_> ) | \ ___/| | \
|
|
421
|
-
\______ /\____/ \____/|__| \___ >___| /
|
|
422
|
-
\/ \/ \/
|
|
423
|
-
GEX
|
|
424
|
-
`;
|
|
425
|
-
|
|
426
|
-
// src/runtimes/node/report.ts
|
|
427
|
-
import { readFile as readFile4 } from "fs/promises";
|
|
428
|
-
import path5 from "path";
|
|
429
|
-
|
|
430
|
-
// src/shared/transform.ts
|
|
431
|
-
import path4 from "path";
|
|
432
|
-
import { readFile as readFile3 } from "fs/promises";
|
|
433
|
-
function toPkgArray(obj) {
|
|
434
|
-
if (!obj) return [];
|
|
435
|
-
return Object.keys(obj).map((name) => ({ name, node: obj[name] })).filter((p) => p && p.node);
|
|
436
|
-
}
|
|
437
|
-
async function buildReportFromNpmTree(tree, opts) {
|
|
438
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
439
|
-
const report = {
|
|
440
|
-
report_version: "1.0",
|
|
441
|
-
timestamp,
|
|
442
|
-
tool_version: opts.toolVersion,
|
|
443
|
-
global_packages: [],
|
|
444
|
-
local_dependencies: [],
|
|
445
|
-
local_dev_dependencies: []
|
|
446
|
-
};
|
|
447
|
-
if (opts.context === "local") {
|
|
448
|
-
let pkgMeta = null;
|
|
449
|
-
try {
|
|
450
|
-
const pkgJsonPath = path4.join(opts.cwd || process.cwd(), "package.json");
|
|
451
|
-
const raw = await readFile3(pkgJsonPath, "utf8");
|
|
452
|
-
pkgMeta = JSON.parse(raw);
|
|
453
|
-
} catch {
|
|
454
|
-
}
|
|
455
|
-
if (pkgMeta?.name) report.project_name = pkgMeta.name;
|
|
456
|
-
if (pkgMeta?.version) report.project_version = pkgMeta.version;
|
|
457
|
-
const depsObj = tree?.dependencies;
|
|
458
|
-
const devDepsObj = tree?.devDependencies;
|
|
459
|
-
const prodItems = toPkgArray(depsObj);
|
|
460
|
-
const treeDevItems = toPkgArray(devDepsObj);
|
|
461
|
-
if (treeDevItems.length > 0) {
|
|
462
|
-
for (const { name, node } of treeDevItems) {
|
|
463
|
-
const version = node && node.version || "";
|
|
464
|
-
const resolvedPath = node && node.path || path4.join(opts.cwd || process.cwd(), "node_modules", name);
|
|
465
|
-
report.local_dev_dependencies.push({ name, version, resolved_path: resolvedPath });
|
|
9
|
+
// src/cli.ts
|
|
10
|
+
import readline from "readline";
|
|
11
|
+
async function promptRuntimeSelection(io = {}) {
|
|
12
|
+
const input = io.input ?? process.stdin;
|
|
13
|
+
const output = io.output ?? process.stdout;
|
|
14
|
+
return new Promise((resolve) => {
|
|
15
|
+
const rl = readline.createInterface({ input, output });
|
|
16
|
+
output.write("\nSelect a runtime to use:\n");
|
|
17
|
+
output.write(" 1) gex-bun (Bun package manager)\n");
|
|
18
|
+
output.write(" 2) gex-npm (npm / Node.js package manager)\n\n");
|
|
19
|
+
rl.question("Enter your choice (1-2): ", (answer) => {
|
|
20
|
+
rl.close();
|
|
21
|
+
const choice = answer.trim().toLowerCase();
|
|
22
|
+
if (choice === "1" || choice === "gex-bun" || choice === "bun") {
|
|
23
|
+
resolve("bun");
|
|
24
|
+
return;
|
|
466
25
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
const version = node && node.version || "";
|
|
471
|
-
const resolvedPath = node && node.path || path4.join(opts.cwd || process.cwd(), "node_modules", name);
|
|
472
|
-
const pkg = { name, version, resolved_path: resolvedPath };
|
|
473
|
-
if (!treeDevItems.length && devKeys.has(name)) {
|
|
474
|
-
report.local_dev_dependencies.push(pkg);
|
|
475
|
-
} else {
|
|
476
|
-
report.local_dependencies.push(pkg);
|
|
26
|
+
if (choice === "2" || choice === "gex-npm" || choice === "gex-node" || choice === "npm" || choice === "node") {
|
|
27
|
+
resolve("npm");
|
|
28
|
+
return;
|
|
477
29
|
}
|
|
478
|
-
|
|
479
|
-
report.local_dependencies.sort((a, b) => a.name.localeCompare(b.name));
|
|
480
|
-
report.local_dev_dependencies.sort((a, b) => a.name.localeCompare(b.name));
|
|
481
|
-
} else if (opts.context === "global") {
|
|
482
|
-
const depsObj = tree?.dependencies;
|
|
483
|
-
const items = toPkgArray(depsObj);
|
|
484
|
-
for (const { name, node } of items) {
|
|
485
|
-
const version = node && node.version || "";
|
|
486
|
-
const resolvedPath = node && node.path || path4.join(opts.globalRoot || "", name);
|
|
487
|
-
const pkg = { name, version, resolved_path: resolvedPath };
|
|
488
|
-
report.global_packages.push(pkg);
|
|
489
|
-
}
|
|
490
|
-
report.global_packages.sort((a, b) => a.name.localeCompare(b.name));
|
|
491
|
-
}
|
|
492
|
-
if (opts.includeTree) {
|
|
493
|
-
report.tree = tree;
|
|
494
|
-
}
|
|
495
|
-
return report;
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
// src/runtimes/node/package-manager.ts
|
|
499
|
-
async function getExecFileAsync3() {
|
|
500
|
-
const { execFile } = await import("child_process");
|
|
501
|
-
const { promisify: promisify2 } = await import("util");
|
|
502
|
-
return promisify2(execFile);
|
|
503
|
-
}
|
|
504
|
-
async function npmLs(options = {}) {
|
|
505
|
-
const args = ["ls", "--json"];
|
|
506
|
-
if (options.global) args.push("--global");
|
|
507
|
-
if (options.omitDev) args.push("--omit=dev");
|
|
508
|
-
if (options.depth0) args.push("--depth=0");
|
|
509
|
-
try {
|
|
510
|
-
const execFileAsync = await getExecFileAsync3();
|
|
511
|
-
const { stdout } = await execFileAsync("npm", args, {
|
|
512
|
-
cwd: options.cwd,
|
|
513
|
-
maxBuffer: 10 * 1024 * 1024
|
|
30
|
+
resolve(null);
|
|
514
31
|
});
|
|
515
|
-
if (stdout && stdout.trim()) return JSON.parse(stdout);
|
|
516
|
-
return {};
|
|
517
|
-
} catch (err) {
|
|
518
|
-
const stdout = err?.stdout;
|
|
519
|
-
if (typeof stdout === "string" && stdout.trim()) {
|
|
520
|
-
try {
|
|
521
|
-
return JSON.parse(stdout);
|
|
522
|
-
} catch (parseErr) {
|
|
523
|
-
if (process.env.DEBUG?.includes("gex")) {
|
|
524
|
-
console.warn("npm ls stdout parse failed:", parseErr);
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
const stderr = err?.stderr;
|
|
529
|
-
const msg = typeof stderr === "string" && stderr.trim() || err?.message || "npm ls failed";
|
|
530
|
-
throw new Error(`npm ls failed: ${msg}`);
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
async function npmRootGlobal() {
|
|
534
|
-
try {
|
|
535
|
-
const execFileAsync = await getExecFileAsync3();
|
|
536
|
-
const { stdout } = await execFileAsync("npm", ["root", "-g"]);
|
|
537
|
-
return stdout.trim();
|
|
538
|
-
} catch (err) {
|
|
539
|
-
const stderr = err?.stderr;
|
|
540
|
-
const msg = typeof stderr === "string" && stderr.trim() || err?.message || "npm root -g failed";
|
|
541
|
-
throw new Error(`npm root -g failed: ${msg}`);
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
// src/runtimes/node/report.ts
|
|
546
|
-
async function produceReport(ctx, options) {
|
|
547
|
-
const toolVersion = await getToolVersion();
|
|
548
|
-
const depth0 = !options.fullTree;
|
|
549
|
-
const cwd = options.cwd || process.cwd();
|
|
550
|
-
const tree = await npmLs({
|
|
551
|
-
global: ctx === "global",
|
|
552
|
-
omitDev: ctx === "local" ? Boolean(options.omitDev) : false,
|
|
553
|
-
depth0,
|
|
554
|
-
cwd
|
|
555
|
-
});
|
|
556
|
-
let project_description;
|
|
557
|
-
let project_homepage;
|
|
558
|
-
let project_bugs;
|
|
559
|
-
if (ctx === "local") {
|
|
560
|
-
try {
|
|
561
|
-
const pkgRaw = await readFile4(path5.join(cwd, "package.json"), "utf8");
|
|
562
|
-
const pkg = JSON.parse(pkgRaw);
|
|
563
|
-
project_description = pkg.description;
|
|
564
|
-
project_homepage = pkg.homepage;
|
|
565
|
-
if (typeof pkg.bugs === "string") project_bugs = pkg.bugs;
|
|
566
|
-
else if (pkg.bugs && typeof pkg.bugs.url === "string") project_bugs = pkg.bugs.url;
|
|
567
|
-
} catch {
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
const globalRoot = ctx === "global" ? await npmRootGlobal().catch(() => void 0) : void 0;
|
|
571
|
-
const report = await buildReportFromNpmTree(tree, {
|
|
572
|
-
context: ctx,
|
|
573
|
-
includeTree: Boolean(options.fullTree),
|
|
574
|
-
omitDev: Boolean(options.omitDev),
|
|
575
|
-
cwd,
|
|
576
|
-
toolVersion,
|
|
577
|
-
globalRoot
|
|
578
32
|
});
|
|
579
|
-
const markdownExtras = { project_description, project_homepage, project_bugs };
|
|
580
|
-
return { report, markdownExtras };
|
|
581
33
|
}
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
"-u, --update-outdated [packages...]",
|
|
592
|
-
"Update outdated packages (omit package names to update every package)"
|
|
593
|
-
);
|
|
594
|
-
if (allowOmitDev) {
|
|
595
|
-
cmd.option("--omit-dev", "Exclude devDependencies (local only)", false);
|
|
34
|
+
async function run(argv = process.argv, io = {}) {
|
|
35
|
+
void argv;
|
|
36
|
+
const choice = await promptRuntimeSelection(io);
|
|
37
|
+
const output = io.output ?? process.stdout;
|
|
38
|
+
if (choice === "bun") {
|
|
39
|
+
output.write(
|
|
40
|
+
"\nYou selected the Bun runtime.\nRun `gex-bun [command] [options]` to use the Bun CLI directly.\n"
|
|
41
|
+
);
|
|
42
|
+
return;
|
|
596
43
|
}
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
const fullTree = Boolean(opts.fullTree);
|
|
606
|
-
const omitDev = Boolean(opts.omitDev);
|
|
607
|
-
const cwd = process.cwd();
|
|
608
|
-
const selection = normalizeUpdateSelection(opts.updateOutdated);
|
|
609
|
-
const result = await handleOutdatedWorkflow({
|
|
610
|
-
checkOutdated: Boolean(opts.checkOutdated),
|
|
611
|
-
selection,
|
|
612
|
-
contextLabel: "local",
|
|
613
|
-
outFile,
|
|
614
|
-
fetchOutdated: () => npmOutdated({ cwd }),
|
|
615
|
-
updateRunner: selection.shouldUpdate ? async (packages) => {
|
|
616
|
-
await npmUpdate({ cwd, packages });
|
|
617
|
-
} : void 0
|
|
618
|
-
});
|
|
619
|
-
if (opts.checkOutdated) {
|
|
620
|
-
if (result.outdated.length === 0) console.log("All local packages are up to date.");
|
|
621
|
-
else console.log(formatOutdatedTable(result.outdated));
|
|
622
|
-
}
|
|
623
|
-
if (!result.proceed) return;
|
|
624
|
-
const finalOutFile = outFile;
|
|
625
|
-
const { report, markdownExtras } = await produceReport("local", {
|
|
626
|
-
outputFormat,
|
|
627
|
-
outFile: finalOutFile,
|
|
628
|
-
fullTree,
|
|
629
|
-
omitDev
|
|
630
|
-
});
|
|
631
|
-
await outputReport(report, outputFormat, finalOutFile, markdownExtras);
|
|
632
|
-
});
|
|
633
|
-
return localCmd;
|
|
634
|
-
}
|
|
635
|
-
function createGlobalCommand(program) {
|
|
636
|
-
const globalCmd = program.command("global").description("Generate a report of globally installed packages");
|
|
637
|
-
addCommonOptions(globalCmd, { allowOmitDev: false });
|
|
638
|
-
globalCmd.action(async (opts) => {
|
|
639
|
-
const outputFormat = opts.outputFormat ?? "json";
|
|
640
|
-
const outFile = opts.outFile;
|
|
641
|
-
const fullTree = Boolean(opts.fullTree);
|
|
642
|
-
const cwd = process.cwd();
|
|
643
|
-
const selection = normalizeUpdateSelection(opts.updateOutdated);
|
|
644
|
-
const result = await handleOutdatedWorkflow({
|
|
645
|
-
checkOutdated: Boolean(opts.checkOutdated),
|
|
646
|
-
selection,
|
|
647
|
-
contextLabel: "global",
|
|
648
|
-
outFile,
|
|
649
|
-
fetchOutdated: () => npmOutdated({ cwd, global: true }),
|
|
650
|
-
updateRunner: selection.shouldUpdate ? async (packages) => {
|
|
651
|
-
await npmUpdate({ cwd, global: true, packages });
|
|
652
|
-
} : void 0
|
|
653
|
-
});
|
|
654
|
-
if (opts.checkOutdated) {
|
|
655
|
-
if (result.outdated.length === 0) console.log("All global packages are up to date.");
|
|
656
|
-
else console.log(formatOutdatedTable(result.outdated));
|
|
657
|
-
}
|
|
658
|
-
if (!result.proceed) return;
|
|
659
|
-
const finalOutFile = outFile;
|
|
660
|
-
const { report, markdownExtras } = await produceReport("global", {
|
|
661
|
-
outputFormat,
|
|
662
|
-
outFile: finalOutFile,
|
|
663
|
-
fullTree
|
|
664
|
-
});
|
|
665
|
-
await outputReport(report, outputFormat, finalOutFile, markdownExtras);
|
|
666
|
-
});
|
|
667
|
-
return globalCmd;
|
|
668
|
-
}
|
|
669
|
-
function createReadCommand(program) {
|
|
670
|
-
const readCmd = program.command("read").description(
|
|
671
|
-
"Read a previously generated report (JSON or Markdown) and either print package names or install them"
|
|
672
|
-
).argument("[report]", "Path to report file (JSON or Markdown)", "gex-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", false);
|
|
673
|
-
readCmd.action(async (reportArg, opts) => {
|
|
674
|
-
const chosen = opts.report || reportArg || "gex-report.json";
|
|
675
|
-
const reportPath = path6.resolve(process.cwd(), chosen);
|
|
676
|
-
try {
|
|
677
|
-
const parsed = await loadReportFromFile(reportPath);
|
|
678
|
-
const doInstall = Boolean(opts.install);
|
|
679
|
-
const doPrint = Boolean(opts.print) || !doInstall;
|
|
680
|
-
if (doPrint) {
|
|
681
|
-
printFromReport(parsed);
|
|
682
|
-
}
|
|
683
|
-
if (doInstall) {
|
|
684
|
-
await installFromReport(parsed, { cwd: process.cwd(), packageManager: "npm" });
|
|
685
|
-
}
|
|
686
|
-
} catch (err) {
|
|
687
|
-
const isMd = isMarkdownReportFile(reportPath);
|
|
688
|
-
const hint = isMd ? "Try generating a JSON report with: gex global -f json -o global.json, then: gex read global.json" : "Specify a report path with: gex read <path-to-report.json>";
|
|
689
|
-
console.error(`Failed to read report at ${reportPath}: ${err?.message || err}`);
|
|
690
|
-
console.error(hint);
|
|
691
|
-
process.exitCode = 1;
|
|
692
|
-
}
|
|
693
|
-
});
|
|
694
|
-
return readCmd;
|
|
695
|
-
}
|
|
696
|
-
async function createProgram() {
|
|
697
|
-
const program = new Command().name("gex").description("GEX: Dependency auditing and documentation for Node.js (local and global).").version(await getToolVersion());
|
|
698
|
-
program.addHelpText("beforeAll", `
|
|
699
|
-
${ASCII_BANNER}`);
|
|
700
|
-
createLocalCommand(program);
|
|
701
|
-
createGlobalCommand(program);
|
|
702
|
-
createReadCommand(program);
|
|
703
|
-
return program;
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
// src/runtimes/node/cli.ts
|
|
707
|
-
async function run(argv = process.argv) {
|
|
708
|
-
const program = await createProgram();
|
|
709
|
-
await program.parseAsync(argv);
|
|
44
|
+
if (choice === "npm") {
|
|
45
|
+
output.write(
|
|
46
|
+
"\nYou selected the npm/Node.js runtime.\nRun `gex-npm [command] [options]` to use the Node CLI directly.\n"
|
|
47
|
+
);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
output.write("Invalid selection. Please run `gex` again and choose 1 or 2.\n");
|
|
51
|
+
process.exitCode = 1;
|
|
710
52
|
}
|
|
711
53
|
var isMainModule = (() => {
|
|
712
54
|
try {
|
|
@@ -727,31 +69,7 @@ if (isMainModule) {
|
|
|
727
69
|
process.exitCode = 1;
|
|
728
70
|
});
|
|
729
71
|
}
|
|
730
|
-
|
|
731
|
-
// src/cli.ts
|
|
732
|
-
async function run2(argv = process.argv) {
|
|
733
|
-
return run(argv);
|
|
734
|
-
}
|
|
735
|
-
var isMainModule2 = (() => {
|
|
736
|
-
try {
|
|
737
|
-
if (typeof __require !== "undefined" && typeof module !== "undefined") {
|
|
738
|
-
return __require.main === module;
|
|
739
|
-
}
|
|
740
|
-
if (typeof import.meta !== "undefined") {
|
|
741
|
-
return import.meta.url === `file://${process.argv[1]}`;
|
|
742
|
-
}
|
|
743
|
-
return false;
|
|
744
|
-
} catch {
|
|
745
|
-
return false;
|
|
746
|
-
}
|
|
747
|
-
})();
|
|
748
|
-
if (isMainModule2) {
|
|
749
|
-
run2().catch((error) => {
|
|
750
|
-
console.error("CLI error:", error);
|
|
751
|
-
process.exitCode = 1;
|
|
752
|
-
});
|
|
753
|
-
}
|
|
754
72
|
export {
|
|
755
|
-
|
|
73
|
+
run
|
|
756
74
|
};
|
|
757
75
|
//# sourceMappingURL=cli.mjs.map
|