superjs-core 0.5.0 → 0.6.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.
@@ -1,8 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // src/dep-exray/cli.ts
4
- import { Command } from "commander";
5
-
6
3
  // src/dep-exray/scanner/index.ts
7
4
  import { readFileSync, readdirSync, existsSync } from "fs";
8
5
  import { join, basename } from "path";
@@ -300,27 +297,40 @@ async function scanProject(config) {
300
297
  }
301
298
 
302
299
  // src/dep-exray/reporter/index.ts
303
- import pc from "picocolors";
300
+ var _ = {
301
+ reset: "\x1B[0m",
302
+ bold: "\x1B[1m",
303
+ dim: "\x1B[2m",
304
+ red: "\x1B[31m",
305
+ green: "\x1B[32m",
306
+ yellow: "\x1B[33m",
307
+ blue: "\x1B[34m",
308
+ cyan: "\x1B[36m",
309
+ white: "\x1B[37m"
310
+ };
311
+ function style(text, codes) {
312
+ return codes.join("") + text + _.reset;
313
+ }
304
314
  function severityColor(severity) {
305
315
  switch (severity) {
306
316
  case "critical":
307
- return pc.bold(pc.red(severity.toUpperCase()));
317
+ return style(severity.toUpperCase(), [_.bold, _.red]);
308
318
  case "high":
309
- return pc.red(severity.toUpperCase());
319
+ return style(severity.toUpperCase(), [_.red]);
310
320
  case "medium":
311
- return pc.yellow(severity.toUpperCase());
321
+ return style(severity.toUpperCase(), [_.yellow]);
312
322
  case "low":
313
- return pc.dim(severity.toUpperCase());
323
+ return style(severity.toUpperCase(), [_.dim]);
314
324
  }
315
325
  }
316
326
  function confidenceIcon(confidence) {
317
327
  switch (confidence) {
318
328
  case "high":
319
- return pc.green("\u25CF");
329
+ return style("\u25CF", [_.green]);
320
330
  case "medium":
321
- return pc.yellow("\u25CF");
331
+ return style("\u25CF", [_.yellow]);
322
332
  case "low":
323
- return pc.red("\u25CF");
333
+ return style("\u25CF", [_.red]);
324
334
  }
325
335
  }
326
336
  function generateReport(result, jsonOutput) {
@@ -328,55 +338,97 @@ function generateReport(result, jsonOutput) {
328
338
  return JSON.stringify(result, null, 2);
329
339
  }
330
340
  const lines = [];
331
- lines.push(pc.bold(pc.cyan(`\u250C${"\u2500".repeat(58)}\u2510`)));
332
- lines.push(pc.bold(pc.cyan(`\u2502${" ".repeat(18)}dep-exray Report${" ".repeat(21)}\u2502`)));
333
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
334
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.white("\u{1F4E6} PROJECT:")} ${pc.bold(result.projectName)}${" ".repeat(Math.max(1, 47 - result.projectName.length))}\u2502`)));
335
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.white("\u{1F4CA} DEPENDENCIES:")} ${pc.bold(String(result.directDeps))} direct + ${pc.bold(String(result.transitiveDeps))} transitive${" ".repeat(Math.max(1, 27 - String(result.transitiveDeps).length))}\u2502`)));
336
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.white("\u{1F4BE} TOTAL SIZE:")} ${pc.bold(result.totalEstimatedSize)}${" ".repeat(Math.max(1, 42 - result.totalEstimatedSize.length))}\u2502`)));
337
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
341
+ const t = (text, codes = [_.cyan]) => style(text, [_.bold, ...codes]);
342
+ lines.push(t(`\u250C${"\u2500".repeat(58)}\u2510`));
343
+ lines.push(t(`\u2502${" ".repeat(18)}dep-exray Report${" ".repeat(21)}\u2502`));
344
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
345
+ lines.push(t(`\u2502 ${style("\u{1F4E6} PROJECT:", [_.white])} ${style(result.projectName, [_.bold])}${" ".repeat(Math.max(1, 47 - result.projectName.length))}\u2502`));
346
+ lines.push(t(`\u2502 ${style("\u{1F4CA} DEPENDENCIES:", [_.white])} ${style(String(result.directDeps), [_.bold])} direct + ${style(String(result.transitiveDeps), [_.bold])} transitive${" ".repeat(Math.max(1, 27 - String(result.transitiveDeps).length))}\u2502`));
347
+ lines.push(t(`\u2502 ${style("\u{1F4BE} TOTAL SIZE:", [_.white])} ${style(result.totalEstimatedSize, [_.bold])}${" ".repeat(Math.max(1, 42 - result.totalEstimatedSize.length))}\u2502`));
348
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
338
349
  if (result.highImpactReplacements.length > 0) {
339
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.green("\u{1F7E2}")} ${pc.bold(pc.green("HIGH IMPACT REPLACEMENTS"))}${" ".repeat(23)}\u2502`)));
350
+ lines.push(t(`\u2502 ${style("\u{1F7E2}", [_.green])} ${style("HIGH IMPACT REPLACEMENTS", [_.bold, _.green])}${" ".repeat(23)}\u2502`));
340
351
  for (const item of result.highImpactReplacements) {
341
- const autoPr = item.autoPrReady ? pc.green("\u2713 Auto-PR ready") : pc.dim("Manual review needed");
352
+ const autoPr = item.autoPrReady ? style("\u2713 Auto-PR ready", [_.green]) : style("Manual review needed", [_.dim]);
342
353
  const confIcon = confidenceIcon(item.confidence);
343
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
344
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.red("\u2717")} ${pc.bold(item.packageName)} (${item.estimatedSizeReduction})${" ".repeat(Math.max(1, 38 - item.estimatedSizeReduction.length))}\u2502`)));
345
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.dim("\u2192")} ${pc.cyan(item.replacement)}${" ".repeat(Math.max(1, 51 - item.replacement.length))}\u2502`)));
346
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.dim("\u2514\u2500")} ${autoPr} ${confIcon} ${item.confidence}${" ".repeat(Math.max(1, 35))}\u2502`)));
354
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
355
+ lines.push(t(`\u2502 ${style("\u2717", [_.red])} ${style(item.packageName, [_.bold])} (${item.estimatedSizeReduction})${" ".repeat(Math.max(1, 38 - item.estimatedSizeReduction.length))}\u2502`));
356
+ lines.push(t(`\u2502 ${style("\u2192", [_.dim])} ${style(item.replacement, [_.cyan])}${" ".repeat(Math.max(1, 51 - item.replacement.length))}\u2502`));
357
+ lines.push(t(`\u2502 ${style("\u2514\u2500", [_.dim])} ${autoPr} ${confIcon} ${item.confidence}${" ".repeat(Math.max(1, 35))}\u2502`));
347
358
  }
348
359
  }
349
360
  if (result.mediumImpactReplacements.length > 0) {
350
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
351
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.yellow("\u{1F7E1}")} ${pc.bold(pc.yellow("MEDIUM IMPACT REPLACEMENTS"))}${" ".repeat(20)}\u2502`)));
361
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
362
+ lines.push(t(`\u2502 ${style("\u{1F7E1}", [_.yellow])} ${style("MEDIUM IMPACT REPLACEMENTS", [_.bold, _.yellow])}${" ".repeat(20)}\u2502`));
352
363
  for (const item of result.mediumImpactReplacements) {
353
- const autoPr = item.autoPrReady ? pc.green("\u2713 Auto-PR ready") : pc.dim("Manual review needed");
364
+ const autoPr = item.autoPrReady ? style("\u2713 Auto-PR ready", [_.green]) : style("Manual review needed", [_.dim]);
354
365
  const confIcon = confidenceIcon(item.confidence);
355
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
356
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.red("\u2717")} ${pc.bold(item.packageName)} (${item.estimatedSizeReduction})${" ".repeat(Math.max(1, 38 - item.estimatedSizeReduction.length))}\u2502`)));
357
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.dim("\u2192")} ${pc.cyan(item.replacement)}${" ".repeat(Math.max(1, 51 - item.replacement.length))}\u2502`)));
358
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.dim("\u2514\u2500")} ${autoPr} ${confIcon} ${item.confidence}${" ".repeat(Math.max(1, 35))}\u2502`)));
366
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
367
+ lines.push(t(`\u2502 ${style("\u2717", [_.red])} ${style(item.packageName, [_.bold])} (${item.estimatedSizeReduction})${" ".repeat(Math.max(1, 38 - item.estimatedSizeReduction.length))}\u2502`));
368
+ lines.push(t(`\u2502 ${style("\u2192", [_.dim])} ${style(item.replacement, [_.cyan])}${" ".repeat(Math.max(1, 51 - item.replacement.length))}\u2502`));
369
+ lines.push(t(`\u2502 ${style("\u2514\u2500", [_.dim])} ${autoPr} ${confIcon} ${item.confidence}${" ".repeat(Math.max(1, 35))}\u2502`));
359
370
  }
360
371
  }
361
372
  if (result.securityIssues.length > 0) {
362
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
363
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.red("\u{1F534}")} ${pc.bold(pc.red("SECURITY ISSUES"))}${" ".repeat(33)}\u2502`)));
373
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
374
+ lines.push(t(`\u2502 ${style("\u{1F534}", [_.red])} ${style("SECURITY ISSUES", [_.bold, _.red])}${" ".repeat(33)}\u2502`));
364
375
  for (const issue of result.securityIssues) {
365
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
366
- lines.push(pc.bold(pc.cyan(`\u2502 ${severityColor(issue.severity)} ${pc.bold(issue.cveId)} in ${issue.packageName}${" ".repeat(Math.max(1, 40 - issue.packageName.length))}\u2502`)));
367
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.dim("\u2192")} ${issue.fix}${" ".repeat(Math.max(1, 52 - issue.fix.length))}\u2502`)));
376
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
377
+ lines.push(t(`\u2502 ${severityColor(issue.severity)} ${style(issue.cveId, [_.bold])} in ${issue.packageName}${" ".repeat(Math.max(1, 40 - issue.packageName.length))}\u2502`));
378
+ lines.push(t(`\u2502 ${style("\u2192", [_.dim])} ${issue.fix}${" ".repeat(Math.max(1, 52 - issue.fix.length))}\u2502`));
368
379
  }
369
380
  }
370
- lines.push(pc.bold(pc.cyan(`\u2514${"\u2500".repeat(58)}\u2518`)));
381
+ lines.push(t(`\u2514${"\u2500".repeat(58)}\u2518`));
371
382
  return lines.join("\n");
372
383
  }
373
384
 
374
385
  // src/dep-exray/cli.ts
375
- var program = new Command();
376
- program.name("dep-exray").description("Dependency health scanner for JavaScript/TypeScript projects").version("0.1.0").argument("[path]", "Project path to scan", ".").option("-j, --json", "Output as JSON").option("-v, --verbose", "Verbose output").option("--fix", "Auto-generate migration PRs").action(async (path, options) => {
386
+ function parseArgs(args) {
387
+ let path = ".";
388
+ let json = false;
389
+ let verbose = false;
390
+ let fix = false;
391
+ for (let i = 0; i < args.length; i++) {
392
+ const arg = args[i];
393
+ if (arg === "--json" || arg === "-j") {
394
+ json = true;
395
+ } else if (arg === "--verbose" || arg === "-v") {
396
+ verbose = true;
397
+ } else if (arg === "--fix") {
398
+ fix = true;
399
+ } else if (!arg.startsWith("-")) {
400
+ path = arg;
401
+ }
402
+ }
403
+ return { path, json, verbose, fix };
404
+ }
405
+ async function main() {
406
+ const args = process.argv.slice(2);
407
+ if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
408
+ console.log(`
409
+ dep-exray \u2014 Dependency Health Scanner
410
+
411
+ Usage:
412
+ dep-exray [path] [options]
413
+
414
+ Arguments:
415
+ path Project path to scan (default: .)
416
+
417
+ Options:
418
+ -j, --json Output as JSON
419
+ -v, --verbose Verbose output
420
+ --fix Auto-generate migration PRs
421
+ -h, --help Show this help
422
+ `);
423
+ process.exit(0);
424
+ }
425
+ const { path, json, verbose, fix } = parseArgs(args);
377
426
  try {
378
- const result = await scanProject({ path, verbose: options.verbose, jsonOutput: options.json });
379
- console.log(generateReport(result, options.json));
427
+ const result = await scanProject({ path, verbose, jsonOutput: json });
428
+ console.log(generateReport(result, json));
429
+ if (fix) {
430
+ console.log("\n --fix mode: Auto-PR generation not yet implemented\n");
431
+ }
380
432
  } catch (error) {
381
433
  const message = error instanceof Error ? error.message : String(error);
382
434
  console.error(`
