@yabasha/gex 0.3.2 → 0.4.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.mjs CHANGED
@@ -6,24 +6,215 @@ 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/cli.ts
10
- import { readFile as readFile2 } from "fs/promises";
11
- import path2 from "path";
12
- import { fileURLToPath } from "url";
13
- import { execFile as execFile2 } from "child_process";
14
- import { promisify as promisify2 } from "util";
9
+ // src/cli/commands.ts
10
+ import path6 from "path";
15
11
  import { Command } from "commander";
16
12
 
13
+ // src/cli/install.ts
14
+ async function getExecFileAsync() {
15
+ const { execFile } = await import("child_process");
16
+ const { promisify } = await import("util");
17
+ return promisify(execFile);
18
+ }
19
+ async function installFromReport(report, cwd) {
20
+ const globalPkgs = report.global_packages.map((p) => `${p.name}@${p.version}`).filter(Boolean);
21
+ const localPkgs = report.local_dependencies.map((p) => `${p.name}@${p.version}`).filter(Boolean);
22
+ const devPkgs = report.local_dev_dependencies.map((p) => `${p.name}@${p.version}`).filter(Boolean);
23
+ if (globalPkgs.length === 0 && localPkgs.length === 0 && devPkgs.length === 0) {
24
+ console.log("No packages to install from report.");
25
+ return;
26
+ }
27
+ const execFileAsync = await getExecFileAsync();
28
+ if (globalPkgs.length > 0) {
29
+ console.log(`Installing global: ${globalPkgs.join(" ")}`);
30
+ await execFileAsync("npm", ["i", "-g", ...globalPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 });
31
+ }
32
+ if (localPkgs.length > 0) {
33
+ console.log(`Installing local deps: ${localPkgs.join(" ")}`);
34
+ await execFileAsync("npm", ["i", ...localPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 });
35
+ }
36
+ if (devPkgs.length > 0) {
37
+ console.log(`Installing local devDeps: ${devPkgs.join(" ")}`);
38
+ await execFileAsync("npm", ["i", "-D", ...devPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 });
39
+ }
40
+ }
41
+ function printFromReport(report) {
42
+ const lines = [];
43
+ if (report.global_packages.length > 0) {
44
+ lines.push("Global Packages:");
45
+ for (const p of report.global_packages) {
46
+ lines.push(`- ${p.name}@${p.version}`);
47
+ }
48
+ }
49
+ if (report.local_dependencies.length > 0) {
50
+ if (lines.length) lines.push("");
51
+ lines.push("Local Dependencies:");
52
+ for (const p of report.local_dependencies) {
53
+ lines.push(`- ${p.name}@${p.version}`);
54
+ }
55
+ }
56
+ if (report.local_dev_dependencies.length > 0) {
57
+ if (lines.length) lines.push("");
58
+ lines.push("Local Dev Dependencies:");
59
+ for (const p of report.local_dev_dependencies) {
60
+ lines.push(`- ${p.name}@${p.version}`);
61
+ }
62
+ }
63
+ if (lines.length === 0) {
64
+ lines.push("(no packages found in report)");
65
+ }
66
+ console.log(lines.join("\n"));
67
+ }
68
+
69
+ // src/cli/output.ts
70
+ import path from "path";
71
+
72
+ // src/report/json.ts
73
+ function renderJson(report) {
74
+ const r = {
75
+ ...report,
76
+ global_packages: [...report.global_packages].sort((a, b) => a.name.localeCompare(b.name)),
77
+ local_dependencies: [...report.local_dependencies].sort((a, b) => a.name.localeCompare(b.name)),
78
+ local_dev_dependencies: [...report.local_dev_dependencies].sort(
79
+ (a, b) => a.name.localeCompare(b.name)
80
+ )
81
+ };
82
+ return JSON.stringify(r, null, 2);
83
+ }
84
+
85
+ // src/report/md.ts
86
+ function table(headers, rows) {
87
+ const header = `| ${headers.join(" | ")} |`;
88
+ const sep = `| ${headers.map(() => "---").join(" | ")} |`;
89
+ const body = rows.map((r) => `| ${r.join(" | ")} |`).join("\n");
90
+ return [header, sep, body].filter(Boolean).join("\n");
91
+ }
92
+ function renderMarkdown(report) {
93
+ const lines = [];
94
+ lines.push("# GEX Report");
95
+ lines.push("");
96
+ if (report.project_name || report.project_version || report.project_description || report.project_homepage || report.project_bugs) {
97
+ lines.push("## Project Metadata");
98
+ if (report.project_name) lines.push(`- Name: ${report.project_name}`);
99
+ if (report.project_version) lines.push(`- Version: ${report.project_version}`);
100
+ if (report.project_description)
101
+ lines.push(`- Description: ${report.project_description}`);
102
+ if (report.project_homepage)
103
+ lines.push(`- Homepage: ${report.project_homepage}`);
104
+ if (report.project_bugs) lines.push(`- Bugs: ${report.project_bugs}`);
105
+ lines.push("");
106
+ }
107
+ if (report.global_packages.length > 0) {
108
+ lines.push("## Global Packages");
109
+ const rows = report.global_packages.map((p) => [p.name, p.version || "", p.resolved_path || ""]);
110
+ lines.push(table(["Name", "Version", "Path"], rows));
111
+ lines.push("");
112
+ }
113
+ if (report.local_dependencies.length > 0) {
114
+ lines.push("## Local Dependencies");
115
+ const rows = report.local_dependencies.map((p) => [
116
+ p.name,
117
+ p.version || "",
118
+ p.resolved_path || ""
119
+ ]);
120
+ lines.push(table(["Name", "Version", "Path"], rows));
121
+ lines.push("");
122
+ }
123
+ if (report.local_dev_dependencies.length > 0) {
124
+ lines.push("## Local Dev Dependencies");
125
+ const rows = report.local_dev_dependencies.map((p) => [
126
+ p.name,
127
+ p.version || "",
128
+ p.resolved_path || ""
129
+ ]);
130
+ lines.push(table(["Name", "Version", "Path"], rows));
131
+ lines.push("");
132
+ }
133
+ lines.push("---");
134
+ lines.push("_Generated by GEX_");
135
+ return lines.join("\n");
136
+ }
137
+
138
+ // src/cli/output.ts
139
+ async function outputReport(report, format, outFile, markdownExtras) {
140
+ const content = format === "json" ? renderJson(report) : renderMarkdown({ ...report, ...markdownExtras || {} });
141
+ if (outFile) {
142
+ const outDir = path.dirname(outFile);
143
+ const { mkdir, writeFile } = await import("fs/promises");
144
+ await mkdir(outDir, { recursive: true });
145
+ await writeFile(outFile, content, "utf8");
146
+ console.log(`Wrote report to ${outFile}`);
147
+ } else {
148
+ console.log(content);
149
+ }
150
+ }
151
+
152
+ // src/cli/parser.ts
153
+ import { readFile } from "fs/promises";
154
+ import path2 from "path";
155
+ function isMarkdownReportFile(filePath) {
156
+ const ext = path2.extname(filePath).toLowerCase();
157
+ return ext === ".md" || ext === ".markdown";
158
+ }
159
+ function parseMarkdownPackagesTable(lines, startIndex) {
160
+ const rows = [];
161
+ if (!lines[startIndex] || !lines[startIndex].trim().startsWith("|")) return rows;
162
+ let i = startIndex + 2;
163
+ while (i < lines.length && lines[i].trim().startsWith("|")) {
164
+ const cols = lines[i].split("|").map((c) => c.trim()).filter((_, idx, arr) => !(idx === 0 || idx === arr.length - 1));
165
+ const [name = "", version = "", resolved_path = ""] = cols;
166
+ if (name) rows.push({ name, version, resolved_path });
167
+ i++;
168
+ }
169
+ return rows;
170
+ }
171
+ function parseMarkdownReport(md) {
172
+ const lines = md.split(/\r?\n/);
173
+ const findSection = (title) => lines.findIndex((l) => l.trim().toLowerCase() === `## ${title}`.toLowerCase());
174
+ const parseSection = (idx) => {
175
+ if (idx < 0) return [];
176
+ let i = idx + 1;
177
+ while (i < lines.length && !lines[i].trim().startsWith("|")) i++;
178
+ return parseMarkdownPackagesTable(lines, i);
179
+ };
180
+ const global_packages = parseSection(findSection("Global Packages"));
181
+ const local_dependencies = parseSection(findSection("Local Dependencies"));
182
+ const local_dev_dependencies = parseSection(findSection("Local Dev Dependencies"));
183
+ const report = {
184
+ report_version: "1.0",
185
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
186
+ tool_version: "unknown",
187
+ global_packages,
188
+ local_dependencies,
189
+ local_dev_dependencies
190
+ };
191
+ return report;
192
+ }
193
+ async function loadReportFromFile(reportPath) {
194
+ const raw = await readFile(reportPath, "utf8");
195
+ if (isMarkdownReportFile(reportPath) || raw.startsWith("# GEX Report")) {
196
+ return parseMarkdownReport(raw);
197
+ }
198
+ return JSON.parse(raw);
199
+ }
200
+
201
+ // src/cli/report.ts
202
+ import { readFile as readFile4 } from "fs/promises";
203
+ import path5 from "path";
204
+
17
205
  // src/npm.ts
