@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/README.md +16 -5
- package/dist/cli.cjs +281 -221
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +279 -222
- package/dist/cli.mjs.map +1 -1
- package/dist/index.cjs +410 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +189 -4
- package/dist/index.d.ts +189 -4
- package/dist/index.mjs +393 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -1
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
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
|
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 =
|
|
78
|
-
const raw = await
|
|
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 ||
|
|
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 ||
|
|
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/
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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 =
|
|
187
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
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
|
|
394
|
+
return cmd;
|
|
352
395
|
}
|
|
353
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
|
432
|
-
|
|
433
|
-
if (
|
|
434
|
-
|
|
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
|