@@ -384,6 +436,6 @@ program.name("dep-exray").description("Dependency health scanner for JavaScript/
384
436
  `);
385
437
  process.exit(1);
386
438
  }
387
- });
388
- program.parse();
439
+ }
440
+ main();
389
441
  //# sourceMappingURL=cli.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/dep-exray/cli.ts","../../src/dep-exray/scanner/index.ts","../../src/dep-exray/known-mappings.ts","../../src/dep-exray/reporter/index.ts"],"sourcesContent":["#!/usr/bin/env node\r\nimport { Command } from 'commander'\r\nimport { scanProject } from './scanner/index.js'\r\nimport { generateReport } from './reporter/index.js'\r\n\r\nconst program = new Command()\r\n\r\nprogram\r\n .name('dep-exray')\r\n .description('Dependency health scanner for JavaScript/TypeScript projects')\r\n .version('0.1.0')\r\n .argument('[path]', 'Project path to scan', '.')\r\n .option('-j, --json', 'Output as JSON')\r\n .option('-v, --verbose', 'Verbose output')\r\n .option('--fix', 'Auto-generate migration PRs')\r\n .action(async (path: string, options: { json?: boolean; verbose?: boolean; fix?: boolean }) => {\r\n try {\r\n const result = await scanProject({ path, verbose: options.verbose, jsonOutput: options.json })\r\n console.log(generateReport(result, options.json))\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error)\r\n console.error(`\\n ✖ ${message}\\n`)\r\n process.exit(1)\r\n }\r\n })\r\n\r\nprogram.parse()\r\n","import { readFileSync, readdirSync, existsSync } from 'node:fs'\r\nimport { join, basename } from 'node:path'\r\nimport type { ScanResult, ReplacementSuggestion, SecurityIssue, ScannerConfig } from '../types.js'\r\nimport { KNOWN_MAPPINGS, KNOWN_CVES, type PackageMapping } from '../known-mappings.js'\r\n\r\ninterface LockfilePackages {\r\n [key: string]: { version?: string; dependencies?: Record<string, string> } | undefined\r\n}\r\n\r\ninterface LockfileData {\r\n packages: LockfilePackages\r\n}\r\n\r\nfunction parsePackageJson(path: string): { name: string; dependencies: Record<string, string>; devDependencies: Record<string, string> } {\r\n const raw = readFileSync(path, 'utf-8')\r\n const json = JSON.parse(raw)\r\n return {\r\n name: json.name ?? basename(join(path, '..')),\r\n dependencies: (json.dependencies as Record<string, string>) ?? {},\r\n devDependencies: (json.devDependencies as Record<string, string>) ?? {},\r\n }\r\n}\r\n\r\nfunction parseLockfile(projectPath: string): LockfileData | null {\r\n const lockPath = join(projectPath, 'package-lock.json')\r\n if (!existsSync(lockPath)) return null\r\n try {\r\n const raw = readFileSync(lockPath, 'utf-8')\r\n const json = JSON.parse(raw)\r\n const packages: LockfilePackages = {}\r\n\r\n if (json.packages) {\r\n for (const [key, val] of Object.entries(json.packages as Record<string, { version?: string }>)) {\r\n if (key) {\r\n packages[key] = val\r\n }\r\n }\r\n }\r\n\r\n if (json.dependencies && Object.keys(packages).length === 0) {\r\n for (const [key, val] of Object.entries(json.dependencies as Record<string, { version?: string; requires?: Record<string, string> }>)) {\r\n packages[key] = { version: val.version, dependencies: val.requires }\r\n }\r\n }\r\n\r\n return { packages }\r\n } catch {\r\n return null\r\n }\r\n}\r\n\r\nfunction detectImportInFile(filePath: string, regex: RegExp): boolean {\r\n try {\r\n const content = readFileSync(filePath, 'utf-8')\r\n return regex.test(content)\r\n } catch {\r\n return false\r\n }\r\n}\r\n\r\nfunction detectImportsInSrc(projectPath: string, mapping: PackageMapping): boolean {\r\n const regex = new RegExp(mapping.detectionPattern)\r\n const srcDir = join(projectPath, 'src')\r\n if (!existsSync(srcDir)) return false\r\n\r\n try {\r\n const files = collectSourceFiles(srcDir)\r\n for (const file of files) {\r\n if (detectImportInFile(file, regex)) return true\r\n }\r\n } catch {\r\n return false\r\n }\r\n return false\r\n}\r\n\r\nfunction collectSourceFiles(dir: string): string[] {\r\n const results: string[] = []\r\n try {\r\n const entries = readdirSync(dir, { withFileTypes: true })\r\n for (const entry of entries) {\r\n if (entry.name === 'node_modules' || entry.name === 'dist' || entry.name === '.git' || entry.name === 'coverage' || entry.name === '.tsup') {\r\n continue\r\n }\r\n const full = join(dir, entry.name)\r\n if (entry.isDirectory()) {\r\n results.push(...collectSourceFiles(full))\r\n } else if (entry.isFile()) {\r\n const ext = entry.name.split('.').pop()\r\n if (ext === 'ts' || ext === 'tsx' || ext === 'js' || ext === 'jsx' || ext === 'mjs' || ext === 'cjs') {\r\n results.push(full)\r\n }\r\n }\r\n }\r\n } catch {\r\n // skip inaccessible dirs\r\n }\r\n return results\r\n}\r\n\r\nfunction estimateTransitiveCount(lockfile: LockfileData | null, directNames: Set<string>): number {\r\n if (!lockfile) return 0\r\n let count = 0\r\n for (const key of Object.keys(lockfile.packages)) {\r\n if (!key || key === '') continue\r\n const name = key.startsWith('node_modules/') ? key.slice('node_modules/'.length) : key\r\n const rootName = name.startsWith('@') ? `${name.split('/')[0]}/${name.split('/')[1]}` : name.split('/')[0]\r\n if (rootName && !directNames.has(rootName)) {\r\n count++\r\n }\r\n }\r\n return count\r\n}\r\n\r\nfunction parseSize(value: string): number {\r\n const cleaned = value.replace(/\\(.*?\\)/g, '').trim()\r\n const match = cleaned.match(/^([\\d.]+)\\s*(KB|MB)/i)\r\n if (!match) return 0\r\n const num = Number.parseFloat(match[1]!)\r\n if (!match[2]) return 0\r\n if (match[2].toUpperCase() === 'MB') return num * 1024\r\n return num\r\n}\r\n\r\nexport async function scanProject(config: ScannerConfig): Promise<ScanResult> {\r\n const projectPath = config.path ?? '.'\r\n const pkgPath = join(projectPath, 'package.json')\r\n\r\n if (!existsSync(pkgPath)) {\r\n throw new Error(`No package.json found at ${projectPath}. Run dep-exray in a JavaScript/TypeScript project directory.`)\r\n }\r\n\r\n const pkg = parsePackageJson(pkgPath)\r\n const lockfile = parseLockfile(projectPath)\r\n\r\n const allDeps: Record<string, string> = { ...pkg.dependencies, ...pkg.devDependencies }\r\n const directNames = new Set(Object.keys(allDeps))\r\n\r\n const transitiveCount = estimateTransitiveCount(lockfile, directNames)\r\n\r\n const highImpactReplacements: ReplacementSuggestion[] = []\r\n const mediumImpactReplacements: ReplacementSuggestion[] = []\r\n const securityIssues: SecurityIssue[] = []\r\n\r\n const sizeMap: Record<string, string> = {}\r\n for (const m of KNOWN_MAPPINGS) {\r\n sizeMap[m.name] = m.size\r\n }\r\n\r\n for (const mapping of KNOWN_MAPPINGS) {\r\n const isDirect = directNames.has(mapping.name)\r\n if (!isDirect) continue\r\n\r\n const isUsed = detectImportsInSrc(projectPath, mapping)\r\n if (!isUsed && !config.verbose) continue\r\n\r\n const mappingSize = parseSize(sizeMap[mapping.name] ?? '0 KB')\r\n const replacementSize = mapping.replacement.startsWith('native') ? 0 : 5\r\n const reductionStr = mappingSize > 1024\r\n ? `${(mappingSize / 1024).toFixed(1)} MB → ${replacementSize} KB`\r\n : `${mappingSize.toFixed(0)} KB → ${replacementSize} KB`\r\n\r\n const suggestion: ReplacementSuggestion = {\r\n packageName: mapping.name,\r\n reason: mapping.reason,\r\n replacement: mapping.replacement,\r\n estimatedSizeReduction: reductionStr,\r\n confidence: mapping.confidence,\r\n autoPrReady: mapping.autoPrReady,\r\n }\r\n\r\n if (mapping.confidence === 'high') {\r\n highImpactReplacements.push(suggestion)\r\n } else {\r\n mediumImpactReplacements.push(suggestion)\r\n }\r\n }\r\n\r\n for (const [name, cves] of Object.entries(KNOWN_CVES)) {\r\n if (directNames.has(name)) {\r\n for (const cveItem of cves) {\r\n securityIssues.push({\r\n packageName: name,\r\n cveId: cveItem.cve,\r\n severity: cveItem.severity as SecurityIssue['severity'],\r\n fix: cveItem.fix,\r\n })\r\n }\r\n }\r\n }\r\n\r\n let totalSizeKB = 0\r\n for (const depName of directNames) {\r\n const sizeStr = sizeMap[depName]\r\n if (sizeStr) {\r\n totalSizeKB += parseSize(sizeStr)\r\n } else {\r\n totalSizeKB += 50\r\n }\r\n }\r\n totalSizeKB += transitiveCount * 30\r\n\r\n const totalSizeStr = totalSizeKB > 1024\r\n ? `${(totalSizeKB / 1024).toFixed(1)} MB`\r\n : `${totalSizeKB.toFixed(0)} KB`\r\n\r\n return {\r\n projectName: pkg.name,\r\n directDeps: directNames.size,\r\n transitiveDeps: transitiveCount,\r\n totalEstimatedSize: totalSizeStr,\r\n highImpactReplacements,\r\n mediumImpactReplacements,\r\n securityIssues,\r\n }\r\n}\r\n","\r\n\r\nexport interface PackageMapping {\r\n name: string\r\n size: string\r\n replacement: string\r\n confidence: 'high' | 'medium' | 'low'\r\n autoPrReady: boolean\r\n reason: string\r\n detectionPattern: string\r\n}\r\n\r\nexport const KNOWN_MAPPINGS: PackageMapping[] = [\r\n {\r\n name: 'lodash',\r\n size: '4.2 MB',\r\n replacement: 'jscore-core',\r\n confidence: 'high',\r\n autoPrReady: true,\r\n reason: 'Most lodash functions have direct replacements in jscore-core with 99% API compatibility',\r\n detectionPattern: 'from [\\'\"]lodash[\\'\"]|require\\\\([\\'\"]lodash[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'moment',\r\n size: '2.5 MB',\r\n replacement: 'jscore-core/date',\r\n confidence: 'high',\r\n autoPrReady: true,\r\n reason: 'date utilities in jscore-core cover 95% of common moment use cases',\r\n detectionPattern: 'from [\\'\"]moment[\\'\"]|require\\\\([\\'\"]moment[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'date-fns',\r\n size: '1.2 MB (tree-shaked ~50KB)',\r\n replacement: 'jscore-core/date',\r\n confidence: 'medium',\r\n autoPrReady: false,\r\n reason: 'Partially overlapping — jscore-core covers basic date ops but not all locale support',\r\n detectionPattern: 'from [\\'\"]date-fns[\\'\"]|require\\\\([\\'\"]date-fns[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'axios',\r\n size: '1.6 MB',\r\n replacement: 'native fetch + jscore-core/async/retry',\r\n confidence: 'medium',\r\n autoPrReady: false,\r\n reason: 'Native fetch covers most use cases; needs manual review for interceptors',\r\n detectionPattern: 'from [\\'\"]axios[\\'\"]|require\\\\([\\'\"]axios[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'uuid',\r\n size: '30 KB',\r\n replacement: 'crypto.randomUUID() (native)',\r\n confidence: 'high',\r\n autoPrReady: true,\r\n reason: 'crypto.randomUUID() is available in all modern Node.js and browsers',\r\n detectionPattern: 'from [\\'\"]uuid[\\'\"]|require\\\\([\\'\"]uuid[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'deepmerge',\r\n size: '15 KB',\r\n replacement: 'jscore-core',\r\n confidence: 'high',\r\n autoPrReady: true,\r\n reason: 'jscore-core provides deepMerge out of the box',\r\n detectionPattern: 'from [\\'\"]deepmerge[\\'\"]|require\\\\([\\'\"]deepmerge[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'lodash.merge',\r\n size: '25 KB',\r\n replacement: 'jscore-core',\r\n confidence: 'high',\r\n autoPrReady: true,\r\n reason: 'jscore-core provides deepMerge out of the box',\r\n detectionPattern: 'from [\\'\"]lodash\\\\.(merge|clone|pick|omit|get|set)[\\'\"]',\r\n },\r\n {\r\n name: 'chalk',\r\n size: '45 KB',\r\n replacement: 'picocolors',\r\n confidence: 'medium',\r\n autoPrReady: false,\r\n reason: \"picocolors is 3KB vs chalk's 45KB with same API\",\r\n detectionPattern: 'from [\\'\"]chalk[\\'\"]|require\\\\([\\'\"]chalk[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'nanoid',\r\n size: '8 KB',\r\n replacement: 'jscore-core/string (nanoid)',\r\n confidence: 'high',\r\n autoPrReady: true,\r\n reason: 'jscore-core provides nanoid with same API',\r\n detectionPattern: 'from [\\'\"]nanoid[\\'\"]|require\\\\([\\'\"]nanoid[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'dayjs',\r\n size: '50 KB',\r\n replacement: 'jscore-core/date',\r\n confidence: 'medium',\r\n autoPrReady: false,\r\n reason: 'Partially overlapping — covers basics but not all plugins',\r\n detectionPattern: 'from [\\'\"]dayjs[\\'\"]|require\\\\([\\'\"]dayjs[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'clsx',\r\n size: '5 KB',\r\n replacement: 'native template literals',\r\n confidence: 'high',\r\n autoPrReady: true,\r\n reason: 'Can be replaced with simple template literal conditional pattern',\r\n detectionPattern: 'from [\\'\"]clsx[\\'\"]|require\\\\([\\'\"]clsx[\\'\"]\\\\)',\r\n },\r\n]\r\n\r\nexport const KNOWN_CVES: Record<string, { cve: string; severity: string; fix: string }[]> = {\r\n 'ansi-regex': [\r\n { cve: 'CVE-2021-3807', severity: 'high', fix: 'Update to ansi-regex@6.0.1 or later' },\r\n ],\r\n 'semver': [\r\n { cve: 'CVE-2022-25883', severity: 'medium', fix: 'Update to semver@7.5.2 or later' },\r\n ],\r\n 'json5': [\r\n { cve: 'CVE-2022-46175', severity: 'high', fix: 'Update to json5@2.2.3 or later' },\r\n ],\r\n 'lodash': [\r\n { cve: 'CVE-2020-28502', severity: 'high', fix: 'Update to lodash@4.17.21 or later' },\r\n { cve: 'CVE-2020-8203', severity: 'medium', fix: 'Update to lodash@4.17.21 or later' },\r\n ],\r\n}\r\n","import pc from 'picocolors'\r\nimport type { ScanResult, ReplacementSuggestion, SecurityIssue } from '../types.js'\r\n\r\nfunction severityColor(severity: SecurityIssue['severity']): string {\r\n switch (severity) {\r\n case 'critical': return pc.bold(pc.red(severity.toUpperCase()))\r\n case 'high': return pc.red(severity.toUpperCase())\r\n case 'medium': return pc.yellow(severity.toUpperCase())\r\n case 'low': return pc.dim(severity.toUpperCase())\r\n }\r\n}\r\n\r\nfunction confidenceIcon(confidence: ReplacementSuggestion['confidence']): string {\r\n switch (confidence) {\r\n case 'high': return pc.green('●')\r\n case 'medium': return pc.yellow('●')\r\n case 'low': return pc.red('●')\r\n }\r\n}\r\n\r\nexport function generateReport(result: ScanResult, jsonOutput?: boolean): string {\r\n if (jsonOutput) {\r\n return JSON.stringify(result, null, 2)\r\n }\r\n\r\n const lines: string[] = []\r\n\r\n // ┌─┐│└┘─\r\n lines.push(pc.bold(pc.cyan(`┌${'─'.repeat(58)}┐`)))\r\n lines.push(pc.bold(pc.cyan(`│${' '.repeat(18)}dep-exray Report${' '.repeat(21)}│`)))\r\n lines.push(pc.bold(pc.cyan(`├${'─'.repeat(58)}┤`)))\r\n lines.push(pc.bold(pc.cyan(`│ ${pc.white('📦 PROJECT:')} ${pc.bold(result.projectName)}${' '.repeat(Math.max(1, 47 - result.projectName.length))}│`)))\r\n lines.push(pc.bold(pc.cyan(`│ ${pc.white('📊 DEPENDENCIES:')} ${pc.bold(String(result.directDeps))} direct + ${pc.bold(String(result.transitiveDeps))} transitive${' '.repeat(Math.max(1, 27 - String(result.transitiveDeps).length))}│`)))\r\n lines.push(pc.bold(pc.cyan(`│ ${pc.white('💾 TOTAL SIZE:')} ${pc.bold(result.totalEstimatedSize)}${' '.repeat(Math.max(1, 42 - result.totalEstimatedSize.length))}│`)))\r\n lines.push(pc.bold(pc.cyan(`├${'─'.repeat(58)}┤`)))\r\n\r\n if (result.highImpactReplacements.length > 0) {\r\n lines.push(pc.bold(pc.cyan(`│ ${pc.green('🟢')} ${pc.bold(pc.green('HIGH IMPACT REPLACEMENTS'))}${' '.repeat(23)}│`)))\r\n for (const item of result.highImpactReplacements) {\r\n const autoPr = item.autoPrReady ? pc.green('✓ Auto-PR ready') : pc.dim('Manual review needed')\r\n const confIcon = confidenceIcon(item.confidence)\r\n lines.push(pc.bold(pc.cyan(`├${'─'.repeat(58)}┤`)))\r\n lines.push(pc.bold(pc.cyan(`│ ${pc.red('✗')} ${pc.bold(item.packageName)} (${item.estimatedSizeReduction})${' '.repeat(Math.max(1, 38 - item.estimatedSizeReduction.length))}│`)))\r\n lines.push(pc.bold(pc.cyan(`│ ${pc.dim('→')} ${pc.cyan(item.replacement)}${' '.repeat(Math.max(1, 51 - item.replacement.length))}│`)))\r\n lines.push(pc.bold(pc.cyan(`│ ${pc.dim('└─')} ${autoPr} ${confIcon} ${item.confidence}${' '.repeat(Math.max(1, 35))}│`)))\r\n }\r\n }\r\n\r\n if (result.mediumImpactReplacements.length > 0) {\r\n lines.push(pc.bold(pc.cyan(`├${'─'.repeat(58)}┤`)))\r\n lines.push(pc.bold(pc.cyan(`│ ${pc.yellow('🟡')} ${pc.bold(pc.yellow('MEDIUM IMPACT REPLACEMENTS'))}${' '.repeat(20)}│`)))\r\n for (const item of result.mediumImpactReplacements) {\r\n const autoPr = item.autoPrReady ? pc.green('✓ Auto-PR ready') : pc.dim('Manual review needed')\r\n const confIcon = confidenceIcon(item.confidence)\r\n lines.push(pc.bold(pc.cyan(`├${'─'.repeat(58)}┤`)))\r\n lines.push(pc.bold(pc.cyan(`│ ${pc.red('✗')} ${pc.bold(item.packageName)} (${item.estimatedSizeReduction})${' '.repeat(Math.max(1, 38 - item.estimatedSizeReduction.length))}│`)))\r\n lines.push(pc.bold(pc.cyan(`│ ${pc.dim('→')} ${pc.cyan(item.replacement)}${' '.repeat(Math.max(1, 51 - item.replacement.length))}│`)))\r\n lines.push(pc.bold(pc.cyan(`│ ${pc.dim('└─')} ${autoPr} ${confIcon} ${item.confidence}${' '.repeat(Math.max(1, 35))}│`)))\r\n }\r\n }\r\n\r\n if (result.securityIssues.length > 0) {\r\n lines.push(pc.bold(pc.cyan(`├${'─'.repeat(58)}┤`)))\r\n lines.push(pc.bold(pc.cyan(`│ ${pc.red('🔴')} ${pc.bold(pc.red('SECURITY ISSUES'))}${' '.repeat(33)}│`)))\r\n for (const issue of result.securityIssues) {\r\n lines.push(pc.bold(pc.cyan(`├${'─'.repeat(58)}┤`)))\r\n lines.push(pc.bold(pc.cyan(`│ ${severityColor(issue.severity)} ${pc.bold(issue.cveId)} in ${issue.packageName}${' '.repeat(Math.max(1, 40 - issue.packageName.length))}│`)))\r\n lines.push(pc.bold(pc.cyan(`│ ${pc.dim('→')} ${issue.fix}${' '.repeat(Math.max(1, 52 - issue.fix.length))}│`)))\r\n }\r\n }\r\n\r\n lines.push(pc.bold(pc.cyan(`└${'─'.repeat(58)}┘`)))\r\n\r\n return lines.join('\\n')\r\n}\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/dep-exray/scanner/index.ts","../../src/dep-exray/known-mappings.ts","../../src/dep-exray/reporter/index.ts","../../src/dep-exray/cli.ts"],"sourcesContent":["import { readFileSync, readdirSync, existsSync } from 'node:fs'\r\nimport { join, basename } from 'node:path'\r\nimport type { ScanResult, ReplacementSuggestion, SecurityIssue, ScannerConfig } from '../types.js'\r\nimport { KNOWN_MAPPINGS, KNOWN_CVES, type PackageMapping } from '../known-mappings.js'\r\n\r\ninterface LockfilePackages {\r\n [key: string]: { version?: string; dependencies?: Record<string, string> } | undefined\r\n}\r\n\r\ninterface LockfileData {\r\n packages: LockfilePackages\r\n}\r\n\r\nfunction parsePackageJson(path: string): { name: string; dependencies: Record<string, string>; devDependencies: Record<string, string> } {\r\n const raw = readFileSync(path, 'utf-8')\r\n const json = JSON.parse(raw)\r\n return {\r\n name: json.name ?? basename(join(path, '..')),\r\n dependencies: (json.dependencies as Record<string, string>) ?? {},\r\n devDependencies: (json.devDependencies as Record<string, string>) ?? {},\r\n }\r\n}\r\n\r\nfunction parseLockfile(projectPath: string): LockfileData | null {\r\n const lockPath = join(projectPath, 'package-lock.json')\r\n if (!existsSync(lockPath)) return null\r\n try {\r\n const raw = readFileSync(lockPath, 'utf-8')\r\n const json = JSON.parse(raw)\r\n const packages: LockfilePackages = {}\r\n\r\n if (json.packages) {\r\n for (const [key, val] of Object.entries(json.packages as Record<string, { version?: string }>)) {\r\n if (key) {\r\n packages[key] = val\r\n }\r\n }\r\n }\r\n\r\n if (json.dependencies && Object.keys(packages).length === 0) {\r\n for (const [key, val] of Object.entries(json.dependencies as Record<string, { version?: string; requires?: Record<string, string> }>)) {\r\n packages[key] = { version: val.version, dependencies: val.requires }\r\n }\r\n }\r\n\r\n return { packages }\r\n } catch {\r\n return null\r\n }\r\n}\r\n\r\nfunction detectImportInFile(filePath: string, regex: RegExp): boolean {\r\n try {\r\n const content = readFileSync(filePath, 'utf-8')\r\n return regex.test(content)\r\n } catch {\r\n return false\r\n }\r\n}\r\n\r\nfunction detectImportsInSrc(projectPath: string, mapping: PackageMapping): boolean {\r\n const regex = new RegExp(mapping.detectionPattern)\r\n const srcDir = join(projectPath, 'src')\r\n if (!existsSync(srcDir)) return false\r\n\r\n try {\r\n const files = collectSourceFiles(srcDir)\r\n for (const file of files) {\r\n if (detectImportInFile(file, regex)) return true\r\n }\r\n } catch {\r\n return false\r\n }\r\n return false\r\n}\r\n\r\nfunction collectSourceFiles(dir: string): string[] {\r\n const results: string[] = []\r\n try {\r\n const entries = readdirSync(dir, { withFileTypes: true })\r\n for (const entry of entries) {\r\n if (entry.name === 'node_modules' || entry.name === 'dist' || entry.name === '.git' || entry.name === 'coverage' || entry.name === '.tsup') {\r\n continue\r\n }\r\n const full = join(dir, entry.name)\r\n if (entry.isDirectory()) {\r\n results.push(...collectSourceFiles(full))\r\n } else if (entry.isFile()) {\r\n const ext = entry.name.split('.').pop()\r\n if (ext === 'ts' || ext === 'tsx' || ext === 'js' || ext === 'jsx' || ext === 'mjs' || ext === 'cjs') {\r\n results.push(full)\r\n }\r\n }\r\n }\r\n } catch {\r\n // skip inaccessible dirs\r\n }\r\n return results\r\n}\r\n\r\nfunction estimateTransitiveCount(lockfile: LockfileData | null, directNames: Set<string>): number {\r\n if (!lockfile) return 0\r\n let count = 0\r\n for (const key of Object.keys(lockfile.packages)) {\r\n if (!key || key === '') continue\r\n const name = key.startsWith('node_modules/') ? key.slice('node_modules/'.length) : key\r\n const rootName = name.startsWith('@') ? `${name.split('/')[0]}/${name.split('/')[1]}` : name.split('/')[0]\r\n if (rootName && !directNames.has(rootName)) {\r\n count++\r\n }\r\n }\r\n return count\r\n}\r\n\r\nfunction parseSize(value: string): number {\r\n const cleaned = value.replace(/\\(.*?\\)/g, '').trim()\r\n const match = cleaned.match(/^([\\d.]+)\\s*(KB|MB)/i)\r\n if (!match) return 0\r\n const num = Number.parseFloat(match[1]!)\r\n if (!match[2]) return 0\r\n if (match[2].toUpperCase() === 'MB') return num * 1024\r\n return num\r\n}\r\n\r\nexport async function scanProject(config: ScannerConfig): Promise<ScanResult> {\r\n const projectPath = config.path ?? '.'\r\n const pkgPath = join(projectPath, 'package.json')\r\n\r\n if (!existsSync(pkgPath)) {\r\n throw new Error(`No package.json found at ${projectPath}. Run dep-exray in a JavaScript/TypeScript project directory.`)\r\n }\r\n\r\n const pkg = parsePackageJson(pkgPath)\r\n const lockfile = parseLockfile(projectPath)\r\n\r\n const allDeps: Record<string, string> = { ...pkg.dependencies, ...pkg.devDependencies }\r\n const directNames = new Set(Object.keys(allDeps))\r\n\r\n const transitiveCount = estimateTransitiveCount(lockfile, directNames)\r\n\r\n const highImpactReplacements: ReplacementSuggestion[] = []\r\n const mediumImpactReplacements: ReplacementSuggestion[] = []\r\n const securityIssues: SecurityIssue[] = []\r\n\r\n const sizeMap: Record<string, string> = {}\r\n for (const m of KNOWN_MAPPINGS) {\r\n sizeMap[m.name] = m.size\r\n }\r\n\r\n for (const mapping of KNOWN_MAPPINGS) {\r\n const isDirect = directNames.has(mapping.name)\r\n if (!isDirect) continue\r\n\r\n const isUsed = detectImportsInSrc(projectPath, mapping)\r\n if (!isUsed && !config.verbose) continue\r\n\r\n const mappingSize = parseSize(sizeMap[mapping.name] ?? '0 KB')\r\n const replacementSize = mapping.replacement.startsWith('native') ? 0 : 5\r\n const reductionStr = mappingSize > 1024\r\n ? `${(mappingSize / 1024).toFixed(1)} MB → ${replacementSize} KB`\r\n : `${mappingSize.toFixed(0)} KB → ${replacementSize} KB`\r\n\r\n const suggestion: ReplacementSuggestion = {\r\n packageName: mapping.name,\r\n reason: mapping.reason,\r\n replacement: mapping.replacement,\r\n estimatedSizeReduction: reductionStr,\r\n confidence: mapping.confidence,\r\n autoPrReady: mapping.autoPrReady,\r\n }\r\n\r\n if (mapping.confidence === 'high') {\r\n highImpactReplacements.push(suggestion)\r\n } else {\r\n mediumImpactReplacements.push(suggestion)\r\n }\r\n }\r\n\r\n for (const [name, cves] of Object.entries(KNOWN_CVES)) {\r\n if (directNames.has(name)) {\r\n for (const cveItem of cves) {\r\n securityIssues.push({\r\n packageName: name,\r\n cveId: cveItem.cve,\r\n severity: cveItem.severity as SecurityIssue['severity'],\r\n fix: cveItem.fix,\r\n })\r\n }\r\n }\r\n }\r\n\r\n let totalSizeKB = 0\r\n for (const depName of directNames) {\r\n const sizeStr = sizeMap[depName]\r\n if (sizeStr) {\r\n totalSizeKB += parseSize(sizeStr)\r\n } else {\r\n totalSizeKB += 50\r\n }\r\n }\r\n totalSizeKB += transitiveCount * 30\r\n\r\n const totalSizeStr = totalSizeKB > 1024\r\n ? `${(totalSizeKB / 1024).toFixed(1)} MB`\r\n : `${totalSizeKB.toFixed(0)} KB`\r\n\r\n return {\r\n projectName: pkg.name,\r\n directDeps: directNames.size,\r\n transitiveDeps: transitiveCount,\r\n totalEstimatedSize: totalSizeStr,\r\n highImpactReplacements,\r\n mediumImpactReplacements,\r\n securityIssues,\r\n }\r\n}\r\n","\r\n\r\nexport interface PackageMapping {\r\n name: string\r\n size: string\r\n replacement: string\r\n confidence: 'high' | 'medium' | 'low'\r\n autoPrReady: boolean\r\n reason: string\r\n detectionPattern: string\r\n}\r\n\r\nexport const KNOWN_MAPPINGS: PackageMapping[] = [\r\n {\r\n name: 'lodash',\r\n size: '4.2 MB',\r\n replacement: 'jscore-core',\r\n confidence: 'high',\r\n autoPrReady: true,\r\n reason: 'Most lodash functions have direct replacements in jscore-core with 99% API compatibility',\r\n detectionPattern: 'from [\\'\"]lodash[\\'\"]|require\\\\([\\'\"]lodash[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'moment',\r\n size: '2.5 MB',\r\n replacement: 'jscore-core/date',\r\n confidence: 'high',\r\n autoPrReady: true,\r\n reason: 'date utilities in jscore-core cover 95% of common moment use cases',\r\n detectionPattern: 'from [\\'\"]moment[\\'\"]|require\\\\([\\'\"]moment[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'date-fns',\r\n size: '1.2 MB (tree-shaked ~50KB)',\r\n replacement: 'jscore-core/date',\r\n confidence: 'medium',\r\n autoPrReady: false,\r\n reason: 'Partially overlapping — jscore-core covers basic date ops but not all locale support',\r\n detectionPattern: 'from [\\'\"]date-fns[\\'\"]|require\\\\([\\'\"]date-fns[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'axios',\r\n size: '1.6 MB',\r\n replacement: 'native fetch + jscore-core/async/retry',\r\n confidence: 'medium',\r\n autoPrReady: false,\r\n reason: 'Native fetch covers most use cases; needs manual review for interceptors',\r\n detectionPattern: 'from [\\'\"]axios[\\'\"]|require\\\\([\\'\"]axios[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'uuid',\r\n size: '30 KB',\r\n replacement: 'crypto.randomUUID() (native)',\r\n confidence: 'high',\r\n autoPrReady: true,\r\n reason: 'crypto.randomUUID() is available in all modern Node.js and browsers',\r\n detectionPattern: 'from [\\'\"]uuid[\\'\"]|require\\\\([\\'\"]uuid[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'deepmerge',\r\n size: '15 KB',\r\n replacement: 'jscore-core',\r\n confidence: 'high',\r\n autoPrReady: true,\r\n reason: 'jscore-core provides deepMerge out of the box',\r\n detectionPattern: 'from [\\'\"]deepmerge[\\'\"]|require\\\\([\\'\"]deepmerge[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'lodash.merge',\r\n size: '25 KB',\r\n replacement: 'jscore-core',\r\n confidence: 'high',\r\n autoPrReady: true,\r\n reason: 'jscore-core provides deepMerge out of the box',\r\n detectionPattern: 'from [\\'\"]lodash\\\\.(merge|clone|pick|omit|get|set)[\\'\"]',\r\n },\r\n {\r\n name: 'chalk',\r\n size: '45 KB',\r\n replacement: 'picocolors',\r\n confidence: 'medium',\r\n autoPrReady: false,\r\n reason: \"picocolors is 3KB vs chalk's 45KB with same API\",\r\n detectionPattern: 'from [\\'\"]chalk[\\'\"]|require\\\\([\\'\"]chalk[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'nanoid',\r\n size: '8 KB',\r\n replacement: 'jscore-core/string (nanoid)',\r\n confidence: 'high',\r\n autoPrReady: true,\r\n reason: 'jscore-core provides nanoid with same API',\r\n detectionPattern: 'from [\\'\"]nanoid[\\'\"]|require\\\\([\\'\"]nanoid[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'dayjs',\r\n size: '50 KB',\r\n replacement: 'jscore-core/date',\r\n confidence: 'medium',\r\n autoPrReady: false,\r\n reason: 'Partially overlapping — covers basics but not all plugins',\r\n detectionPattern: 'from [\\'\"]dayjs[\\'\"]|require\\\\([\\'\"]dayjs[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'clsx',\r\n size: '5 KB',\r\n replacement: 'native template literals',\r\n confidence: 'high',\r\n autoPrReady: true,\r\n reason: 'Can be replaced with simple template literal conditional pattern',\r\n detectionPattern: 'from [\\'\"]clsx[\\'\"]|require\\\\([\\'\"]clsx[\\'\"]\\\\)',\r\n },\r\n]\r\n\r\nexport const KNOWN_CVES: Record<string, { cve: string; severity: string; fix: string }[]> = {\r\n 'ansi-regex': [\r\n { cve: 'CVE-2021-3807', severity: 'high', fix: 'Update to ansi-regex@6.0.1 or later' },\r\n ],\r\n 'semver': [\r\n { cve: 'CVE-2022-25883', severity: 'medium', fix: 'Update to semver@7.5.2 or later' },\r\n ],\r\n 'json5': [\r\n { cve: 'CVE-2022-46175', severity: 'high', fix: 'Update to json5@2.2.3 or later' },\r\n ],\r\n 'lodash': [\r\n { cve: 'CVE-2020-28502', severity: 'high', fix: 'Update to lodash@4.17.21 or later' },\r\n { cve: 'CVE-2020-8203', severity: 'medium', fix: 'Update to lodash@4.17.21 or later' },\r\n ],\r\n}\r\n","import type { ScanResult, ReplacementSuggestion, SecurityIssue } from '../types.js'\n\n// ANSI color codes — zero dependencies\nconst _ = {\n reset: '\\x1b[0m',\n bold: '\\x1b[1m',\n dim: '\\x1b[2m',\n red: '\\x1b[31m',\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n blue: '\\x1b[34m',\n cyan: '\\x1b[36m',\n white: '\\x1b[37m',\n}\n\nfunction style(text: string, codes: string[]): string {\n return codes.join('') + text + _.reset\n}\n\nfunction severityColor(severity: SecurityIssue['severity']): string {\n switch (severity) {\n case 'critical': return style(severity.toUpperCase(), [_.bold, _.red])\n case 'high': return style(severity.toUpperCase(), [_.red])\n case 'medium': return style(severity.toUpperCase(), [_.yellow])\n case 'low': return style(severity.toUpperCase(), [_.dim])\n }\n}\n\nfunction confidenceIcon(confidence: ReplacementSuggestion['confidence']): string {\n switch (confidence) {\n case 'high': return style('●', [_.green])\n case 'medium': return style('●', [_.yellow])\n case 'low': return style('●', [_.red])\n }\n}\n\nexport function generateReport(result: ScanResult, jsonOutput?: boolean): string {\n if (jsonOutput) {\n return JSON.stringify(result, null, 2)\n }\n\n const lines: string[] = []\n\n const t = (text: string, codes: string[] = [_.cyan]) => style(text, [_.bold, ...codes])\n\n lines.push(t(`┌${'─'.repeat(58)}┐`))\n lines.push(t(`│${' '.repeat(18)}dep-exray Report${' '.repeat(21)}│`))\n lines.push(t(`├${'─'.repeat(58)}┤`))\n lines.push(t(`│ ${style('📦 PROJECT:', [_.white])} ${style(result.projectName, [_.bold])}${' '.repeat(Math.max(1, 47 - result.projectName.length))}│`))\n lines.push(t(`│ ${style('📊 DEPENDENCIES:', [_.white])} ${style(String(result.directDeps), [_.bold])} direct + ${style(String(result.transitiveDeps), [_.bold])} transitive${' '.repeat(Math.max(1, 27 - String(result.transitiveDeps).length))}│`))\n lines.push(t(`│ ${style('💾 TOTAL SIZE:', [_.white])} ${style(result.totalEstimatedSize, [_.bold])}${' '.repeat(Math.max(1, 42 - result.totalEstimatedSize.length))}│`))\n lines.push(t(`├${'─'.repeat(58)}┤`))\n\n if (result.highImpactReplacements.length > 0) {\n lines.push(t(`│ ${style('🟢', [_.green])} ${style('HIGH IMPACT REPLACEMENTS', [_.bold, _.green])}${' '.repeat(23)}│`))\n for (const item of result.highImpactReplacements) {\n const autoPr = item.autoPrReady ? style('✓ Auto-PR ready', [_.green]) : style('Manual review needed', [_.dim])\n const confIcon = confidenceIcon(item.confidence)\n lines.push(t(`├${'─'.repeat(58)}┤`))\n lines.push(t(`│ ${style('✗', [_.red])} ${style(item.packageName, [_.bold])} (${item.estimatedSizeReduction})${' '.repeat(Math.max(1, 38 - item.estimatedSizeReduction.length))}│`))\n lines.push(t(`│ ${style('→', [_.dim])} ${style(item.replacement, [_.cyan])}${' '.repeat(Math.max(1, 51 - item.replacement.length))}│`))\n lines.push(t(`│ ${style('└─', [_.dim])} ${autoPr} ${confIcon} ${item.confidence}${' '.repeat(Math.max(1, 35))}│`))\n }\n }\n\n if (result.mediumImpactReplacements.length > 0) {\n lines.push(t(`├${'─'.repeat(58)}┤`))\n lines.push(t(`│ ${style('🟡', [_.yellow])} ${style('MEDIUM IMPACT REPLACEMENTS', [_.bold, _.yellow])}${' '.repeat(20)}│`))\n for (const item of result.mediumImpactReplacements) {\n const autoPr = item.autoPrReady ? style('✓ Auto-PR ready', [_.green]) : style('Manual review needed', [_.dim])\n const confIcon = confidenceIcon(item.confidence)\n lines.push(t(`├${'─'.repeat(58)}┤`))\n lines.push(t(`│ ${style('✗', [_.red])} ${style(item.packageName, [_.bold])} (${item.estimatedSizeReduction})${' '.repeat(Math.max(1, 38 - item.estimatedSizeReduction.length))}│`))\n lines.push(t(`│ ${style('→', [_.dim])} ${style(item.replacement, [_.cyan])}${' '.repeat(Math.max(1, 51 - item.replacement.length))}│`))\n lines.push(t(`│ ${style('└─', [_.dim])} ${autoPr} ${confIcon} ${item.confidence}${' '.repeat(Math.max(1, 35))}│`))\n }\n }\n\n if (result.securityIssues.length > 0) {\n lines.push(t(`├${'─'.repeat(58)}┤`))\n lines.push(t(`│ ${style('🔴', [_.red])} ${style('SECURITY ISSUES', [_.bold, _.red])}${' '.repeat(33)}│`))\n for (const issue of result.securityIssues) {\n lines.push(t(`├${'─'.repeat(58)}┤`))\n lines.push(t(`│ ${severityColor(issue.severity)} ${style(issue.cveId, [_.bold])} in ${issue.packageName}${' '.repeat(Math.max(1, 40 - issue.packageName.length))}│`))\n lines.push(t(`│ ${style('→', [_.dim])} ${issue.fix}${' '.repeat(Math.max(1, 52 - issue.fix.length))}│`))\n }\n }\n\n lines.push(t(`└${'─'.repeat(58)}┘`))\n\n return lines.join('\\n')\n}\n","#!/usr/bin/env node\nimport { scanProject } from './scanner/index.js'\nimport { generateReport } from './reporter/index.js'\n\nfunction parseArgs(args: string[]): { path: string; json: boolean; verbose: boolean; fix: boolean } {\n let path = '.'\n let json = false\n let verbose = false\n let fix = false\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i]!\n if (arg === '--json' || arg === '-j') {\n json = true\n } else if (arg === '--verbose' || arg === '-v') {\n verbose = true\n } else if (arg === '--fix') {\n fix = true\n } else if (!arg.startsWith('-')) {\n path = arg\n }\n }\n\n return { path, json, verbose, fix }\n}\n\nasync function main() {\n const args = process.argv.slice(2)\n\n if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {\n console.log(`\n dep-exray — Dependency Health Scanner\n\n Usage:\n dep-exray [path] [options]\n\n Arguments:\n path Project path to scan (default: .)\n\n Options:\n -j, --json Output as JSON\n -v, --verbose Verbose output\n --fix Auto-generate migration PRs\n -h, --help Show this help\n `)\n process.exit(0)\n }\n\n const { path, json, verbose, fix } = parseArgs(args)\n\n try {\n const result = await scanProject({ path, verbose, jsonOutput: json })\n console.log(generateReport(result, json))\n if (fix) {\n console.log('\\n --fix mode: Auto-PR generation not yet implemented\\n')\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n console.error(`\\n ✖ ${message}\\n`)\n process.exit(1)\n }\n}\n\nmain()\n"],"mappings":"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","names":[]}
@@ -295,27 +295,40 @@ async function scanProject(config) {
295
295
  }
296
296
 
297
297
  // src/dep-exray/reporter/index.ts
298
- import pc from "picocolors";
298
+ var _ = {
299
+ reset: "\x1B[0m",
300
+ bold: "\x1B[1m",
301
+ dim: "\x1B[2m",
302
+ red: "\x1B[31m",
303
+ green: "\x1B[32m",
304
+ yellow: "\x1B[33m",
305
+ blue: "\x1B[34m",
306
+ cyan: "\x1B[36m",
307
+ white: "\x1B[37m"
308
+ };
309
+ function style(text, codes) {
310
+ return codes.join("") + text + _.reset;
311
+ }
299
312
  function severityColor(severity) {
300
313
  switch (severity) {
301
314
  case "critical":
302
- return pc.bold(pc.red(severity.toUpperCase()));
315
+ return style(severity.toUpperCase(), [_.bold, _.red]);
303
316
  case "high":
304
- return pc.red(severity.toUpperCase());
317
+ return style(severity.toUpperCase(), [_.red]);
305
318
  case "medium":
306
- return pc.yellow(severity.toUpperCase());
319
+ return style(severity.toUpperCase(), [_.yellow]);
307
320
  case "low":
308
- return pc.dim(severity.toUpperCase());
321
+ return style(severity.toUpperCase(), [_.dim]);
309
322
  }
310
323
  }
311
324
  function confidenceIcon(confidence) {
312
325
  switch (confidence) {
313
326
  case "high":
314
- return pc.green("\u25CF");
327
+ return style("\u25CF", [_.green]);
315
328
  case "medium":
316
- return pc.yellow("\u25CF");
329
+ return style("\u25CF", [_.yellow]);
317
330
  case "low":
318
- return pc.red("\u25CF");
331
+ return style("\u25CF", [_.red]);
319
332
  }
320
333
  }
321
334
  function generateReport(result, jsonOutput) {
@@ -323,46 +336,47 @@ function generateReport(result, jsonOutput) {
323
336
  return JSON.stringify(result, null, 2);
324
337
  }
325
338
  const lines = [];
326
- lines.push(pc.bold(pc.cyan(`\u250C${"\u2500".repeat(58)}\u2510`)));
327
- lines.push(pc.bold(pc.cyan(`\u2502${" ".repeat(18)}dep-exray Report${" ".repeat(21)}\u2502`)));
328
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
329
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.white("\u{1F4E6} PROJECT:")} ${pc.bold(result.projectName)}${" ".repeat(Math.max(1, 47 - result.projectName.length))}\u2502`)));
330
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.white("\u{1F4CA} DEPENDENCIES:")} ${pc.bold(String(result.directDeps))} direct + ${pc.bold(String(result.transitiveDeps))} transitive${" ".repeat(Math.max(1, 27 - String(result.transitiveDeps).length))}\u2502`)));
331
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.white("\u{1F4BE} TOTAL SIZE:")} ${pc.bold(result.totalEstimatedSize)}${" ".repeat(Math.max(1, 42 - result.totalEstimatedSize.length))}\u2502`)));
332
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
339
+ const t = (text, codes = [_.cyan]) => style(text, [_.bold, ...codes]);
340
+ lines.push(t(`\u250C${"\u2500".repeat(58)}\u2510`));
341
+ lines.push(t(`\u2502${" ".repeat(18)}dep-exray Report${" ".repeat(21)}\u2502`));
342
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
343
+ lines.push(t(`\u2502 ${style("\u{1F4E6} PROJECT:", [_.white])} ${style(result.projectName, [_.bold])}${" ".repeat(Math.max(1, 47 - result.projectName.length))}\u2502`));
344
+ lines.push(t(`\u2502 ${style("\u{1F4CA} DEPENDENCIES:", [_.white])} ${style(String(result.directDeps), [_.bold])} direct + ${style(String(result.transitiveDeps), [_.bold])} transitive${" ".repeat(Math.max(1, 27 - String(result.transitiveDeps).length))}\u2502`));
345
+ lines.push(t(`\u2502 ${style("\u{1F4BE} TOTAL SIZE:", [_.white])} ${style(result.totalEstimatedSize, [_.bold])}${" ".repeat(Math.max(1, 42 - result.totalEstimatedSize.length))}\u2502`));
346
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
333
347
  if (result.highImpactReplacements.length > 0) {
334
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.green("\u{1F7E2}")} ${pc.bold(pc.green("HIGH IMPACT REPLACEMENTS"))}${" ".repeat(23)}\u2502`)));
348
+ lines.push(t(`\u2502 ${style("\u{1F7E2}", [_.green])} ${style("HIGH IMPACT REPLACEMENTS", [_.bold, _.green])}${" ".repeat(23)}\u2502`));
335
349
  for (const item of result.highImpactReplacements) {
336
- const autoPr = item.autoPrReady ? pc.green("\u2713 Auto-PR ready") : pc.dim("Manual review needed");
350
+ const autoPr = item.autoPrReady ? style("\u2713 Auto-PR ready", [_.green]) : style("Manual review needed", [_.dim]);
337
351
  const confIcon = confidenceIcon(item.confidence);
338
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
339
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.red("\u2717")} ${pc.bold(item.packageName)} (${item.estimatedSizeReduction})${" ".repeat(Math.max(1, 38 - item.estimatedSizeReduction.length))}\u2502`)));
340
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.dim("\u2192")} ${pc.cyan(item.replacement)}${" ".repeat(Math.max(1, 51 - item.replacement.length))}\u2502`)));
341
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.dim("\u2514\u2500")} ${autoPr} ${confIcon} ${item.confidence}${" ".repeat(Math.max(1, 35))}\u2502`)));
352
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
353
+ lines.push(t(`\u2502 ${style("\u2717", [_.red])} ${style(item.packageName, [_.bold])} (${item.estimatedSizeReduction})${" ".repeat(Math.max(1, 38 - item.estimatedSizeReduction.length))}\u2502`));
354
+ lines.push(t(`\u2502 ${style("\u2192", [_.dim])} ${style(item.replacement, [_.cyan])}${" ".repeat(Math.max(1, 51 - item.replacement.length))}\u2502`));
355
+ lines.push(t(`\u2502 ${style("\u2514\u2500", [_.dim])} ${autoPr} ${confIcon} ${item.confidence}${" ".repeat(Math.max(1, 35))}\u2502`));
342
356
  }