18
- import { execFile } from "child_process";
19
- import { promisify } from "util";
20
- var execFileAsync = promisify(execFile);
206
+ async function getExecFileAsync2() {
207
+ const { execFile } = await import("child_process");
208
+ const { promisify } = await import("util");
209
+ return promisify(execFile);
210
+ }
21
211
  async function npmLs(options = {}) {
22
212
  const args = ["ls", "--json"];
23
213
  if (options.global) args.push("--global");
24
214
  if (options.omitDev) args.push("--omit=dev");
25
215
  if (options.depth0) args.push("--depth=0");
26
216
  try {
217
+ const execFileAsync = await getExecFileAsync2();
27
218
  const { stdout } = await execFileAsync("npm", args, {
28
219
  cwd: options.cwd,
29
220
  maxBuffer: 10 * 1024 * 1024
@@ -35,7 +226,10 @@ async function npmLs(options = {}) {
35
226
  if (typeof stdout === "string" && stdout.trim()) {
36
227
  try {
37
228
  return JSON.parse(stdout);
38
- } catch {
229
+ } catch (parseErr) {
230
+ if (process.env.DEBUG?.includes("gex")) {
231
+ console.warn("npm ls stdout parse failed:", parseErr);
232
+ }
39
233
  }
40
234
  }
41
235
  const stderr = err?.stderr;
@@ -45,6 +239,7 @@ async function npmLs(options = {}) {
45
239
  }
46
240
  async function npmRootGlobal() {
47
241
  try {
242
+ const execFileAsync = await getExecFileAsync2();
48
243
  const { stdout } = await execFileAsync("npm", ["root", "-g"]);
49
244
  return stdout.trim();
50
245
  } catch (err) {
@@ -55,8 +250,8 @@ async function npmRootGlobal() {
55
250
  }
56
251
 
57
252
  // src/transform.ts
58
- import path from "path";
59
- import { readFile } from "fs/promises";
253
+ import path3 from "path";
254
+ import { readFile as readFile2 } from "fs/promises";
60
255
  function toPkgArray(obj) {
61
256
  if (!obj) return [];
62
257
  return Object.keys(obj).map((name) => ({ name, node: obj[name] })).filter((p) => p && p.node);
@@ -74,8 +269,8 @@ async function buildReportFromNpmTree(tree, opts) {
74
269
  if (opts.context === "local") {
75
270
  let pkgMeta = null;
76
271
  try {
77
- const pkgJsonPath = path.join(opts.cwd || process.cwd(), "package.json");
78
- const raw = await readFile(pkgJsonPath, "utf8");
272
+ const pkgJsonPath = path3.join(opts.cwd || process.cwd(), "package.json");
273
+ const raw = await readFile2(pkgJsonPath, "utf8");
79
274
  pkgMeta = JSON.parse(raw);
80
275
  } catch {
81
276
  }
@@ -86,7 +281,7 @@ async function buildReportFromNpmTree(tree, opts) {
86
281
  const devKeys = new Set(Object.keys(pkgMeta?.devDependencies || {}));
87
282
  for (const { name, node } of items) {
88
283
  const version = node && node.version || "";
89
- const resolvedPath = node && node.path || path.join(opts.cwd || process.cwd(), "node_modules", name);
284
+ const resolvedPath = node && node.path || path3.join(opts.cwd || process.cwd(), "node_modules", name);
90
285
  const pkg = { name, version, resolved_path: resolvedPath };
91
286
  if (devKeys.has(name)) {
92
287
  report.local_dev_dependencies.push(pkg);
@@ -101,7 +296,7 @@ async function buildReportFromNpmTree(tree, opts) {
101
296
  const items = toPkgArray(depsObj);
102
297
  for (const { name, node } of items) {
103
298
  const version = node && node.version || "";
104
- const resolvedPath = node && node.path || path.join(opts.globalRoot || "", name);
299
+ const resolvedPath = node && node.path || path3.join(opts.globalRoot || "", name);
105
300
  const pkg = { name, version, resolved_path: resolvedPath };
106
301
  report.global_packages.push(pkg);
107
302
  }
@@ -113,103 +308,41 @@ async function buildReportFromNpmTree(tree, opts) {
113
308
  return report;
114
309
  }
115
310
 
116
- // src/report/json.ts
117
- function renderJson(report) {
118
- const r = {
119
- ...report,
120
- global_packages: [...report.global_packages].sort((a, b) => a.name.localeCompare(b.name)),
121
- local_dependencies: [...report.local_dependencies].sort((a, b) => a.name.localeCompare(b.name)),
122
- local_dev_dependencies: [...report.local_dev_dependencies].sort(
123
- (a, b) => a.name.localeCompare(b.name)
124
- )
125
- };
126
- return JSON.stringify(r, null, 2);
127
- }
128
-
129
- // src/report/md.ts
130
- function table(headers, rows) {
131
- const header = `| ${headers.join(" | ")} |`;
132
- const sep = `| ${headers.map(() => "---").join(" | ")} |`;
133
- const body = rows.map((r) => `| ${r.join(" | ")} |`).join("\n");
134
- return [header, sep, body].filter(Boolean).join("\n");
135
- }
136
- function renderMarkdown(report) {
137
- const lines = [];
138
- lines.push("# GEX Report");
139
- lines.push("");
140
- if (report.project_name || report.project_version) {
141
- lines.push("## Project Metadata");
142
- if (report.project_name) lines.push(`- Name: ${report.project_name}`);
143
- if (report.project_version) lines.push(`- Version: ${report.project_version}`);
144
- if (report.project_description)
145
- lines.push(`- Description: ${report.project_description}`);
146
- if (report.project_homepage)
147
- lines.push(`- Homepage: ${report.project_homepage}`);
148
- if (report.project_bugs) lines.push(`- Bugs: ${report.project_bugs}`);
149
- lines.push("");
150
- }
151
- if (report.global_packages.length > 0) {
152
- lines.push("## Global Packages");
153
- const rows = report.global_packages.map((p) => [p.name, p.version || "", p.resolved_path || ""]);
154
- lines.push(table(["Name", "Version", "Path"], rows));
155
- lines.push("");
156
- }
157
- if (report.local_dependencies.length > 0) {
158
- lines.push("## Local Dependencies");
159
- const rows = report.local_dependencies.map((p) => [
160
- p.name,
161
- p.version || "",
162
- p.resolved_path || ""
163
- ]);
164
- lines.push(table(["Name", "Version", "Path"], rows));
165
- lines.push("");
166
- }
167
- if (report.local_dev_dependencies.length > 0) {
168
- lines.push("## Local Dev Dependencies");
169
- const rows = report.local_dev_dependencies.map((p) => [
170
- p.name,
171
- p.version || "",
172
- p.resolved_path || ""
173
- ]);
174
- lines.push(table(["Name", "Version", "Path"], rows));
175
- lines.push("");
176
- }
177
- lines.push("---");
178
- lines.push("_Generated by GEX_");
179
- return lines.join("\n");
180
- }
181
-
182
- // src/cli.ts
311
+ // src/cli/utils.ts
312
+ import { readFile as readFile3 } from "fs/promises";
313
+ import path4 from "path";
314
+ import { fileURLToPath } from "url";
183
315
  function getPkgJsonPath() {
184
316
  try {
185
317
  const __filename = fileURLToPath(import.meta.url);
186
- const __dirnameLocal = path2.dirname(__filename);
187
- return path2.resolve(__dirnameLocal, "..", "package.json");
318
+ const __dirnameLocal = path4.dirname(__filename);
319
+ return path4.resolve(__dirnameLocal, "..", "..", "package.json");
188
320
  } catch {
189
321
  const dir = typeof __dirname !== "undefined" ? __dirname : process.cwd();
190
- return path2.resolve(dir, "..", "package.json");
322
+ return path4.resolve(dir, "..", "package.json");
191
323
  }
192
324
  }
193
325
  async function getToolVersion() {
194
326
  try {
195
327
  const pkgPath = getPkgJsonPath();
196
- const raw = await readFile2(pkgPath, "utf8");
328
+ const raw = await readFile3(pkgPath, "utf8");
197
329
  const pkg = JSON.parse(raw);
198
330
  return pkg.version || "0.0.0";
199
331
  } catch {
200
332
  return "0.0.0";
201
333
  }
202
334
  }
203
- var execFileAsync2 = promisify2(execFile2);
204
335
  var ASCII_BANNER = String.raw`
205
336
  ________ __
206
- / _____/ ____ _____/ |_ ____ ____
337
+ / _____/ ____ _____/ |_ ____ ____
207
338
  / \ ___ / _ \ / _ \ __\/ __ \ / \
208
339
  \ \_\ ( <_> | <_> ) | \ ___/| | \
209
340
  \______ /\____/ \____/|__| \___ >___| /
210
- \/ \/ \/
341
+ \/ \/ \/
211
342
  GEX
212
343
  `;
344
+
345
+ // src/cli/report.ts
213
346
  async function produceReport(ctx, options) {
214
347
  const toolVersion = await getToolVersion();
215
348
  const depth0 = !options.fullTree;
@@ -225,7 +358,7 @@ async function produceReport(ctx, options) {
225
358
  let project_bugs;
226
359
  if (ctx === "local") {
227
360
  try {
228
- const pkgRaw = await readFile2(path2.join(cwd, "package.json"), "utf8");
361
+ const pkgRaw = await readFile4(path5.join(cwd, "package.json"), "utf8");
229
362
  const pkg = JSON.parse(pkgRaw);
230
363
  project_description = pkg.description;
231
364
  project_homepage = pkg.homepage;
@@ -246,126 +379,21 @@ async function produceReport(ctx, options) {
246
379
  const markdownExtras = { project_description, project_homepage, project_bugs };
247
380
  return { report, markdownExtras };
248
381
  }
249
- function printFromReport(report) {
250
- const lines = [];
251
- if (report.global_packages.length > 0) {
252
- lines.push("Global Packages:");
253
- for (const p of report.global_packages) {
254
- lines.push(`- ${p.name}@${p.version}`);
255
- }
256
- }
257
- if (report.local_dependencies.length > 0) {
258
- if (lines.length) lines.push("");
259
- lines.push("Local Dependencies:");
260
- for (const p of report.local_dependencies) {
261
- lines.push(`- ${p.name}@${p.version}`);
262
- }
263
- }
264
- if (report.local_dev_dependencies.length > 0) {
265
- if (lines.length) lines.push("");
266
- lines.push("Local Dev Dependencies:");
267
- for (const p of report.local_dev_dependencies) {
268
- lines.push(`- ${p.name}@${p.version}`);
269
- }
270
- }
271
- if (lines.length === 0) {
272
- lines.push("(no packages found in report)");
273
- }
274
- console.log(lines.join("\n"));
275
- }
276
- async function installFromReport(report, cwd) {
277
- const globalPkgs = report.global_packages.map((p) => `${p.name}@${p.version}`).filter(Boolean);
278
- const localPkgs = report.local_dependencies.map((p) => `${p.name}@${p.version}`).filter(Boolean);
279
- const devPkgs = report.local_dev_dependencies.map((p) => `${p.name}@${p.version}`).filter(Boolean);
280
- if (globalPkgs.length === 0 && localPkgs.length === 0 && devPkgs.length === 0) {
281
- console.log("No packages to install from report.");
282
- return;
283
- }
284
- if (globalPkgs.length > 0) {
285
- console.log(`Installing global: ${globalPkgs.join(" ")}`);
286
- await execFileAsync2("npm", ["i", "-g", ...globalPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 });
287
- }
288
- if (localPkgs.length > 0) {
289
- console.log(`Installing local deps: ${localPkgs.join(" ")}`);
290
- await execFileAsync2("npm", ["i", ...localPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 });
291
- }
292
- if (devPkgs.length > 0) {
293
- console.log(`Installing local devDeps: ${devPkgs.join(" ")}`);
294
- await execFileAsync2("npm", ["i", "-D", ...devPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 });
295
- }
296
- }
297
- async function outputReport(report, format, outFile, markdownExtras) {
298
- const content = format === "json" ? renderJson(report) : renderMarkdown({ ...report, ...markdownExtras || {} });
299
- if (outFile) {
300
- const outDir = path2.dirname(outFile);
301
- await (await import("fs/promises")).mkdir(outDir, { recursive: true });
302
- await (await import("fs/promises")).writeFile(outFile, content, "utf8");
303
- console.log(`Wrote report to ${outFile}`);
304
- } else {
305
- console.log(content);
306
- }
307
- }
308
- function isMarkdownReportFile(filePath) {
309
- const ext = path2.extname(filePath).toLowerCase();
310
- return ext === ".md" || ext === ".markdown";
311
- }
312
- function parseMarkdownPackagesTable(lines, startIndex) {
313
- const rows = [];
314
- if (!lines[startIndex] || !lines[startIndex].trim().startsWith("|")) return rows;
315
- let i = startIndex + 2;
316
- while (i < lines.length && lines[i].trim().startsWith("|")) {
317
- const cols = lines[i].split("|").map((c) => c.trim()).filter((_, idx, arr) => !(idx === 0 || idx === arr.length - 1));
318
- const [name = "", version = "", resolved_path = ""] = cols;
319
- if (name) rows.push({ name, version, resolved_path });
320
- i++;
321
- }
322
- return rows;
323
- }
324
- function parseMarkdownReport(md) {
325
- const lines = md.split(/\r?\n/);
326
- const findSection = (title) => lines.findIndex((l) => l.trim().toLowerCase() === `## ${title}`.toLowerCase());
327
- const parseSection = (idx) => {
328
- if (idx < 0) return [];
329
- let i = idx + 1;
330
- while (i < lines.length && !lines[i].trim().startsWith("|")) i++;
331
- return parseMarkdownPackagesTable(lines, i);
332
- };
333
- const global_packages = parseSection(findSection("Global Packages"));
334
- const local_dependencies = parseSection(findSection("Local Dependencies"));
335
- const local_dev_dependencies = parseSection(findSection("Local Dev Dependencies"));
336
- const report = {
337
- report_version: "1.0",
338
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
339
- tool_version: "unknown",
340
- global_packages,
341
- local_dependencies,
342
- local_dev_dependencies
343
- };
344
- return report;
345
- }
346
- async function loadReportFromFile(reportPath) {
347
- const raw = await readFile2(reportPath, "utf8");
348
- if (isMarkdownReportFile(reportPath) || raw.startsWith("# GEX Report")) {
349
- return parseMarkdownReport(raw);
382
+
383
+ // src/cli/commands.ts
384
+ function addCommonOptions(cmd, { allowOmitDev }) {
385
+ cmd.option(
386
+ "-f, --output-format <format>",
387
+ "Output format: md or json",
388
+ (val) => val === "md" ? "md" : "json",
389
+ "json"
390
+ ).option("-o, --out-file <path>", "Write report to file").option("--full-tree", "Include full npm ls tree (omit depth=0 default)", false);
391
+ if (allowOmitDev) {
392
+ cmd.option("--omit-dev", "Exclude devDependencies (local only)", false);
350
393
  }
351
- return JSON.parse(raw);
394
+ return cmd;
352
395
  }
353
- async function run(argv = process.argv) {
354
- const program = new Command().name("gex").description("GEX: Dependency auditing and documentation for Node.js (local and global).").version(await getToolVersion());
355
- program.addHelpText("beforeAll", `
356
- ${ASCII_BANNER}`);
357
- const addCommonOptions = (cmd, { allowOmitDev }) => {
358
- cmd.option(
359
- "-f, --output-format <format>",
360
- "Output format: md or json",
361
- (val) => val === "md" ? "md" : "json",
362
- "json"
363
- ).option("-o, --out-file <path>", "Write report to file").option("--full-tree", "Include full npm ls tree (omit depth=0 default)", false);
364
- if (allowOmitDev) {
365
- cmd.option("--omit-dev", "Exclude devDependencies (local only)", false);
366
- }
367
- return cmd;
368
- };
396
+ function createLocalCommand(program) {
369
397
  const localCmd = program.command("local", { isDefault: true }).description("Generate a report for the current project's dependencies");
370
398
  addCommonOptions(localCmd, { allowOmitDev: true });
371
399
  localCmd.action(async (opts) => {
@@ -373,10 +401,7 @@ ${ASCII_BANNER}`);
373
401
  const outFile = opts.outFile;
374
402
  const fullTree = Boolean(opts.fullTree);
375
403
  const omitDev = Boolean(opts.omitDev);
376
- let finalOutFile = outFile;
377
- if (!outFile && opts.outputFormat && typeof opts.outputFormat === "string") {
378
- finalOutFile = `gex-report.${outputFormat}`;
379
- }
404
+ const finalOutFile = outFile;
380
405
  const { report, markdownExtras } = await produceReport("local", {
381
406
  outputFormat,
382
407
  outFile: finalOutFile,
@@ -385,16 +410,16 @@ ${ASCII_BANNER}`);
385
410
  });
386
411
  await outputReport(report, outputFormat, finalOutFile, markdownExtras);
387
412
  });
413
+ return localCmd;
414
+ }
415
+ function createGlobalCommand(program) {
388
416
  const globalCmd = program.command("global").description("Generate a report of globally installed packages");
389
417
  addCommonOptions(globalCmd, { allowOmitDev: false });
390
418
  globalCmd.action(async (opts) => {
391
419
  const outputFormat = opts.outputFormat ?? "json";
392
420
  const outFile = opts.outFile;
393
421
  const fullTree = Boolean(opts.fullTree);
394
- let finalOutFile = outFile;
395
- if (!outFile && opts.outputFormat && typeof opts.outputFormat === "string") {
396
- finalOutFile = `gex-report.${outputFormat}`;
397
- }
422
+ const finalOutFile = outFile;
398
423
  const { report, markdownExtras } = await produceReport("global", {
399
424
  outputFormat,
400
425
  outFile: finalOutFile,
@@ -402,12 +427,15 @@ ${ASCII_BANNER}`);
402
427
  });
403
428
  await outputReport(report, outputFormat, finalOutFile, markdownExtras);
404
429
  });
430
+ return globalCmd;
431
+ }
432
+ function createReadCommand(program) {
405
433
  const readCmd = program.command("read").description(
406
434
  "Read a previously generated report (JSON or Markdown) and either print package names or install them"
407
435
  ).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);
408
436
  readCmd.action(async (reportArg, opts) => {
409
437
  const chosen = opts.report || reportArg || "gex-report.json";
410
- const reportPath = path2.resolve(process.cwd(), chosen);
438
+ const reportPath = path6.resolve(process.cwd(), chosen);
411
439
  try {
412
440
  const parsed = await loadReportFromFile(reportPath);
413
441
  const doInstall = Boolean(opts.install);
@@ -426,12 +454,41 @@ ${ASCII_BANNER}`);
426
454
  process.exitCode = 1;
427
455
  }
428
456
  });
457
+ return readCmd;
458
+ }
459
+ async function createProgram() {
460
+ const program = new Command().name("gex").description("GEX: Dependency auditing and documentation for Node.js (local and global).").version(await getToolVersion());
461
+ program.addHelpText("beforeAll", `
462
+ ${ASCII_BANNER}`);
463
+ createLocalCommand(program);
464
+ createGlobalCommand(program);
465
+ createReadCommand(program);
466
+ return program;
467
+ }
468
+
469
+ // src/cli.ts
470
+ async function run(argv = process.argv) {
471
+ const program = await createProgram();
429
472
  await program.parseAsync(argv);
430
473
  }
431
- var isCjsMain = typeof __require !== "undefined" && __require.main === module;
432
- var isEsmMain = typeof import.meta !== "undefined" && import.meta.url === `file://${process.argv[1]}`;
433
- if (isCjsMain || isEsmMain) {
434
- run();
474
+ var isMainModule = (() => {
475
+ try {
476
+ if (typeof __require !== "undefined" && typeof module !== "undefined") {
477
+ return __require.main === module;
478
+ }
479
+ if (typeof import.meta !== "undefined") {
480
+ return import.meta.url === `file://${process.argv[1]}`;
481
+ }
482
+ return false;
483
+ } catch {
484
+ return false;
485
+ }
486
+ })();
487
+ if (isMainModule) {
488
+ run().catch((error) => {
489
+ console.error("CLI error:", error);
490
+ process.exitCode = 1;
491
+ });
435
492
  }
436
493
  export {
437
494
  run