@yabasha/gex 0.3.1 → 0.3.3

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/index.mjs CHANGED
@@ -1,8 +1,398 @@
1
1
  // src/index.ts
2
- function greet(name) {
3
- return `Hello, ${name}!`;
2
+ import { readFile as readFile2 } from "fs/promises";
3
+ import { execFile } from "child_process";
4
+ import { promisify } from "util";
5
+ import path3 from "path";
6
+
7
+ // src/npm.ts
8
+ async function getExecFileAsync() {
9
+ const { execFile: execFile2 } = await import("child_process");
10
+ const { promisify: promisify2 } = await import("util");
11
+ return promisify2(execFile2);
12
+ }
13
+ async function npmLs(options = {}) {
14
+ const args = ["ls", "--json"];
15
+ if (options.global) args.push("--global");
16
+ if (options.omitDev) args.push("--omit=dev");
17
+ if (options.depth0) args.push("--depth=0");
18
+ try {
19
+ const execFileAsync2 = await getExecFileAsync();
20
+ const { stdout } = await execFileAsync2("npm", args, {
21
+ cwd: options.cwd,
22
+ maxBuffer: 10 * 1024 * 1024
23
+ });
24
+ if (stdout && stdout.trim()) return JSON.parse(stdout);
25
+ return {};
26
+ } catch (err) {
27
+ const stdout = err?.stdout;
28
+ if (typeof stdout === "string" && stdout.trim()) {
29
+ try {
30
+ return JSON.parse(stdout);
31
+ } catch (parseErr) {
32
+ if (process.env.DEBUG?.includes("gex")) {
33
+ console.warn("npm ls stdout parse failed:", parseErr);
34
+ }
35
+ }
36
+ }
37
+ const stderr = err?.stderr;
38
+ const msg = typeof stderr === "string" && stderr.trim() || err?.message || "npm ls failed";
39
+ throw new Error(`npm ls failed: ${msg}`);
40
+ }
41
+ }
42
+ async function npmRootGlobal() {
43
+ try {
44
+ const execFileAsync2 = await getExecFileAsync();
45
+ const { stdout } = await execFileAsync2("npm", ["root", "-g"]);
46
+ return stdout.trim();
47
+ } catch (err) {
48
+ const stderr = err?.stderr;
49
+ const msg = typeof stderr === "string" && stderr.trim() || err?.message || "npm root -g failed";
50
+ throw new Error(`npm root -g failed: ${msg}`);
51
+ }
52
+ }
53
+
54
+ // src/transform.ts
55
+ import path from "path";
56
+ import { readFile } from "fs/promises";
57
+ function toPkgArray(obj) {
58
+ if (!obj) return [];
59
+ return Object.keys(obj).map((name) => ({ name, node: obj[name] })).filter((p) => p && p.node);
60
+ }
61
+ async function buildReportFromNpmTree(tree, opts) {
62
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
63
+ const report = {
64
+ report_version: "1.0",
65
+ timestamp,
66
+ tool_version: opts.toolVersion,
67
+ global_packages: [],
68
+ local_dependencies: [],
69
+ local_dev_dependencies: []
70
+ };
71
+ if (opts.context === "local") {
72
+ let pkgMeta = null;
73
+ try {
74
+ const pkgJsonPath = path.join(opts.cwd || process.cwd(), "package.json");
75
+ const raw = await readFile(pkgJsonPath, "utf8");
76
+ pkgMeta = JSON.parse(raw);
77
+ } catch {
78
+ }
79
+ if (pkgMeta?.name) report.project_name = pkgMeta.name;
80
+ if (pkgMeta?.version) report.project_version = pkgMeta.version;
81
+ const depsObj = tree?.dependencies;
82
+ const items = toPkgArray(depsObj);
83
+ const devKeys = new Set(Object.keys(pkgMeta?.devDependencies || {}));
84
+ for (const { name, node } of items) {
85
+ const version = node && node.version || "";
86
+ const resolvedPath = node && node.path || path.join(opts.cwd || process.cwd(), "node_modules", name);
87
+ const pkg = { name, version, resolved_path: resolvedPath };
88
+ if (devKeys.has(name)) {
89
+ report.local_dev_dependencies.push(pkg);
90
+ } else {
91
+ report.local_dependencies.push(pkg);
92
+ }
93
+ }
94
+ report.local_dependencies.sort((a, b) => a.name.localeCompare(b.name));
95
+ report.local_dev_dependencies.sort((a, b) => a.name.localeCompare(b.name));
96
+ } else if (opts.context === "global") {
97
+ const depsObj = tree?.dependencies;
98
+ const items = toPkgArray(depsObj);
99
+ for (const { name, node } of items) {
100
+ const version = node && node.version || "";
101
+ const resolvedPath = node && node.path || path.join(opts.globalRoot || "", name);
102
+ const pkg = { name, version, resolved_path: resolvedPath };
103
+ report.global_packages.push(pkg);
104
+ }
105
+ report.global_packages.sort((a, b) => a.name.localeCompare(b.name));
106
+ }
107
+ if (opts.includeTree) {
108
+ report.tree = tree;
109
+ }
110
+ return report;
111
+ }
112
+
113
+ // src/report/json.ts
114
+ function renderJson(report) {
115
+ const r = {
116
+ ...report,
117
+ global_packages: [...report.global_packages].sort((a, b) => a.name.localeCompare(b.name)),
118
+ local_dependencies: [...report.local_dependencies].sort((a, b) => a.name.localeCompare(b.name)),
119
+ local_dev_dependencies: [...report.local_dev_dependencies].sort(
120
+ (a, b) => a.name.localeCompare(b.name)
121
+ )
122
+ };
123
+ return JSON.stringify(r, null, 2);
124
+ }
125
+
126
+ // src/report/md.ts
127
+ function table(headers, rows) {
128
+ const header = `| ${headers.join(" | ")} |`;
129
+ const sep = `| ${headers.map(() => "---").join(" | ")} |`;
130
+ const body = rows.map((r) => `| ${r.join(" | ")} |`).join("\n");
131
+ return [header, sep, body].filter(Boolean).join("\n");
132
+ }
133
+ function renderMarkdown(report) {
134
+ const lines = [];
135
+ lines.push("# GEX Report");
136
+ lines.push("");
137
+ if (report.project_name || report.project_version || report.project_description || report.project_homepage || report.project_bugs) {
138
+ lines.push("## Project Metadata");
139
+ if (report.project_name) lines.push(`- Name: ${report.project_name}`);
140
+ if (report.project_version) lines.push(`- Version: ${report.project_version}`);
141
+ if (report.project_description)
142
+ lines.push(`- Description: ${report.project_description}`);
143
+ if (report.project_homepage)
144
+ lines.push(`- Homepage: ${report.project_homepage}`);
145
+ if (report.project_bugs) lines.push(`- Bugs: ${report.project_bugs}`);
146
+ lines.push("");
147
+ }
148
+ if (report.global_packages.length > 0) {
149
+ lines.push("## Global Packages");
150
+ const rows = report.global_packages.map((p) => [p.name, p.version || "", p.resolved_path || ""]);
151
+ lines.push(table(["Name", "Version", "Path"], rows));
152
+ lines.push("");
153
+ }
154
+ if (report.local_dependencies.length > 0) {
155
+ lines.push("## Local Dependencies");
156
+ const rows = report.local_dependencies.map((p) => [
157
+ p.name,
158
+ p.version || "",
159
+ p.resolved_path || ""
160
+ ]);
161
+ lines.push(table(["Name", "Version", "Path"], rows));
162
+ lines.push("");
163
+ }
164
+ if (report.local_dev_dependencies.length > 0) {
165
+ lines.push("## Local Dev Dependencies");
166
+ const rows = report.local_dev_dependencies.map((p) => [
167
+ p.name,
168
+ p.version || "",
169
+ p.resolved_path || ""
170
+ ]);
171
+ lines.push(table(["Name", "Version", "Path"], rows));
172
+ lines.push("");
173
+ }
174
+ lines.push("---");
175
+ lines.push("_Generated by GEX_");
176
+ return lines.join("\n");
177
+ }
178
+
179
+ // src/validators.ts
180
+ import path2 from "path";
181
+ import { setTimeout } from "timers";
182
+ var ValidationError = class extends Error {
183
+ constructor(message) {
184
+ super(message);
185
+ this.name = "ValidationError";
186
+ }
187
+ };
188
+ function validateFilePath(filePath) {
189
+ if (!filePath || typeof filePath !== "string") {
190
+ throw new ValidationError("File path must be a non-empty string");
191
+ }
192
+ if (filePath.trim().length === 0) {
193
+ throw new ValidationError("File path cannot be empty or whitespace only");
194
+ }
195
+ const suspiciousPatterns = [
196
+ /\.\.\//g,
197
+ // Parent directory references
198
+ /\.\.\\+/g,
199
+ // Windows parent directory references
200
+ /%2e%2e%2f/gi,
201
+ // URL-encoded parent directory references
202
+ /%2e%2e%5c/gi,
203
+ // URL-encoded Windows parent directory references
204
+ /\0/g
205
+ // Null bytes
206
+ ];
207
+ for (const pattern of suspiciousPatterns) {
208
+ if (pattern.test(filePath)) {
209
+ throw new ValidationError("File path contains suspicious characters or patterns");
210
+ }
211
+ }
212
+ const resolvedPath = path2.resolve(filePath);
213
+ const cwd = process.cwd();
214
+ if (!resolvedPath.startsWith(cwd) && !path2.isAbsolute(filePath)) {
215
+ throw new ValidationError("File path attempts to access files outside the current directory");
216
+ }
217
+ return resolvedPath;
218
+ }
219
+ function validateOutputFormat(format) {
220
+ if (format !== "json" && format !== "md") {
221
+ throw new ValidationError('Output format must be "json" or "md"');
222
+ }
223
+ return format;
224
+ }
225
+ var RateLimiter = class {
226
+ lastCall = 0;
227
+ minInterval;
228
+ constructor(minIntervalMs = 100) {
229
+ this.minInterval = minIntervalMs;
230
+ }
231
+ /**
232
+ * Ensures minimum time between operations
233
+ */
234
+ async throttle() {
235
+ const now = Date.now();
236
+ const elapsed = now - this.lastCall;
237
+ if (elapsed < this.minInterval) {
238
+ const delay = this.minInterval - elapsed;
239
+ await new Promise((resolve) => setTimeout(resolve, delay));
240
+ }
241
+ this.lastCall = Date.now();
242
+ }
243
+ };
244
+ var npmRateLimiter = new RateLimiter(50);
245
+
246
+ // src/index.ts
247
+ var execFileAsync = promisify(execFile);
248
+ async function generateLocalReport(options = {}) {
249
+ await npmRateLimiter.throttle();
250
+ const cwd = options.cwd ? validateFilePath(options.cwd) : process.cwd();
251
+ const toolVersion = options.toolVersion || await getToolVersion();
252
+ const tree = await npmLs({
253
+ global: false,
254
+ omitDev: options.omitDev,
255
+ depth0: options.depth0,
256
+ cwd
257
+ });
258
+ return buildReportFromNpmTree(tree, {
259
+ context: "local",
260
+ includeTree: options.includeTree,
261
+ omitDev: options.omitDev,
262
+ cwd,
263
+ toolVersion
264
+ });
265
+ }
266
+ async function generateGlobalReport(options = {}) {
267
+ await npmRateLimiter.throttle();
268
+ const toolVersion = options.toolVersion || await getToolVersion();
269
+ const globalRoot = await npmRootGlobal().catch(() => void 0);
270
+ const tree = await npmLs({
271
+ global: true,
272
+ depth0: options.depth0
273
+ });
274
+ return buildReportFromNpmTree(tree, {
275
+ context: "global",
276
+ includeTree: options.includeTree,
277
+ toolVersion,
278
+ globalRoot
279
+ });
280
+ }
281
+ function formatReport(report, format, markdownExtras) {
282
+ const validatedFormat = validateOutputFormat(format);
283
+ if (validatedFormat === "json") {
284
+ return renderJson(report);
285
+ } else {
286
+ return renderMarkdown({ ...report, ...markdownExtras || {} });
287
+ }
288
+ }
289
+ async function installPackagesFromReport(report, options = {}) {
290
+ const cwd = options.cwd ? validateFilePath(options.cwd) : process.cwd();
291
+ const globalPkgs = report.global_packages.map((p) => `${p.name}@${p.version}`).filter(Boolean);
292
+ const localPkgs = report.local_dependencies.map((p) => `${p.name}@${p.version}`).filter(Boolean);
293
+ const devPkgs = report.local_dev_dependencies.map((p) => `${p.name}@${p.version}`).filter(Boolean);
294
+ if (globalPkgs.length === 0 && localPkgs.length === 0 && devPkgs.length === 0) {
295
+ return;
296
+ }
297
+ if (options.dryRun) {
298
+ if (globalPkgs.length > 0) {
299
+ console.log(`[DRY RUN] Would install global: ${globalPkgs.join(" ")}`);
300
+ }
301
+ if (localPkgs.length > 0) {
302
+ console.log(`[DRY RUN] Would install local deps: ${localPkgs.join(" ")}`);
303
+ }
304
+ if (devPkgs.length > 0) {
305
+ console.log(`[DRY RUN] Would install dev deps: ${devPkgs.join(" ")}`);
306
+ }
307
+ return;
308
+ }
309
+ if (globalPkgs.length > 0) {
310
+ await npmRateLimiter.throttle();
311
+ await execFileAsync("npm", ["i", "-g", ...globalPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 });
312
+ }
313
+ if (localPkgs.length > 0) {
314
+ await npmRateLimiter.throttle();
315
+ await execFileAsync("npm", ["i", ...localPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 });
316
+ }
317
+ if (devPkgs.length > 0) {
318
+ await npmRateLimiter.throttle();
319
+ await execFileAsync("npm", ["i", "-D", ...devPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 });
320
+ }
321
+ }
322
+ async function parseReportFile(filePath) {
323
+ const validatedPath = validateFilePath(filePath);
324
+ const raw = await readFile2(validatedPath, "utf8");
325
+ if (validatedPath.endsWith(".md") || validatedPath.endsWith(".markdown") || raw.startsWith("# GEX Report")) {
326
+ return parseMarkdownReport(raw);
327
+ }
328
+ try {
329
+ return JSON.parse(raw);
330
+ } catch (error) {
331
+ throw new Error(
332
+ `Failed to parse report file as JSON: ${error instanceof Error ? error.message : "Unknown error"}`
333
+ );
334
+ }
335
+ }
336
+ async function getToolVersion() {
337
+ try {
338
+ const pkgPath = getPackageJsonPath();
339
+ const raw = await readFile2(pkgPath, "utf8");
340
+ const pkg = JSON.parse(raw);
341
+ return pkg.version || "0.0.0";
342
+ } catch {
343
+ return "0.0.0";
344
+ }
345
+ }
346
+ function getPackageJsonPath() {
347
+ try {
348
+ const __filename = import.meta.url.replace("file://", "");
349
+ const __dirname = path3.dirname(__filename);
350
+ return path3.resolve(__dirname, "..", "package.json");
351
+ } catch {
352
+ return path3.resolve(process.cwd(), "package.json");
353
+ }
354
+ }
355
+ function parseMarkdownReport(md) {
356
+ const lines = md.split(/\r?\n/);
357
+ const findSection = (title) => lines.findIndex((l) => l.trim().toLowerCase() === `## ${title}`.toLowerCase());
358
+ const parseSection = (idx) => {
359
+ if (idx < 0) return [];
360
+ let i = idx + 1;
361
+ while (i < lines.length && !lines[i].trim().startsWith("|")) i++;
362
+ return parseMarkdownPackagesTable(lines, i);
363
+ };
364
+ const global_packages = parseSection(findSection("Global Packages"));
365
+ const local_dependencies = parseSection(findSection("Local Dependencies"));
366
+ const local_dev_dependencies = parseSection(findSection("Local Dev Dependencies"));
367
+ return {
368
+ report_version: "1.0",
369
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
370
+ tool_version: "unknown",
371
+ global_packages,
372
+ local_dependencies,
373
+ local_dev_dependencies
374
+ };
375
+ }
376
+ function parseMarkdownPackagesTable(lines, startIndex) {
377
+ const rows = [];
378
+ if (!lines[startIndex] || !lines[startIndex].trim().startsWith("|")) return rows;
379
+ let i = startIndex + 2;
380
+ while (i < lines.length && lines[i].trim().startsWith("|")) {
381
+ const cols = lines[i].split("|").map((c) => c.trim()).filter((_, idx, arr) => !(idx === 0 || idx === arr.length - 1));
382
+ const [name = "", version = "", resolved_path = ""] = cols;
383
+ if (name) {
384
+ rows.push({ name, version, resolved_path });
385
+ }
386
+ i++;
387
+ }
388
+ return rows;
4
389
  }
5
390
  export {
6
- greet
391
+ ValidationError,
392
+ formatReport,
393
+ generateGlobalReport,
394
+ generateLocalReport,
395
+ installPackagesFromReport,
396
+ parseReportFile
7
397
  };
8
398
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Library API entry.\n * Export functions here for consumers who import your package.\n */\n\nexport function greet(name: string): string {\n return `Hello, ${name}!`\n}\n"],"mappings":";AAKO,SAAS,MAAM,MAAsB;AAC1C,SAAO,UAAU,IAAI;AACvB;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/npm.ts","../src/transform.ts","../src/report/json.ts","../src/report/md.ts","../src/validators.ts"],"sourcesContent":["/**\n * @fileoverview Library API for GEX - Node.js dependency auditing and reporting tool\n * @version 0.3.2\n */\n\nimport { readFile } from 'node:fs/promises'\nimport { execFile } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport path from 'node:path'\n\nimport { npmLs, npmRootGlobal } from './npm.js'\nimport { buildReportFromNpmTree } from './transform.js'\nimport { renderJson } from './report/json.js'\nimport { renderMarkdown } from './report/md.js'\nimport { npmRateLimiter, validateFilePath, validateOutputFormat } from './validators.js'\nimport type { OutputFormat, PackageInfo, Report } from './types.js'\n\nconst execFileAsync = promisify(execFile)\n\nexport type { Report, PackageInfo, OutputFormat } from './types.js'\nexport { ValidationError } from './validators.js'\n\n/**\n * Options for generating local dependency reports\n */\nexport interface LocalReportOptions {\n /** Current working directory (defaults to process.cwd()) */\n cwd?: string\n /** Whether to exclude devDependencies */\n omitDev?: boolean\n /** Whether to use depth=0 for faster execution */\n depth0?: boolean\n /** Whether to include the full npm ls tree in the report */\n includeTree?: boolean\n /** Tool version to include in report metadata */\n toolVersion?: string\n}\n\n/**\n * Options for generating global dependency reports\n */\nexport interface GlobalReportOptions {\n /** Whether to use depth=0 for faster execution */\n depth0?: boolean\n /** Whether to include the full npm ls tree in the report */\n includeTree?: boolean\n /** Tool version to include in report metadata */\n toolVersion?: string\n}\n\n/**\n * Options for installing packages from a report\n */\nexport interface InstallOptions {\n /** Current working directory (defaults to process.cwd()) */\n cwd?: string\n /** Whether to perform a dry run (log commands without executing) */\n dryRun?: boolean\n}\n\n/**\n * Generates a dependency report for the local project\n *\n * @param options Configuration options for the report generation\n * @returns Promise that resolves to a Report object\n * @throws {ValidationError} If options are invalid\n * @throws {Error} If npm operations fail\n *\n * @example\n * ```typescript\n * import { generateLocalReport } from '@yabasha/gex'\n *\n * const report = await generateLocalReport({\n * omitDev: true,\n * depth0: true\n * })\n *\n * console.log(`Found ${report.local_dependencies.length} dependencies`)\n * ```\n */\nexport async function generateLocalReport(options: LocalReportOptions = {}): Promise<Report> {\n await npmRateLimiter.throttle()\n\n const cwd = options.cwd ? validateFilePath(options.cwd) : process.cwd()\n const toolVersion = options.toolVersion || (await getToolVersion())\n\n const tree = await npmLs({\n global: false,\n omitDev: options.omitDev,\n depth0: options.depth0,\n cwd,\n })\n\n return buildReportFromNpmTree(tree, {\n context: 'local',\n includeTree: options.includeTree,\n omitDev: options.omitDev,\n cwd,\n toolVersion,\n })\n}\n\n/**\n * Generates a dependency report for globally installed packages\n *\n * @param options Configuration options for the report generation\n * @returns Promise that resolves to a Report object\n * @throws {ValidationError} If options are invalid\n * @throws {Error} If npm operations fail\n *\n * @example\n * ```typescript\n * import { generateGlobalReport } from '@yabasha/gex'\n *\n * const report = await generateGlobalReport({ depth0: true })\n * console.log(`Found ${report.global_packages.length} global packages`)\n * ```\n */\nexport async function generateGlobalReport(options: GlobalReportOptions = {}): Promise<Report> {\n await npmRateLimiter.throttle()\n\n const toolVersion = options.toolVersion || (await getToolVersion())\n const globalRoot = await npmRootGlobal().catch(() => undefined)\n\n const tree = await npmLs({\n global: true,\n depth0: options.depth0,\n })\n\n return buildReportFromNpmTree(tree, {\n context: 'global',\n includeTree: options.includeTree,\n toolVersion,\n globalRoot,\n })\n}\n\n/**\n * Formats a report object as a string in the specified format\n *\n * @param report The report object to format\n * @param format The output format ('json' or 'md')\n * @param markdownExtras Additional metadata for markdown formatting\n * @returns Formatted report as a string\n * @throws {ValidationError} If format is invalid\n *\n * @example\n * ```typescript\n * import { generateLocalReport, formatReport } from '@yabasha/gex'\n *\n * const report = await generateLocalReport()\n * const jsonOutput = formatReport(report, 'json')\n * const markdownOutput = formatReport(report, 'md', {\n * project_description: 'My awesome project'\n * })\n * ```\n */\nexport function formatReport(\n report: Report,\n format: OutputFormat,\n markdownExtras?: {\n project_description?: string\n project_homepage?: string\n project_bugs?: string\n },\n): string {\n const validatedFormat = validateOutputFormat(format)\n\n if (validatedFormat === 'json') {\n return renderJson(report)\n } else {\n return renderMarkdown({ ...report, ...(markdownExtras || {}) })\n }\n}\n\n/**\n * Installs packages listed in a report\n *\n * @param report The report containing packages to install\n * @param options Installation options\n * @returns Promise that resolves when installation is complete\n * @throws {ValidationError} If options are invalid\n * @throws {Error} If npm installation fails\n *\n * @example\n * ```typescript\n * import { parseReportFile, installPackagesFromReport } from '@yabasha/gex'\n *\n * const report = await parseReportFile('./gex-report.json')\n * await installPackagesFromReport(report, { dryRun: true })\n * ```\n */\nexport async function installPackagesFromReport(\n report: Report,\n options: InstallOptions = {},\n): Promise<void> {\n const cwd = options.cwd ? validateFilePath(options.cwd) : process.cwd()\n\n const globalPkgs = report.global_packages.map((p) => `${p.name}@${p.version}`).filter(Boolean)\n const localPkgs = report.local_dependencies.map((p) => `${p.name}@${p.version}`).filter(Boolean)\n const devPkgs = report.local_dev_dependencies.map((p) => `${p.name}@${p.version}`).filter(Boolean)\n\n if (globalPkgs.length === 0 && localPkgs.length === 0 && devPkgs.length === 0) {\n return\n }\n\n if (options.dryRun) {\n if (globalPkgs.length > 0) {\n console.log(`[DRY RUN] Would install global: ${globalPkgs.join(' ')}`)\n }\n if (localPkgs.length > 0) {\n console.log(`[DRY RUN] Would install local deps: ${localPkgs.join(' ')}`)\n }\n if (devPkgs.length > 0) {\n console.log(`[DRY RUN] Would install dev deps: ${devPkgs.join(' ')}`)\n }\n return\n }\n\n if (globalPkgs.length > 0) {\n await npmRateLimiter.throttle()\n await execFileAsync('npm', ['i', '-g', ...globalPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 })\n }\n\n if (localPkgs.length > 0) {\n await npmRateLimiter.throttle()\n await execFileAsync('npm', ['i', ...localPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 })\n }\n\n if (devPkgs.length > 0) {\n await npmRateLimiter.throttle()\n await execFileAsync('npm', ['i', '-D', ...devPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 })\n }\n}\n\n/**\n * Parses a report file (JSON or Markdown) and returns a Report object\n *\n * @param filePath Path to the report file\n * @returns Promise that resolves to a parsed Report object\n * @throws {ValidationError} If file path is invalid\n * @throws {Error} If file cannot be read or parsed\n *\n * @example\n * ```typescript\n * import { parseReportFile } from '@yabasha/gex'\n *\n * // Parse JSON report\n * const jsonReport = await parseReportFile('./gex-report.json')\n *\n * // Parse Markdown report\n * const mdReport = await parseReportFile('./gex-report.md')\n * ```\n */\nexport async function parseReportFile(filePath: string): Promise<Report> {\n const validatedPath = validateFilePath(filePath)\n const raw = await readFile(validatedPath, 'utf8')\n\n if (\n validatedPath.endsWith('.md') ||\n validatedPath.endsWith('.markdown') ||\n raw.startsWith('# GEX Report')\n ) {\n return parseMarkdownReport(raw)\n }\n\n try {\n return JSON.parse(raw) as Report\n } catch (error) {\n throw new Error(\n `Failed to parse report file as JSON: ${error instanceof Error ? error.message : 'Unknown error'}`,\n )\n }\n}\n\n/**\n * Gets the current tool version from package.json\n */\nasync function getToolVersion(): Promise<string> {\n try {\n const pkgPath = getPackageJsonPath()\n const raw = await readFile(pkgPath, 'utf8')\n const pkg = JSON.parse(raw)\n return pkg.version || '0.0.0'\n } catch {\n return '0.0.0'\n }\n}\n\n/**\n * Gets the path to package.json\n */\nfunction getPackageJsonPath(): string {\n try {\n const __filename = import.meta.url.replace('file://', '')\n const __dirname = path.dirname(__filename)\n return path.resolve(__dirname, '..', 'package.json')\n } catch {\n return path.resolve(process.cwd(), 'package.json')\n }\n}\n\n/**\n * Parses a markdown report and converts it to a Report object\n * (Simplified version of CLI implementation)\n */\nfunction parseMarkdownReport(md: string): Report {\n const lines = md.split(/\\r?\\n/)\n\n const findSection = (title: string) =>\n lines.findIndex((l) => l.trim().toLowerCase() === `## ${title}`.toLowerCase())\n\n const parseSection = (idx: number): PackageInfo[] => {\n if (idx < 0) return []\n\n let i = idx + 1\n while (i < lines.length && !lines[i].trim().startsWith('|')) i++\n\n return parseMarkdownPackagesTable(lines, i)\n }\n\n const global_packages = parseSection(findSection('Global Packages'))\n const local_dependencies = parseSection(findSection('Local Dependencies'))\n const local_dev_dependencies = parseSection(findSection('Local Dev Dependencies'))\n\n return {\n report_version: '1.0',\n timestamp: new Date().toISOString(),\n tool_version: 'unknown',\n global_packages,\n local_dependencies,\n local_dev_dependencies,\n }\n}\n\n/**\n * Parses a markdown table and extracts package information\n */\nfunction parseMarkdownPackagesTable(lines: string[], startIndex: number): PackageInfo[] {\n const rows: PackageInfo[] = []\n if (!lines[startIndex] || !lines[startIndex].trim().startsWith('|')) return rows\n\n let i = startIndex + 2\n while (i < lines.length && lines[i].trim().startsWith('|')) {\n const cols = lines[i]\n .split('|')\n .map((c) => c.trim())\n .filter((_, idx, arr) => !(idx === 0 || idx === arr.length - 1))\n\n const [name = '', version = '', resolved_path = ''] = cols\n if (name) {\n rows.push({ name, version, resolved_path })\n }\n i++\n }\n\n return rows\n}\n","/**\n * @fileoverview npm command execution utilities for dependency analysis\n */\n\n/**\n * Lazily obtain a promisified execFile so tests can mock built-ins reliably.\n */\nasync function getExecFileAsync(): Promise<\n (\n command: string,\n args?: readonly string[] | null,\n options?: any,\n ) => Promise<{ stdout: string; stderr: string }>\n> {\n const { execFile } = await import('node:child_process')\n const { promisify } = await import('node:util')\n return promisify(execFile) as any\n}\n\n/**\n * Options for npm ls command execution\n */\nexport type NpmLsOptions = {\n /** Whether to list global packages */\n global?: boolean\n /** Whether to omit devDependencies */\n omitDev?: boolean\n /** Whether to use depth=0 for faster execution */\n depth0?: boolean\n /** Current working directory for command execution */\n cwd?: string\n}\n\n/**\n * Executes npm ls command and returns parsed dependency tree\n *\n * @param options - Configuration options for npm ls command\n * @returns Promise resolving to npm dependency tree object\n * @throws {Error} If npm command fails or output cannot be parsed\n *\n * @example\n * ```typescript\n * import { npmLs } from './npm.js'\n *\n * // Get local dependencies with devDependencies omitted\n * const tree = await npmLs({ omitDev: true, depth0: true })\n *\n * // Get global packages\n * const globalTree = await npmLs({ global: true })\n * ```\n */\nexport async function npmLs(options: NpmLsOptions = {}): Promise<any> {\n const args = ['ls', '--json']\n if (options.global) args.push('--global')\n if (options.omitDev) args.push('--omit=dev')\n if (options.depth0) args.push('--depth=0')\n\n try {\n const execFileAsync = await getExecFileAsync()\n const { stdout } = await execFileAsync('npm', args, {\n cwd: options.cwd,\n maxBuffer: 10 * 1024 * 1024,\n })\n if (stdout && stdout.trim()) return JSON.parse(stdout)\n return {}\n } catch (err: any) {\n const stdout = err?.stdout\n if (typeof stdout === 'string' && stdout.trim()) {\n try {\n return JSON.parse(stdout)\n } catch (parseErr) {\n if (process.env.DEBUG?.includes('gex')) {\n console.warn('npm ls stdout parse failed:', parseErr)\n }\n }\n }\n const stderr = err?.stderr\n const msg = (typeof stderr === 'string' && stderr.trim()) || err?.message || 'npm ls failed'\n throw new Error(`npm ls failed: ${msg}`)\n }\n}\n\n/**\n * Gets the global npm root directory path\n *\n * @returns Promise resolving to the global npm root path\n * @throws {Error} If npm root -g command fails\n *\n * @example\n * ```typescript\n * import { npmRootGlobal } from './npm.js'\n *\n * try {\n * const globalRoot = await npmRootGlobal()\n * console.log('Global npm root:', globalRoot)\n * } catch (error) {\n * console.error('Failed to get global root:', error.message)\n * }\n * ```\n */\nexport async function npmRootGlobal(): Promise<string> {\n try {\n const execFileAsync = await getExecFileAsync()\n const { stdout } = await execFileAsync('npm', ['root', '-g'])\n return stdout.trim()\n } catch (err: any) {\n const stderr = err?.stderr\n const msg =\n (typeof stderr === 'string' && stderr.trim()) || err?.message || 'npm root -g failed'\n throw new Error(`npm root -g failed: ${msg}`)\n }\n}\n","/**\n * @fileoverview Data transformation utilities for converting npm tree data into reports\n */\n\nimport path from 'node:path'\nimport { readFile } from 'node:fs/promises'\n\nimport type { PackageInfo, Report } from './types.js'\n\n/**\n * Options for report generation and normalization\n */\nexport type NormalizeOptions = {\n /** Context for report generation ('local' or 'global') */\n context: 'local' | 'global'\n /** Whether to include the full npm dependency tree */\n includeTree?: boolean\n /** Whether to omit devDependencies (local context only) */\n omitDev?: boolean\n /** Current working directory */\n cwd?: string\n /** Tool version to include in report */\n toolVersion: string\n /** Global npm root directory path */\n globalRoot?: string\n}\n\n/**\n * Converts npm dependency object to array of package entries\n *\n * @param obj - npm dependency object from npm ls output\n * @returns Array of name/node pairs for packages\n */\nfunction toPkgArray(obj: Record<string, any> | undefined | null): { name: string; node: any }[] {\n if (!obj) return []\n return Object.keys(obj)\n .map((name) => ({ name, node: obj[name] }))\n .filter((p) => p && p.node)\n}\n\n/**\n * Builds a GEX report from npm ls tree output\n *\n * @param tree - Raw npm ls command output\n * @param opts - Report generation options\n * @returns Promise resolving to a formatted Report object\n *\n * @example\n * ```typescript\n * import { buildReportFromNpmTree } from './transform.js'\n * import { npmLs } from './npm.js'\n *\n * const tree = await npmLs({ depth0: true })\n * const report = await buildReportFromNpmTree(tree, {\n * context: 'local',\n * toolVersion: '0.3.2',\n * cwd: process.cwd()\n * })\n *\n * console.log(`Found ${report.local_dependencies.length} dependencies`)\n * ```\n */\nexport async function buildReportFromNpmTree(tree: any, opts: NormalizeOptions): Promise<Report> {\n const timestamp = new Date().toISOString()\n const report: Report = {\n report_version: '1.0',\n timestamp,\n tool_version: opts.toolVersion,\n global_packages: [],\n local_dependencies: [],\n local_dev_dependencies: [],\n }\n\n if (opts.context === 'local') {\n let pkgMeta: any = null\n try {\n const pkgJsonPath = path.join(opts.cwd || process.cwd(), 'package.json')\n const raw = await readFile(pkgJsonPath, 'utf8')\n pkgMeta = JSON.parse(raw)\n } catch {\n // Ignore errors reading/parsing package.json; fall back to undefined metadata\n void 0\n }\n if (pkgMeta?.name) report.project_name = pkgMeta.name\n if (pkgMeta?.version) report.project_version = pkgMeta.version\n\n const depsObj = tree?.dependencies as Record<string, any> | undefined\n const items = toPkgArray(depsObj)\n const devKeys = new Set(Object.keys((pkgMeta?.devDependencies as Record<string, string>) || {}))\n\n for (const { name, node } of items) {\n const version = (node && node.version) || ''\n const resolvedPath =\n (node && node.path) || path.join(opts.cwd || process.cwd(), 'node_modules', name)\n const pkg: PackageInfo = { name, version, resolved_path: resolvedPath }\n if (devKeys.has(name)) {\n report.local_dev_dependencies.push(pkg)\n } else {\n report.local_dependencies.push(pkg)\n }\n }\n\n report.local_dependencies.sort((a, b) => a.name.localeCompare(b.name))\n report.local_dev_dependencies.sort((a, b) => a.name.localeCompare(b.name))\n } else if (opts.context === 'global') {\n const depsObj = tree?.dependencies as Record<string, any> | undefined\n const items = toPkgArray(depsObj)\n\n for (const { name, node } of items) {\n const version = (node && node.version) || ''\n const resolvedPath = (node && node.path) || path.join(opts.globalRoot || '', name)\n const pkg: PackageInfo = { name, version, resolved_path: resolvedPath }\n report.global_packages.push(pkg)\n }\n\n report.global_packages.sort((a, b) => a.name.localeCompare(b.name))\n }\n\n if (opts.includeTree) {\n report.tree = tree\n }\n\n return report\n}\n","/**\n * @fileoverview JSON report rendering utilities\n */\n\nimport type { Report } from '../types.js'\n\n/**\n * Renders a Report object as formatted JSON string\n *\n * @param report - Report object to render\n * @returns Pretty-printed JSON string with consistent package ordering\n *\n * @example\n * ```typescript\n * import { renderJson } from './report/json.js'\n *\n * const report = {\n * report_version: '1.0',\n * timestamp: new Date().toISOString(),\n * tool_version: '0.3.2',\n * global_packages: [],\n * local_dependencies: [{ name: 'axios', version: '1.6.0', resolved_path: '/path/to/axios' }],\n * local_dev_dependencies: []\n * }\n *\n * const jsonOutput = renderJson(report)\n * console.log(jsonOutput) // Pretty-printed JSON\n * ```\n */\nexport function renderJson(report: Report): string {\n const r: Report = {\n ...report,\n global_packages: [...report.global_packages].sort((a, b) => a.name.localeCompare(b.name)),\n local_dependencies: [...report.local_dependencies].sort((a, b) => a.name.localeCompare(b.name)),\n local_dev_dependencies: [...report.local_dev_dependencies].sort((a, b) =>\n a.name.localeCompare(b.name),\n ),\n }\n return JSON.stringify(r, null, 2)\n}\n","/**\n * @fileoverview Markdown report rendering utilities\n */\n\nimport type { Report } from '../types.js'\n\n/**\n * Creates a markdown table from headers and row data\n *\n * @param headers - Array of table header strings\n * @param rows - Array of row data (each row is array of strings)\n * @returns Formatted markdown table string\n */\nfunction table(headers: string[], rows: string[][]): string {\n const header = `| ${headers.join(' | ')} |`\n const sep = `| ${headers.map(() => '---').join(' | ')} |`\n const body = rows.map((r) => `| ${r.join(' | ')} |`).join('\\n')\n return [header, sep, body].filter(Boolean).join('\\n')\n}\n\n/**\n * Renders a Report object as formatted Markdown\n *\n * @param report - Report object with optional project metadata\n * @returns Formatted Markdown string with tables and sections\n *\n * @example\n * ```typescript\n * import { renderMarkdown } from './report/md.js'\n *\n * const report = {\n * report_version: '1.0',\n * timestamp: new Date().toISOString(),\n * tool_version: '0.3.2',\n * project_name: 'my-project',\n * global_packages: [],\n * local_dependencies: [\n * { name: 'axios', version: '1.6.0', resolved_path: '/path/to/axios' }\n * ],\n * local_dev_dependencies: [],\n * project_description: 'My awesome project'\n * }\n *\n * const markdown = renderMarkdown(report)\n * console.log(markdown) // Formatted markdown with tables\n * ```\n */\nexport function renderMarkdown(\n report: Report & {\n project_description?: string\n project_homepage?: string\n project_bugs?: string\n },\n): string {\n const lines: string[] = []\n lines.push('# GEX Report')\n lines.push('')\n\n if (\n report.project_name ||\n report.project_version ||\n (report as any).project_description ||\n (report as any).project_homepage ||\n (report as any).project_bugs\n ) {\n lines.push('## Project Metadata')\n if (report.project_name) lines.push(`- Name: ${report.project_name}`)\n if (report.project_version) lines.push(`- Version: ${report.project_version}`)\n if ((report as any).project_description)\n lines.push(`- Description: ${(report as any).project_description}`)\n if ((report as any).project_homepage)\n lines.push(`- Homepage: ${(report as any).project_homepage}`)\n if ((report as any).project_bugs) lines.push(`- Bugs: ${(report as any).project_bugs}`)\n lines.push('')\n }\n\n if (report.global_packages.length > 0) {\n lines.push('## Global Packages')\n const rows = report.global_packages.map((p) => [p.name, p.version || '', p.resolved_path || ''])\n lines.push(table(['Name', 'Version', 'Path'], rows))\n lines.push('')\n }\n\n if (report.local_dependencies.length > 0) {\n lines.push('## Local Dependencies')\n const rows = report.local_dependencies.map((p) => [\n p.name,\n p.version || '',\n p.resolved_path || '',\n ])\n lines.push(table(['Name', 'Version', 'Path'], rows))\n lines.push('')\n }\n\n if (report.local_dev_dependencies.length > 0) {\n lines.push('## Local Dev Dependencies')\n const rows = report.local_dev_dependencies.map((p) => [\n p.name,\n p.version || '',\n p.resolved_path || '',\n ])\n lines.push(table(['Name', 'Version', 'Path'], rows))\n lines.push('')\n }\n\n lines.push('---')\n lines.push('_Generated by GEX_')\n\n return lines.join('\\n')\n}\n","import path from 'node:path'\nimport { setTimeout } from 'node:timers'\n\nimport type { OutputFormat } from './types.js'\n\n/**\n * Custom error class for validation failures\n */\nexport class ValidationError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'ValidationError'\n }\n}\n\n/**\n * Validates and sanitizes file paths to prevent directory traversal attacks\n */\nexport function validateFilePath(filePath: string): string {\n if (!filePath || typeof filePath !== 'string') {\n throw new ValidationError('File path must be a non-empty string')\n }\n\n if (filePath.trim().length === 0) {\n throw new ValidationError('File path cannot be empty or whitespace only')\n }\n\n const suspiciousPatterns = [\n /\\.\\.\\//g, // Parent directory references\n /\\.\\.\\\\+/g, // Windows parent directory references\n /%2e%2e%2f/gi, // URL-encoded parent directory references\n /%2e%2e%5c/gi, // URL-encoded Windows parent directory references\n /\\0/g, // Null bytes\n ]\n\n for (const pattern of suspiciousPatterns) {\n if (pattern.test(filePath)) {\n throw new ValidationError('File path contains suspicious characters or patterns')\n }\n }\n\n const resolvedPath = path.resolve(filePath)\n const cwd = process.cwd()\n\n if (!resolvedPath.startsWith(cwd) && !path.isAbsolute(filePath)) {\n throw new ValidationError('File path attempts to access files outside the current directory')\n }\n\n return resolvedPath\n}\n\n/**\n * Validates output format\n */\nexport function validateOutputFormat(format: unknown): OutputFormat {\n if (format !== 'json' && format !== 'md') {\n throw new ValidationError('Output format must be \"json\" or \"md\"')\n }\n return format\n}\n\n/**\n * Validates and sanitizes package names\n */\nexport function validatePackageName(name: string): string {\n if (!name || typeof name !== 'string') {\n throw new ValidationError('Package name must be a non-empty string')\n }\n\n const trimmed = name.trim()\n if (trimmed.length === 0) {\n throw new ValidationError('Package name cannot be empty or whitespace only')\n }\n\n const packageNamePattern = /^(@[a-z0-9-_]+\\/)?[a-z0-9-_.]+$/i\n if (!packageNamePattern.test(trimmed)) {\n throw new ValidationError('Package name contains invalid characters')\n }\n\n if (trimmed.length > 214) {\n throw new ValidationError('Package name is too long')\n }\n\n return trimmed\n}\n\n/**\n * Validates semantic version strings\n */\nexport function validateVersion(version: string): string {\n if (typeof version !== 'string') {\n throw new ValidationError('Version must be a string')\n }\n\n const trimmed = version.trim()\n if (trimmed.length === 0) {\n return '' // Allow empty versions for broken packages\n }\n\n const semverPattern = /^(\\d+)\\.(\\d+)\\.(\\d+)(?:-([a-zA-Z0-9-_.]+))?(?:\\+([a-zA-Z0-9-_.]+))?$/\n const relaxedPattern = /^[a-zA-Z0-9-_.+]+$/ // More permissive for npm's various formats\n\n if (!semverPattern.test(trimmed) && !relaxedPattern.test(trimmed)) {\n throw new ValidationError('Version contains invalid characters')\n }\n\n if (trimmed.length > 50) {\n throw new ValidationError('Version string is too long')\n }\n\n return trimmed\n}\n\n/**\n * Sanitizes text for safe inclusion in markdown tables\n */\nexport function sanitizeForMarkdown(text: string): string {\n if (!text || typeof text !== 'string') {\n return ''\n }\n\n return text\n .replace(/\\|/g, '\\\\|') // Escape pipe characters that could break table formatting\n .replace(/\\n/g, ' ') // Replace newlines with spaces\n .replace(/\\r/g, '') // Remove carriage returns\n .replace(/\\t/g, ' ') // Replace tabs with spaces\n .trim()\n}\n\n/**\n * Validates command options object\n */\nexport function validateCommandOptions(options: Record<string, unknown>): Record<string, unknown> {\n if (!options || typeof options !== 'object') {\n throw new ValidationError('Options must be an object')\n }\n\n const validatedOptions: Record<string, unknown> = {}\n\n if ('outputFormat' in options) {\n validatedOptions.outputFormat = validateOutputFormat(options.outputFormat)\n }\n\n if ('outFile' in options && options.outFile != null) {\n validatedOptions.outFile = validateFilePath(options.outFile as string)\n }\n\n if ('cwd' in options && options.cwd != null) {\n validatedOptions.cwd = validateFilePath(options.cwd as string)\n }\n\n for (const [key, value] of Object.entries(options)) {\n if (!Object.hasOwn(validatedOptions, key)) {\n if (typeof value === 'boolean' || typeof value === 'number' || typeof value === 'string') {\n validatedOptions[key] = value\n }\n }\n }\n\n return validatedOptions\n}\n\n/**\n * Rate limiting utility for npm operations\n */\nexport class RateLimiter {\n private lastCall: number = 0\n private readonly minInterval: number\n\n constructor(minIntervalMs: number = 100) {\n this.minInterval = minIntervalMs\n }\n\n /**\n * Ensures minimum time between operations\n */\n async throttle(): Promise<void> {\n const now = Date.now()\n const elapsed = now - this.lastCall\n\n if (elapsed < this.minInterval) {\n const delay = this.minInterval - elapsed\n await new Promise<void>((resolve) => setTimeout(resolve, delay))\n }\n\n this.lastCall = Date.now()\n }\n}\n\n/**\n * Global rate limiter instance for npm operations\n */\nexport const npmRateLimiter = new RateLimiter(50) // 50ms minimum between npm calls\n"],"mappings":"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","names":["readFile","path","execFile","promisify","execFileAsync","path","readFile","path"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yabasha/gex",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "private": false,
5
5
  "description": "A CLI tool for auditing and documenting your Node.js package environment, generating comprehensive reports of global and local dependencies.",
6
6
  "type": "module",
@@ -42,6 +42,14 @@
42
42
  "tsup",
43
43
  "commander"
44
44
  ],
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "https://github.com/yabasha/yabasha-gex"
48
+ },
49
+ "homepage": "https://github.com/yabasha/yabasha-gex#readme",
50
+ "bugs": {
51
+ "url": "https://github.com/yabasha/yabasha-gex/issues"
52
+ },
45
53
  "author": "",
46
54
  "license": "MIT",
47
55
  "devDependencies": {