343
357
  }
344
358
  if (result.mediumImpactReplacements.length > 0) {
345
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
346
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.yellow("\u{1F7E1}")} ${pc.bold(pc.yellow("MEDIUM IMPACT REPLACEMENTS"))}${" ".repeat(20)}\u2502`)));
359
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
360
+ lines.push(t(`\u2502 ${style("\u{1F7E1}", [_.yellow])} ${style("MEDIUM IMPACT REPLACEMENTS", [_.bold, _.yellow])}${" ".repeat(20)}\u2502`));
347
361
  for (const item of result.mediumImpactReplacements) {
348
- const autoPr = item.autoPrReady ? pc.green("\u2713 Auto-PR ready") : pc.dim("Manual review needed");
362
+ const autoPr = item.autoPrReady ? style("\u2713 Auto-PR ready", [_.green]) : style("Manual review needed", [_.dim]);
349
363
  const confIcon = confidenceIcon(item.confidence);
350
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
351
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.red("\u2717")} ${pc.bold(item.packageName)} (${item.estimatedSizeReduction})${" ".repeat(Math.max(1, 38 - item.estimatedSizeReduction.length))}\u2502`)));
352
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.dim("\u2192")} ${pc.cyan(item.replacement)}${" ".repeat(Math.max(1, 51 - item.replacement.length))}\u2502`)));
353
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.dim("\u2514\u2500")} ${autoPr} ${confIcon} ${item.confidence}${" ".repeat(Math.max(1, 35))}\u2502`)));
364
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
365
+ lines.push(t(`\u2502 ${style("\u2717", [_.red])} ${style(item.packageName, [_.bold])} (${item.estimatedSizeReduction})${" ".repeat(Math.max(1, 38 - item.estimatedSizeReduction.length))}\u2502`));
366
+ lines.push(t(`\u2502 ${style("\u2192", [_.dim])} ${style(item.replacement, [_.cyan])}${" ".repeat(Math.max(1, 51 - item.replacement.length))}\u2502`));
367
+ lines.push(t(`\u2502 ${style("\u2514\u2500", [_.dim])} ${autoPr} ${confIcon} ${item.confidence}${" ".repeat(Math.max(1, 35))}\u2502`));
354
368
  }
355
369
  }
356
370
  if (result.securityIssues.length > 0) {
357
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
358
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.red("\u{1F534}")} ${pc.bold(pc.red("SECURITY ISSUES"))}${" ".repeat(33)}\u2502`)));
371
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
372
+ lines.push(t(`\u2502 ${style("\u{1F534}", [_.red])} ${style("SECURITY ISSUES", [_.bold, _.red])}${" ".repeat(33)}\u2502`));
359
373
  for (const issue of result.securityIssues) {
360
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
361
- lines.push(pc.bold(pc.cyan(`\u2502 ${severityColor(issue.severity)} ${pc.bold(issue.cveId)} in ${issue.packageName}${" ".repeat(Math.max(1, 40 - issue.packageName.length))}\u2502`)));
362
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.dim("\u2192")} ${issue.fix}${" ".repeat(Math.max(1, 52 - issue.fix.length))}\u2502`)));
374
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
375
+ lines.push(t(`\u2502 ${severityColor(issue.severity)} ${style(issue.cveId, [_.bold])} in ${issue.packageName}${" ".repeat(Math.max(1, 40 - issue.packageName.length))}\u2502`));
376
+ lines.push(t(`\u2502 ${style("\u2192", [_.dim])} ${issue.fix}${" ".repeat(Math.max(1, 52 - issue.fix.length))}\u2502`));
363
377
  }
364
378
  }
365
- lines.push(pc.bold(pc.cyan(`\u2514${"\u2500".repeat(58)}\u2518`)));
379
+ lines.push(t(`\u2514${"\u2500".repeat(58)}\u2518`));
366
380
  return lines.join("\n");
367
381
  }
368
382