superjs-core 0.5.0 → 0.7.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 +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":";;;AAAA,SAAS,cAAc,aAAa,kBAAkB;AACtD,SAAS,MAAM,gBAAgB;;;ACWxB,IAAM,iBAAmC;AAAA,EAC9C;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AACF;AAEO,IAAM,aAA+E;AAAA,EAC1F,cAAc;AAAA,IACZ,EAAE,KAAK,iBAAiB,UAAU,QAAQ,KAAK,sCAAsC;AAAA,EACvF;AAAA,EACA,UAAU;AAAA,IACR,EAAE,KAAK,kBAAkB,UAAU,UAAU,KAAK,kCAAkC;AAAA,EACtF;AAAA,EACA,SAAS;AAAA,IACP,EAAE,KAAK,kBAAkB,UAAU,QAAQ,KAAK,iCAAiC;AAAA,EACnF;AAAA,EACA,UAAU;AAAA,IACR,EAAE,KAAK,kBAAkB,UAAU,QAAQ,KAAK,oCAAoC;AAAA,IACpF,EAAE,KAAK,iBAAiB,UAAU,UAAU,KAAK,oCAAoC;AAAA,EACvF;AACF;;;ADnHA,SAAS,iBAAiB,MAA+G;AACvI,QAAM,MAAM,aAAa,MAAM,OAAO;AACtC,QAAM,OAAO,KAAK,MAAM,GAAG;AAC3B,SAAO;AAAA,IACL,MAAM,KAAK,QAAQ,SAAS,KAAK,MAAM,IAAI,CAAC;AAAA,IAC5C,cAAe,KAAK,gBAA2C,CAAC;AAAA,IAChE,iBAAkB,KAAK,mBAA8C,CAAC;AAAA,EACxE;AACF;AAEA,SAAS,cAAc,aAA0C;AAC/D,QAAM,WAAW,KAAK,aAAa,mBAAmB;AACtD,MAAI,CAAC,WAAW,QAAQ,EAAG,QAAO;AAClC,MAAI;AACF,UAAM,MAAM,aAAa,UAAU,OAAO;AAC1C,UAAM,OAAO,KAAK,MAAM,GAAG;AAC3B,UAAM,WAA6B,CAAC;AAEpC,QAAI,KAAK,UAAU;AACjB,iBAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,KAAK,QAAgD,GAAG;AAC9F,YAAI,KAAK;AACP,mBAAS,GAAG,IAAI;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AAEA,QAAI,KAAK,gBAAgB,OAAO,KAAK,QAAQ,EAAE,WAAW,GAAG;AAC3D,iBAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,KAAK,YAAuF,GAAG;AACrI,iBAAS,GAAG,IAAI,EAAE,SAAS,IAAI,SAAS,cAAc,IAAI,SAAS;AAAA,MACrE;AAAA,IACF;AAEA,WAAO,EAAE,SAAS;AAAA,EACpB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,mBAAmB,UAAkB,OAAwB;AACpE,MAAI;AACF,UAAM,UAAU,aAAa,UAAU,OAAO;AAC9C,WAAO,MAAM,KAAK,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,mBAAmB,aAAqB,SAAkC;AACjF,QAAM,QAAQ,IAAI,OAAO,QAAQ,gBAAgB;AACjD,QAAM,SAAS,KAAK,aAAa,KAAK;AACtC,MAAI,CAAC,WAAW,MAAM,EAAG,QAAO;AAEhC,MAAI;AACF,UAAM,QAAQ,mBAAmB,MAAM;AACvC,eAAW,QAAQ,OAAO;AACxB,UAAI,mBAAmB,MAAM,KAAK,EAAG,QAAO;AAAA,IAC9C;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,mBAAmB,KAAuB;AACjD,QAAM,UAAoB,CAAC;AAC3B,MAAI;AACF,UAAM,UAAU,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AACxD,eAAW,SAAS,SAAS;AAC3B,UAAI,MAAM,SAAS,kBAAkB,MAAM,SAAS,UAAU,MAAM,SAAS,UAAU,MAAM,SAAS,cAAc,MAAM,SAAS,SAAS;AAC1I;AAAA,MACF;AACA,YAAM,OAAO,KAAK,KAAK,MAAM,IAAI;AACjC,UAAI,MAAM,YAAY,GAAG;AACvB,gBAAQ,KAAK,GAAG,mBAAmB,IAAI,CAAC;AAAA,MAC1C,WAAW,MAAM,OAAO,GAAG;AACzB,cAAM,MAAM,MAAM,KAAK,MAAM,GAAG,EAAE,IAAI;AACtC,YAAI,QAAQ,QAAQ,QAAQ,SAAS,QAAQ,QAAQ,QAAQ,SAAS,QAAQ,SAAS,QAAQ,OAAO;AACpG,kBAAQ,KAAK,IAAI;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAEA,SAAS,wBAAwB,UAA+B,aAAkC;AAChG,MAAI,CAAC,SAAU,QAAO;AACtB,MAAI,QAAQ;AACZ,aAAW,OAAO,OAAO,KAAK,SAAS,QAAQ,GAAG;AAChD,QAAI,CAAC,OAAO,QAAQ,GAAI;AACxB,UAAM,OAAO,IAAI,WAAW,eAAe,IAAI,IAAI,MAAM,gBAAgB,MAAM,IAAI;AACnF,UAAM,WAAW,KAAK,WAAW,GAAG,IAAI,GAAG,KAAK,MAAM,GAAG,EAAE,CAAC,CAAC,IAAI,KAAK,MAAM,GAAG,EAAE,CAAC,CAAC,KAAK,KAAK,MAAM,GAAG,EAAE,CAAC;AACzG,QAAI,YAAY,CAAC,YAAY,IAAI,QAAQ,GAAG;AAC1C;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,UAAU,OAAuB;AACxC,QAAM,UAAU,MAAM,QAAQ,YAAY,EAAE,EAAE,KAAK;AACnD,QAAM,QAAQ,QAAQ,MAAM,sBAAsB;AAClD,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,MAAM,OAAO,WAAW,MAAM,CAAC,CAAE;AACvC,MAAI,CAAC,MAAM,CAAC,EAAG,QAAO;AACtB,MAAI,MAAM,CAAC,EAAE,YAAY,MAAM,KAAM,QAAO,MAAM;AAClD,SAAO;AACT;AAEA,eAAsB,YAAY,QAA4C;AAC5E,QAAM,cAAc,OAAO,QAAQ;AACnC,QAAM,UAAU,KAAK,aAAa,cAAc;AAEhD,MAAI,CAAC,WAAW,OAAO,GAAG;AACxB,UAAM,IAAI,MAAM,4BAA4B,WAAW,+DAA+D;AAAA,EACxH;AAEA,QAAM,MAAM,iBAAiB,OAAO;AACpC,QAAM,WAAW,cAAc,WAAW;AAE1C,QAAM,UAAkC,EAAE,GAAG,IAAI,cAAc,GAAG,IAAI,gBAAgB;AACtF,QAAM,cAAc,IAAI,IAAI,OAAO,KAAK,OAAO,CAAC;AAEhD,QAAM,kBAAkB,wBAAwB,UAAU,WAAW;AAErE,QAAM,yBAAkD,CAAC;AACzD,QAAM,2BAAoD,CAAC;AAC3D,QAAM,iBAAkC,CAAC;AAEzC,QAAM,UAAkC,CAAC;AACzC,aAAW,KAAK,gBAAgB;AAC9B,YAAQ,EAAE,IAAI,IAAI,EAAE;AAAA,EACtB;AAEA,aAAW,WAAW,gBAAgB;AACpC,UAAM,WAAW,YAAY,IAAI,QAAQ,IAAI;AAC7C,QAAI,CAAC,SAAU;AAEf,UAAM,SAAS,mBAAmB,aAAa,OAAO;AACtD,QAAI,CAAC,UAAU,CAAC,OAAO,QAAS;AAEhC,UAAM,cAAc,UAAU,QAAQ,QAAQ,IAAI,KAAK,MAAM;AAC7D,UAAM,kBAAkB,QAAQ,YAAY,WAAW,QAAQ,IAAI,IAAI;AACvE,UAAM,eAAe,cAAc,OAC/B,IAAI,cAAc,MAAM,QAAQ,CAAC,CAAC,cAAS,eAAe,QAC1D,GAAG,YAAY,QAAQ,CAAC,CAAC,cAAS,eAAe;AAErD,UAAM,aAAoC;AAAA,MACxC,aAAa,QAAQ;AAAA,MACrB,QAAQ,QAAQ;AAAA,MAChB,aAAa,QAAQ;AAAA,MACrB,wBAAwB;AAAA,MACxB,YAAY,QAAQ;AAAA,MACpB,aAAa,QAAQ;AAAA,IACvB;AAEA,QAAI,QAAQ,eAAe,QAAQ;AACjC,6BAAuB,KAAK,UAAU;AAAA,IACxC,OAAO;AACL,+BAAyB,KAAK,UAAU;AAAA,IAC1C;AAAA,EACF;AAEA,aAAW,CAAC,MAAM,IAAI,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,QAAI,YAAY,IAAI,IAAI,GAAG;AACzB,iBAAW,WAAW,MAAM;AAC1B,uBAAe,KAAK;AAAA,UAClB,aAAa;AAAA,UACb,OAAO,QAAQ;AAAA,UACf,UAAU,QAAQ;AAAA,UAClB,KAAK,QAAQ;AAAA,QACf,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,MAAI,cAAc;AAClB,aAAW,WAAW,aAAa;AACjC,UAAM,UAAU,QAAQ,OAAO;AAC/B,QAAI,SAAS;AACX,qBAAe,UAAU,OAAO;AAAA,IAClC,OAAO;AACL,qBAAe;AAAA,IACjB;AAAA,EACF;AACA,iBAAe,kBAAkB;AAEjC,QAAM,eAAe,cAAc,OAC/B,IAAI,cAAc,MAAM,QAAQ,CAAC,CAAC,QAClC,GAAG,YAAY,QAAQ,CAAC,CAAC;AAE7B,SAAO;AAAA,IACL,aAAa,IAAI;AAAA,IACjB,YAAY,YAAY;AAAA,IACxB,gBAAgB;AAAA,IAChB,oBAAoB;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AEpNA,IAAM,IAAI;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AACT;AAEA,SAAS,MAAM,MAAc,OAAyB;AACpD,SAAO,MAAM,KAAK,EAAE,IAAI,OAAO,EAAE;AACnC;AAEA,SAAS,cAAc,UAA6C;AAClE,UAAQ,UAAU;AAAA,IAChB,KAAK;AAAY,aAAO,MAAM,SAAS,YAAY,GAAG,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC;AAAA,IACrE,KAAK;AAAQ,aAAO,MAAM,SAAS,YAAY,GAAG,CAAC,EAAE,GAAG,CAAC;AAAA,IACzD,KAAK;AAAU,aAAO,MAAM,SAAS,YAAY,GAAG,CAAC,EAAE,MAAM,CAAC;AAAA,IAC9D,KAAK;AAAO,aAAO,MAAM,SAAS,YAAY,GAAG,CAAC,EAAE,GAAG,CAAC;AAAA,EAC1D;AACF;AAEA,SAAS,eAAe,YAAyD;AAC/E,UAAQ,YAAY;AAAA,IAClB,KAAK;AAAQ,aAAO,MAAM,UAAK,CAAC,EAAE,KAAK,CAAC;AAAA,IACxC,KAAK;AAAU,aAAO,MAAM,UAAK,CAAC,EAAE,MAAM,CAAC;AAAA,IAC3C,KAAK;AAAO,aAAO,MAAM,UAAK,CAAC,EAAE,GAAG,CAAC;AAAA,EACvC;AACF;AAEO,SAAS,eAAe,QAAoB,YAA8B;AAC/E,MAAI,YAAY;AACd,WAAO,KAAK,UAAU,QAAQ,MAAM,CAAC;AAAA,EACvC;AAEA,QAAM,QAAkB,CAAC;AAEzB,QAAM,IAAI,CAAC,MAAc,QAAkB,CAAC,EAAE,IAAI,MAAM,MAAM,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;AAEtF,QAAM,KAAK,EAAE,SAAI,SAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AACnC,QAAM,KAAK,EAAE,SAAI,IAAI,OAAO,EAAE,CAAC,mBAAmB,IAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AACpE,QAAM,KAAK,EAAE,SAAI,SAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AACnC,QAAM,KAAK,EAAE,WAAM,MAAM,sBAAe,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,MAAM,OAAO,aAAa,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,IAAI,OAAO,KAAK,IAAI,GAAG,KAAK,OAAO,YAAY,MAAM,CAAC,CAAC,QAAG,CAAC;AACvJ,QAAM,KAAK,EAAE,WAAM,MAAM,2BAAoB,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,MAAM,OAAO,OAAO,UAAU,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,aAAa,MAAM,OAAO,OAAO,cAAc,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,cAAc,IAAI,OAAO,KAAK,IAAI,GAAG,KAAK,OAAO,OAAO,cAAc,EAAE,MAAM,CAAC,CAAC,QAAG,CAAC;AACpP,QAAM,KAAK,EAAE,WAAM,MAAM,yBAAkB,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,MAAM,OAAO,oBAAoB,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,IAAI,OAAO,KAAK,IAAI,GAAG,KAAK,OAAO,mBAAmB,MAAM,CAAC,CAAC,QAAG,CAAC;AACxK,QAAM,KAAK,EAAE,SAAI,SAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AAEnC,MAAI,OAAO,uBAAuB,SAAS,GAAG;AAC5C,UAAM,KAAK,EAAE,WAAM,MAAM,aAAM,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,MAAM,4BAA4B,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,GAAG,IAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AACtH,eAAW,QAAQ,OAAO,wBAAwB;AAChD,YAAM,SAAS,KAAK,cAAc,MAAM,wBAAmB,CAAC,EAAE,KAAK,CAAC,IAAI,MAAM,wBAAwB,CAAC,EAAE,GAAG,CAAC;AAC7G,YAAM,WAAW,eAAe,KAAK,UAAU;AAC/C,YAAM,KAAK,EAAE,SAAI,SAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AACnC,YAAM,KAAK,EAAE,WAAM,MAAM,UAAK,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,MAAM,KAAK,aAAa,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,sBAAsB,IAAI,IAAI,OAAO,KAAK,IAAI,GAAG,KAAK,KAAK,uBAAuB,MAAM,CAAC,CAAC,QAAG,CAAC;AACnL,YAAM,KAAK,EAAE,WAAM,MAAM,UAAK,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,MAAM,KAAK,aAAa,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,IAAI,OAAO,KAAK,IAAI,GAAG,KAAK,KAAK,YAAY,MAAM,CAAC,CAAC,QAAG,CAAC;AACvI,YAAM,KAAK,EAAE,WAAM,MAAM,gBAAM,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,MAAM,KAAK,QAAQ,IAAI,KAAK,UAAU,GAAG,IAAI,OAAO,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC,QAAG,CAAC;AAAA,IACrH;AAAA,EACF;AAEA,MAAI,OAAO,yBAAyB,SAAS,GAAG;AAC9C,UAAM,KAAK,EAAE,SAAI,SAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AACnC,UAAM,KAAK,EAAE,WAAM,MAAM,aAAM,CAAC,EAAE,MAAM,CAAC,CAAC,IAAI,MAAM,8BAA8B,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,IAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AAC1H,eAAW,QAAQ,OAAO,0BAA0B;AAClD,YAAM,SAAS,KAAK,cAAc,MAAM,wBAAmB,CAAC,EAAE,KAAK,CAAC,IAAI,MAAM,wBAAwB,CAAC,EAAE,GAAG,CAAC;AAC7G,YAAM,WAAW,eAAe,KAAK,UAAU;AAC/C,YAAM,KAAK,EAAE,SAAI,SAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AACnC,YAAM,KAAK,EAAE,WAAM,MAAM,UAAK,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,MAAM,KAAK,aAAa,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,sBAAsB,IAAI,IAAI,OAAO,KAAK,IAAI,GAAG,KAAK,KAAK,uBAAuB,MAAM,CAAC,CAAC,QAAG,CAAC;AACnL,YAAM,KAAK,EAAE,WAAM,MAAM,UAAK,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,MAAM,KAAK,aAAa,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,IAAI,OAAO,KAAK,IAAI,GAAG,KAAK,KAAK,YAAY,MAAM,CAAC,CAAC,QAAG,CAAC;AACvI,YAAM,KAAK,EAAE,WAAM,MAAM,gBAAM,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,MAAM,KAAK,QAAQ,IAAI,KAAK,UAAU,GAAG,IAAI,OAAO,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC,QAAG,CAAC;AAAA,IACrH;AAAA,EACF;AAEA,MAAI,OAAO,eAAe,SAAS,GAAG;AACpC,UAAM,KAAK,EAAE,SAAI,SAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AACnC,UAAM,KAAK,EAAE,WAAM,MAAM,aAAM,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,MAAM,mBAAmB,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AACzG,eAAW,SAAS,OAAO,gBAAgB;AACzC,YAAM,KAAK,EAAE,SAAI,SAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AACnC,YAAM,KAAK,EAAE,WAAM,cAAc,MAAM,QAAQ,CAAC,IAAI,MAAM,MAAM,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC,OAAO,MAAM,WAAW,GAAG,IAAI,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,YAAY,MAAM,CAAC,CAAC,QAAG,CAAC;AACrK,YAAM,KAAK,EAAE,WAAM,MAAM,UAAK,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,MAAM,GAAG,GAAG,IAAI,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,IAAI,MAAM,CAAC,CAAC,QAAG,CAAC;AAAA,IAC1G;AAAA,EACF;AAEA,QAAM,KAAK,EAAE,SAAI,SAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AAEnC,SAAO,MAAM,KAAK,IAAI;AACxB;;;ACvFA,SAAS,UAAU,MAAiF;AAClG,MAAI,OAAO;AACX,MAAI,OAAO;AACX,MAAI,UAAU;AACd,MAAI,MAAM;AAEV,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,MAAM,KAAK,CAAC;AAClB,QAAI,QAAQ,YAAY,QAAQ,MAAM;AACpC,aAAO;AAAA,IACT,WAAW,QAAQ,eAAe,QAAQ,MAAM;AAC9C,gBAAU;AAAA,IACZ,WAAW,QAAQ,SAAS;AAC1B,YAAM;AAAA,IACR,WAAW,CAAC,IAAI,WAAW,GAAG,GAAG;AAC/B,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO,EAAE,MAAM,MAAM,SAAS,IAAI;AACpC;AAEA,eAAe,OAAO;AACpB,QAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AAEjC,MAAI,KAAK,WAAW,KAAK,KAAK,CAAC,MAAM,YAAY,KAAK,CAAC,MAAM,MAAM;AACjE,YAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAcX;AACD,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,EAAE,MAAM,MAAM,SAAS,IAAI,IAAI,UAAU,IAAI;AAEnD,MAAI;AACF,UAAM,SAAS,MAAM,YAAY,EAAE,MAAM,SAAS,YAAY,KAAK,CAAC;AACpE,YAAQ,IAAI,eAAe,QAAQ,IAAI,CAAC;AACxC,QAAI,KAAK;AACP,cAAQ,IAAI,0DAA0D;AAAA,IACxE;AAAA,EACF,SAAS,OAAO;AACd,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,YAAQ,MAAM;AAAA,WAAS,OAAO;AAAA,CAAI;AAClC,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,KAAK;","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
 
@@ -1 +1 @@
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/analyzer/index.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 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","import { readFileSync } from 'node:fs'\r\nimport { readdirSync, statSync } from 'node:fs'\r\nimport { join, extname } from 'node:path'\r\n\r\nconst SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'])\r\n\r\nfunction isSourceFile(file: string): boolean {\r\n return SOURCE_EXTENSIONS.has(extname(file))\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 const fullPath = join(dir, entry.name)\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 if (entry.isDirectory()) {\r\n results.push(...collectSourceFiles(fullPath))\r\n } else if (entry.isFile() && isSourceFile(entry.name)) {\r\n results.push(fullPath)\r\n }\r\n }\r\n } catch {\r\n // skip directories we can't read\r\n }\r\n return results\r\n}\r\n\r\nfunction escapeRegex(str: string): string {\r\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\r\n}\r\n\r\nexport async function analyzeUsage(\r\n projectPath: string,\r\n packageName: string,\r\n): Promise<{\r\n isUsed: boolean\r\n importCount: number\r\n importLocations: string[]\r\n}> {\r\n const importLocations: string[] = []\r\n const escaped = escapeRegex(packageName)\r\n const importRegex = new RegExp(\r\n `(?:from\\\\s+['\"]${escaped}(?:/['\"]|['\"])|require\\\\(\\\\s*['\"]${escaped}(?:/|['\"]))`,\r\n 'g',\r\n )\r\n\r\n const srcDir = join(projectPath, 'src')\r\n let files: string[]\r\n try {\r\n if (statSync(srcDir).isDirectory()) {\r\n files = collectSourceFiles(srcDir)\r\n } else {\r\n files = collectSourceFiles(projectPath)\r\n }\r\n } catch {\r\n files = collectSourceFiles(projectPath)\r\n }\r\n\r\n for (const file of files) {\r\n try {\r\n const content = readFileSync(file, 'utf-8')\r\n importRegex.lastIndex = 0\r\n if (importRegex.test(content)) {\r\n importLocations.push(file)\r\n }\r\n } catch {\r\n // skip unreadable files\r\n }\r\n }\r\n\r\n return {\r\n isUsed: importLocations.length > 0,\r\n importCount: importLocations.length,\r\n importLocations,\r\n }\r\n}\r\n"],"mappings":"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","names":["readFileSync","readdirSync","join","collectSourceFiles"]}
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/analyzer/index.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","import { readFileSync } from 'node:fs'\r\nimport { readdirSync, statSync } from 'node:fs'\r\nimport { join, extname } from 'node:path'\r\n\r\nconst SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'])\r\n\r\nfunction isSourceFile(file: string): boolean {\r\n return SOURCE_EXTENSIONS.has(extname(file))\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 const fullPath = join(dir, entry.name)\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 if (entry.isDirectory()) {\r\n results.push(...collectSourceFiles(fullPath))\r\n } else if (entry.isFile() && isSourceFile(entry.name)) {\r\n results.push(fullPath)\r\n }\r\n }\r\n } catch {\r\n // skip directories we can't read\r\n }\r\n return results\r\n}\r\n\r\nfunction escapeRegex(str: string): string {\r\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\r\n}\r\n\r\nexport async function analyzeUsage(\r\n projectPath: string,\r\n packageName: string,\r\n): Promise<{\r\n isUsed: boolean\r\n importCount: number\r\n importLocations: string[]\r\n}> {\r\n const importLocations: string[] = []\r\n const escaped = escapeRegex(packageName)\r\n const importRegex = new RegExp(\r\n `(?:from\\\\s+['\"]${escaped}(?:/['\"]|['\"])|require\\\\(\\\\s*['\"]${escaped}(?:/|['\"]))`,\r\n 'g',\r\n )\r\n\r\n const srcDir = join(projectPath, 'src')\r\n let files: string[]\r\n try {\r\n if (statSync(srcDir).isDirectory()) {\r\n files = collectSourceFiles(srcDir)\r\n } else {\r\n files = collectSourceFiles(projectPath)\r\n }\r\n } catch {\r\n files = collectSourceFiles(projectPath)\r\n }\r\n\r\n for (const file of files) {\r\n try {\r\n const content = readFileSync(file, 'utf-8')\r\n importRegex.lastIndex = 0\r\n if (importRegex.test(content)) {\r\n importLocations.push(file)\r\n }\r\n } catch {\r\n // skip unreadable files\r\n }\r\n }\r\n\r\n return {\r\n isUsed: importLocations.length > 0,\r\n importCount: importLocations.length,\r\n importLocations,\r\n }\r\n}\r\n"],"mappings":";AAAA,SAAS,cAAc,aAAa,kBAAkB;AACtD,SAAS,MAAM,gBAAgB;;;ACWxB,IAAM,iBAAmC;AAAA,EAC9C;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AACF;AAEO,IAAM,aAA+E;AAAA,EAC1F,cAAc;AAAA,IACZ,EAAE,KAAK,iBAAiB,UAAU,QAAQ,KAAK,sCAAsC;AAAA,EACvF;AAAA,EACA,UAAU;AAAA,IACR,EAAE,KAAK,kBAAkB,UAAU,UAAU,KAAK,kCAAkC;AAAA,EACtF;AAAA,EACA,SAAS;AAAA,IACP,EAAE,KAAK,kBAAkB,UAAU,QAAQ,KAAK,iCAAiC;AAAA,EACnF;AAAA,EACA,UAAU;AAAA,IACR,EAAE,KAAK,kBAAkB,UAAU,QAAQ,KAAK,oCAAoC;AAAA,IACpF,EAAE,KAAK,iBAAiB,UAAU,UAAU,KAAK,oCAAoC;AAAA,EACvF;AACF;;;ADnHA,SAAS,iBAAiB,MAA+G;AACvI,QAAM,MAAM,aAAa,MAAM,OAAO;AACtC,QAAM,OAAO,KAAK,MAAM,GAAG;AAC3B,SAAO;AAAA,IACL,MAAM,KAAK,QAAQ,SAAS,KAAK,MAAM,IAAI,CAAC;AAAA,IAC5C,cAAe,KAAK,gBAA2C,CAAC;AAAA,IAChE,iBAAkB,KAAK,mBAA8C,CAAC;AAAA,EACxE;AACF;AAEA,SAAS,cAAc,aAA0C;AAC/D,QAAM,WAAW,KAAK,aAAa,mBAAmB;AACtD,MAAI,CAAC,WAAW,QAAQ,EAAG,QAAO;AAClC,MAAI;AACF,UAAM,MAAM,aAAa,UAAU,OAAO;AAC1C,UAAM,OAAO,KAAK,MAAM,GAAG;AAC3B,UAAM,WAA6B,CAAC;AAEpC,QAAI,KAAK,UAAU;AACjB,iBAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,KAAK,QAAgD,GAAG;AAC9F,YAAI,KAAK;AACP,mBAAS,GAAG,IAAI;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AAEA,QAAI,KAAK,gBAAgB,OAAO,KAAK,QAAQ,EAAE,WAAW,GAAG;AAC3D,iBAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,KAAK,YAAuF,GAAG;AACrI,iBAAS,GAAG,IAAI,EAAE,SAAS,IAAI,SAAS,cAAc,IAAI,SAAS;AAAA,MACrE;AAAA,IACF;AAEA,WAAO,EAAE,SAAS;AAAA,EACpB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,mBAAmB,UAAkB,OAAwB;AACpE,MAAI;AACF,UAAM,UAAU,aAAa,UAAU,OAAO;AAC9C,WAAO,MAAM,KAAK,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,mBAAmB,aAAqB,SAAkC;AACjF,QAAM,QAAQ,IAAI,OAAO,QAAQ,gBAAgB;AACjD,QAAM,SAAS,KAAK,aAAa,KAAK;AACtC,MAAI,CAAC,WAAW,MAAM,EAAG,QAAO;AAEhC,MAAI;AACF,UAAM,QAAQ,mBAAmB,MAAM;AACvC,eAAW,QAAQ,OAAO;AACxB,UAAI,mBAAmB,MAAM,KAAK,EAAG,QAAO;AAAA,IAC9C;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,mBAAmB,KAAuB;AACjD,QAAM,UAAoB,CAAC;AAC3B,MAAI;AACF,UAAM,UAAU,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AACxD,eAAW,SAAS,SAAS;AAC3B,UAAI,MAAM,SAAS,kBAAkB,MAAM,SAAS,UAAU,MAAM,SAAS,UAAU,MAAM,SAAS,cAAc,MAAM,SAAS,SAAS;AAC1I;AAAA,MACF;AACA,YAAM,OAAO,KAAK,KAAK,MAAM,IAAI;AACjC,UAAI,MAAM,YAAY,GAAG;AACvB,gBAAQ,KAAK,GAAG,mBAAmB,IAAI,CAAC;AAAA,MAC1C,WAAW,MAAM,OAAO,GAAG;AACzB,cAAM,MAAM,MAAM,KAAK,MAAM,GAAG,EAAE,IAAI;AACtC,YAAI,QAAQ,QAAQ,QAAQ,SAAS,QAAQ,QAAQ,QAAQ,SAAS,QAAQ,SAAS,QAAQ,OAAO;AACpG,kBAAQ,KAAK,IAAI;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAEA,SAAS,wBAAwB,UAA+B,aAAkC;AAChG,MAAI,CAAC,SAAU,QAAO;AACtB,MAAI,QAAQ;AACZ,aAAW,OAAO,OAAO,KAAK,SAAS,QAAQ,GAAG;AAChD,QAAI,CAAC,OAAO,QAAQ,GAAI;AACxB,UAAM,OAAO,IAAI,WAAW,eAAe,IAAI,IAAI,MAAM,gBAAgB,MAAM,IAAI;AACnF,UAAM,WAAW,KAAK,WAAW,GAAG,IAAI,GAAG,KAAK,MAAM,GAAG,EAAE,CAAC,CAAC,IAAI,KAAK,MAAM,GAAG,EAAE,CAAC,CAAC,KAAK,KAAK,MAAM,GAAG,EAAE,CAAC;AACzG,QAAI,YAAY,CAAC,YAAY,IAAI,QAAQ,GAAG;AAC1C;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,UAAU,OAAuB;AACxC,QAAM,UAAU,MAAM,QAAQ,YAAY,EAAE,EAAE,KAAK;AACnD,QAAM,QAAQ,QAAQ,MAAM,sBAAsB;AAClD,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,MAAM,OAAO,WAAW,MAAM,CAAC,CAAE;AACvC,MAAI,CAAC,MAAM,CAAC,EAAG,QAAO;AACtB,MAAI,MAAM,CAAC,EAAE,YAAY,MAAM,KAAM,QAAO,MAAM;AAClD,SAAO;AACT;AAEA,eAAsB,YAAY,QAA4C;AAC5E,QAAM,cAAc,OAAO,QAAQ;AACnC,QAAM,UAAU,KAAK,aAAa,cAAc;AAEhD,MAAI,CAAC,WAAW,OAAO,GAAG;AACxB,UAAM,IAAI,MAAM,4BAA4B,WAAW,+DAA+D;AAAA,EACxH;AAEA,QAAM,MAAM,iBAAiB,OAAO;AACpC,QAAM,WAAW,cAAc,WAAW;AAE1C,QAAM,UAAkC,EAAE,GAAG,IAAI,cAAc,GAAG,IAAI,gBAAgB;AACtF,QAAM,cAAc,IAAI,IAAI,OAAO,KAAK,OAAO,CAAC;AAEhD,QAAM,kBAAkB,wBAAwB,UAAU,WAAW;AAErE,QAAM,yBAAkD,CAAC;AACzD,QAAM,2BAAoD,CAAC;AAC3D,QAAM,iBAAkC,CAAC;AAEzC,QAAM,UAAkC,CAAC;AACzC,aAAW,KAAK,gBAAgB;AAC9B,YAAQ,EAAE,IAAI,IAAI,EAAE;AAAA,EACtB;AAEA,aAAW,WAAW,gBAAgB;AACpC,UAAM,WAAW,YAAY,IAAI,QAAQ,IAAI;AAC7C,QAAI,CAAC,SAAU;AAEf,UAAM,SAAS,mBAAmB,aAAa,OAAO;AACtD,QAAI,CAAC,UAAU,CAAC,OAAO,QAAS;AAEhC,UAAM,cAAc,UAAU,QAAQ,QAAQ,IAAI,KAAK,MAAM;AAC7D,UAAM,kBAAkB,QAAQ,YAAY,WAAW,QAAQ,IAAI,IAAI;AACvE,UAAM,eAAe,cAAc,OAC/B,IAAI,cAAc,MAAM,QAAQ,CAAC,CAAC,cAAS,eAAe,QAC1D,GAAG,YAAY,QAAQ,CAAC,CAAC,cAAS,eAAe;AAErD,UAAM,aAAoC;AAAA,MACxC,aAAa,QAAQ;AAAA,MACrB,QAAQ,QAAQ;AAAA,MAChB,aAAa,QAAQ;AAAA,MACrB,wBAAwB;AAAA,MACxB,YAAY,QAAQ;AAAA,MACpB,aAAa,QAAQ;AAAA,IACvB;AAEA,QAAI,QAAQ,eAAe,QAAQ;AACjC,6BAAuB,KAAK,UAAU;AAAA,IACxC,OAAO;AACL,+BAAyB,KAAK,UAAU;AAAA,IAC1C;AAAA,EACF;AAEA,aAAW,CAAC,MAAM,IAAI,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,QAAI,YAAY,IAAI,IAAI,GAAG;AACzB,iBAAW,WAAW,MAAM;AAC1B,uBAAe,KAAK;AAAA,UAClB,aAAa;AAAA,UACb,OAAO,QAAQ;AAAA,UACf,UAAU,QAAQ;AAAA,UAClB,KAAK,QAAQ;AAAA,QACf,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,MAAI,cAAc;AAClB,aAAW,WAAW,aAAa;AACjC,UAAM,UAAU,QAAQ,OAAO;AAC/B,QAAI,SAAS;AACX,qBAAe,UAAU,OAAO;AAAA,IAClC,OAAO;AACL,qBAAe;AAAA,IACjB;AAAA,EACF;AACA,iBAAe,kBAAkB;AAEjC,QAAM,eAAe,cAAc,OAC/B,IAAI,cAAc,MAAM,QAAQ,CAAC,CAAC,QAClC,GAAG,YAAY,QAAQ,CAAC,CAAC;AAE7B,SAAO;AAAA,IACL,aAAa,IAAI;AAAA,IACjB,YAAY,YAAY;AAAA,IACxB,gBAAgB;AAAA,IAChB,oBAAoB;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AEpNA,IAAM,IAAI;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AACT;AAEA,SAAS,MAAM,MAAc,OAAyB;AACpD,SAAO,MAAM,KAAK,EAAE,IAAI,OAAO,EAAE;AACnC;AAEA,SAAS,cAAc,UAA6C;AAClE,UAAQ,UAAU;AAAA,IAChB,KAAK;AAAY,aAAO,MAAM,SAAS,YAAY,GAAG,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC;AAAA,IACrE,KAAK;AAAQ,aAAO,MAAM,SAAS,YAAY,GAAG,CAAC,EAAE,GAAG,CAAC;AAAA,IACzD,KAAK;AAAU,aAAO,MAAM,SAAS,YAAY,GAAG,CAAC,EAAE,MAAM,CAAC;AAAA,IAC9D,KAAK;AAAO,aAAO,MAAM,SAAS,YAAY,GAAG,CAAC,EAAE,GAAG,CAAC;AAAA,EAC1D;AACF;AAEA,SAAS,eAAe,YAAyD;AAC/E,UAAQ,YAAY;AAAA,IAClB,KAAK;AAAQ,aAAO,MAAM,UAAK,CAAC,EAAE,KAAK,CAAC;AAAA,IACxC,KAAK;AAAU,aAAO,MAAM,UAAK,CAAC,EAAE,MAAM,CAAC;AAAA,IAC3C,KAAK;AAAO,aAAO,MAAM,UAAK,CAAC,EAAE,GAAG,CAAC;AAAA,EACvC;AACF;AAEO,SAAS,eAAe,QAAoB,YAA8B;AAC/E,MAAI,YAAY;AACd,WAAO,KAAK,UAAU,QAAQ,MAAM,CAAC;AAAA,EACvC;AAEA,QAAM,QAAkB,CAAC;AAEzB,QAAM,IAAI,CAAC,MAAc,QAAkB,CAAC,EAAE,IAAI,MAAM,MAAM,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;AAEtF,QAAM,KAAK,EAAE,SAAI,SAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AACnC,QAAM,KAAK,EAAE,SAAI,IAAI,OAAO,EAAE,CAAC,mBAAmB,IAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AACpE,QAAM,KAAK,EAAE,SAAI,SAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AACnC,QAAM,KAAK,EAAE,WAAM,MAAM,sBAAe,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,MAAM,OAAO,aAAa,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,IAAI,OAAO,KAAK,IAAI,GAAG,KAAK,OAAO,YAAY,MAAM,CAAC,CAAC,QAAG,CAAC;AACvJ,QAAM,KAAK,EAAE,WAAM,MAAM,2BAAoB,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,MAAM,OAAO,OAAO,UAAU,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,aAAa,MAAM,OAAO,OAAO,cAAc,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,cAAc,IAAI,OAAO,KAAK,IAAI,GAAG,KAAK,OAAO,OAAO,cAAc,EAAE,MAAM,CAAC,CAAC,QAAG,CAAC;AACpP,QAAM,KAAK,EAAE,WAAM,MAAM,yBAAkB,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,MAAM,OAAO,oBAAoB,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,IAAI,OAAO,KAAK,IAAI,GAAG,KAAK,OAAO,mBAAmB,MAAM,CAAC,CAAC,QAAG,CAAC;AACxK,QAAM,KAAK,EAAE,SAAI,SAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AAEnC,MAAI,OAAO,uBAAuB,SAAS,GAAG;AAC5C,UAAM,KAAK,EAAE,WAAM,MAAM,aAAM,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,MAAM,4BAA4B,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,GAAG,IAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AACtH,eAAW,QAAQ,OAAO,wBAAwB;AAChD,YAAM,SAAS,KAAK,cAAc,MAAM,wBAAmB,CAAC,EAAE,KAAK,CAAC,IAAI,MAAM,wBAAwB,CAAC,EAAE,GAAG,CAAC;AAC7G,YAAM,WAAW,eAAe,KAAK,UAAU;AAC/C,YAAM,KAAK,EAAE,SAAI,SAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AACnC,YAAM,KAAK,EAAE,WAAM,MAAM,UAAK,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,MAAM,KAAK,aAAa,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,sBAAsB,IAAI,IAAI,OAAO,KAAK,IAAI,GAAG,KAAK,KAAK,uBAAuB,MAAM,CAAC,CAAC,QAAG,CAAC;AACnL,YAAM,KAAK,EAAE,WAAM,MAAM,UAAK,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,MAAM,KAAK,aAAa,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,IAAI,OAAO,KAAK,IAAI,GAAG,KAAK,KAAK,YAAY,MAAM,CAAC,CAAC,QAAG,CAAC;AACvI,YAAM,KAAK,EAAE,WAAM,MAAM,gBAAM,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,MAAM,KAAK,QAAQ,IAAI,KAAK,UAAU,GAAG,IAAI,OAAO,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC,QAAG,CAAC;AAAA,IACrH;AAAA,EACF;AAEA,MAAI,OAAO,yBAAyB,SAAS,GAAG;AAC9C,UAAM,KAAK,EAAE,SAAI,SAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AACnC,UAAM,KAAK,EAAE,WAAM,MAAM,aAAM,CAAC,EAAE,MAAM,CAAC,CAAC,IAAI,MAAM,8BAA8B,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,IAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AAC1H,eAAW,QAAQ,OAAO,0BAA0B;AAClD,YAAM,SAAS,KAAK,cAAc,MAAM,wBAAmB,CAAC,EAAE,KAAK,CAAC,IAAI,MAAM,wBAAwB,CAAC,EAAE,GAAG,CAAC;AAC7G,YAAM,WAAW,eAAe,KAAK,UAAU;AAC/C,YAAM,KAAK,EAAE,SAAI,SAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AACnC,YAAM,KAAK,EAAE,WAAM,MAAM,UAAK,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,MAAM,KAAK,aAAa,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,sBAAsB,IAAI,IAAI,OAAO,KAAK,IAAI,GAAG,KAAK,KAAK,uBAAuB,MAAM,CAAC,CAAC,QAAG,CAAC;AACnL,YAAM,KAAK,EAAE,WAAM,MAAM,UAAK,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,MAAM,KAAK,aAAa,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,IAAI,OAAO,KAAK,IAAI,GAAG,KAAK,KAAK,YAAY,MAAM,CAAC,CAAC,QAAG,CAAC;AACvI,YAAM,KAAK,EAAE,WAAM,MAAM,gBAAM,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,MAAM,KAAK,QAAQ,IAAI,KAAK,UAAU,GAAG,IAAI,OAAO,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC,QAAG,CAAC;AAAA,IACrH;AAAA,EACF;AAEA,MAAI,OAAO,eAAe,SAAS,GAAG;AACpC,UAAM,KAAK,EAAE,SAAI,SAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AACnC,UAAM,KAAK,EAAE,WAAM,MAAM,aAAM,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,MAAM,mBAAmB,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AACzG,eAAW,SAAS,OAAO,gBAAgB;AACzC,YAAM,KAAK,EAAE,SAAI,SAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AACnC,YAAM,KAAK,EAAE,WAAM,cAAc,MAAM,QAAQ,CAAC,IAAI,MAAM,MAAM,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC,OAAO,MAAM,WAAW,GAAG,IAAI,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,YAAY,MAAM,CAAC,CAAC,QAAG,CAAC;AACrK,YAAM,KAAK,EAAE,WAAM,MAAM,UAAK,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,MAAM,GAAG,GAAG,IAAI,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,IAAI,MAAM,CAAC,CAAC,QAAG,CAAC;AAAA,IAC1G;AAAA,EACF;AAEA,QAAM,KAAK,EAAE,SAAI,SAAI,OAAO,EAAE,CAAC,QAAG,CAAC;AAEnC,SAAO,MAAM,KAAK,IAAI;AACxB;;;AC3FA,SAAS,gBAAAA,qBAAoB;AAC7B,SAAS,eAAAC,cAAa,gBAAgB;AACtC,SAAS,QAAAC,OAAM,eAAe;AAE9B,IAAM,oBAAoB,oBAAI,IAAI,CAAC,OAAO,QAAQ,OAAO,QAAQ,QAAQ,MAAM,CAAC;AAEhF,SAAS,aAAa,MAAuB;AAC3C,SAAO,kBAAkB,IAAI,QAAQ,IAAI,CAAC;AAC5C;AAEA,SAASC,oBAAmB,KAAuB;AACjD,QAAM,UAAoB,CAAC;AAC3B,MAAI;AACF,UAAM,UAAUF,aAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AACxD,eAAW,SAAS,SAAS;AAC3B,YAAM,WAAWC,MAAK,KAAK,MAAM,IAAI;AACrC,UAAI,MAAM,SAAS,kBAAkB,MAAM,SAAS,UAAU,MAAM,SAAS,UAAU,MAAM,SAAS,cAAc,MAAM,SAAS,SAAS;AAC1I;AAAA,MACF;AACA,UAAI,MAAM,YAAY,GAAG;AACvB,gBAAQ,KAAK,GAAGC,oBAAmB,QAAQ,CAAC;AAAA,MAC9C,WAAW,MAAM,OAAO,KAAK,aAAa,MAAM,IAAI,GAAG;AACrD,gBAAQ,KAAK,QAAQ;AAAA,MACvB;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAEA,SAAS,YAAY,KAAqB;AACxC,SAAO,IAAI,QAAQ,uBAAuB,MAAM;AAClD;AAEA,eAAsB,aACpB,aACA,aAKC;AACD,QAAM,kBAA4B,CAAC;AACnC,QAAM,UAAU,YAAY,WAAW;AACvC,QAAM,cAAc,IAAI;AAAA,IACtB,kBAAkB,OAAO,oCAAoC,OAAO;AAAA,IACpE;AAAA,EACF;AAEA,QAAM,SAASD,MAAK,aAAa,KAAK;AACtC,MAAI;AACJ,MAAI;AACF,QAAI,SAAS,MAAM,EAAE,YAAY,GAAG;AAClC,cAAQC,oBAAmB,MAAM;AAAA,IACnC,OAAO;AACL,cAAQA,oBAAmB,WAAW;AAAA,IACxC;AAAA,EACF,QAAQ;AACN,YAAQA,oBAAmB,WAAW;AAAA,EACxC;AAEA,aAAW,QAAQ,OAAO;AACxB,QAAI;AACF,YAAM,UAAUH,cAAa,MAAM,OAAO;AAC1C,kBAAY,YAAY;AACxB,UAAI,YAAY,KAAK,OAAO,GAAG;AAC7B,wBAAgB,KAAK,IAAI;AAAA,MAC3B;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO;AAAA,IACL,QAAQ,gBAAgB,SAAS;AAAA,IACjC,aAAa,gBAAgB;AAAA,IAC7B;AAAA,EACF;AACF;","names":["readFileSync","readdirSync","join","collectSourceFiles"]}
@@ -1,25 +1,38 @@
1
1
  // src/dep-exray/reporter/index.ts
2
- import pc from "picocolors";
2
+ var _ = {
3
+ reset: "\x1B[0m",
4
+ bold: "\x1B[1m",
5
+ dim: "\x1B[2m",
6
+ red: "\x1B[31m",
7
+ green: "\x1B[32m",
8
+ yellow: "\x1B[33m",
9
+ blue: "\x1B[34m",
10
+ cyan: "\x1B[36m",
11
+ white: "\x1B[37m"
12
+ };
13
+ function style(text, codes) {
14
+ return codes.join("") + text + _.reset;
15
+ }
3
16
  function severityColor(severity) {
4
17
  switch (severity) {
5
18
  case "critical":
6
- return pc.bold(pc.red(severity.toUpperCase()));
19
+ return style(severity.toUpperCase(), [_.bold, _.red]);
7
20
  case "high":
8
- return pc.red(severity.toUpperCase());
21
+ return style(severity.toUpperCase(), [_.red]);
9
22
  case "medium":
10
- return pc.yellow(severity.toUpperCase());
23
+ return style(severity.toUpperCase(), [_.yellow]);
11
24
  case "low":
12
- return pc.dim(severity.toUpperCase());
25
+ return style(severity.toUpperCase(), [_.dim]);
13
26
  }
14
27
  }
15
28
  function confidenceIcon(confidence) {
16
29
  switch (confidence) {
17
30
  case "high":
18
- return pc.green("\u25CF");
31
+ return style("\u25CF", [_.green]);
19
32
  case "medium":
20
- return pc.yellow("\u25CF");
33
+ return style("\u25CF", [_.yellow]);
21
34
  case "low":
22
- return pc.red("\u25CF");
35
+ return style("\u25CF", [_.red]);
23
36
  }
24
37
  }
25
38
  function generateReport(result, jsonOutput) {
@@ -27,46 +40,47 @@ function generateReport(result, jsonOutput) {
27
40
  return JSON.stringify(result, null, 2);
28
41
  }
29
42
  const lines = [];
30
- lines.push(pc.bold(pc.cyan(`\u250C${"\u2500".repeat(58)}\u2510`)));
31
- lines.push(pc.bold(pc.cyan(`\u2502${" ".repeat(18)}dep-exray Report${" ".repeat(21)}\u2502`)));
32
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
33
- 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`)));
34
- 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`)));
35
- 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`)));
36
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
43
+ const t = (text, codes = [_.cyan]) => style(text, [_.bold, ...codes]);
44
+ lines.push(t(`\u250C${"\u2500".repeat(58)}\u2510`));
45
+ lines.push(t(`\u2502${" ".repeat(18)}dep-exray Report${" ".repeat(21)}\u2502`));
46
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
47
+ lines.push(t(`\u2502 ${style("\u{1F4E6} PROJECT:", [_.white])} ${style(result.projectName, [_.bold])}${" ".repeat(Math.max(1, 47 - result.projectName.length))}\u2502`));
48
+ 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`));
49
+ lines.push(t(`\u2502 ${style("\u{1F4BE} TOTAL SIZE:", [_.white])} ${style(result.totalEstimatedSize, [_.bold])}${" ".repeat(Math.max(1, 42 - result.totalEstimatedSize.length))}\u2502`));
50
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
37
51
  if (result.highImpactReplacements.length > 0) {
38
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.green("\u{1F7E2}")} ${pc.bold(pc.green("HIGH IMPACT REPLACEMENTS"))}${" ".repeat(23)}\u2502`)));
52
+ lines.push(t(`\u2502 ${style("\u{1F7E2}", [_.green])} ${style("HIGH IMPACT REPLACEMENTS", [_.bold, _.green])}${" ".repeat(23)}\u2502`));
39
53
  for (const item of result.highImpactReplacements) {
40
- const autoPr = item.autoPrReady ? pc.green("\u2713 Auto-PR ready") : pc.dim("Manual review needed");
54
+ const autoPr = item.autoPrReady ? style("\u2713 Auto-PR ready", [_.green]) : style("Manual review needed", [_.dim]);
41
55
  const confIcon = confidenceIcon(item.confidence);
42
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
43
- 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`)));
44
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.dim("\u2192")} ${pc.cyan(item.replacement)}${" ".repeat(Math.max(1, 51 - item.replacement.length))}\u2502`)));
45
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.dim("\u2514\u2500")} ${autoPr} ${confIcon} ${item.confidence}${" ".repeat(Math.max(1, 35))}\u2502`)));
56
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
57
+ lines.push(t(`\u2502 ${style("\u2717", [_.red])} ${style(item.packageName, [_.bold])} (${item.estimatedSizeReduction})${" ".repeat(Math.max(1, 38 - item.estimatedSizeReduction.length))}\u2502`));
58
+ lines.push(t(`\u2502 ${style("\u2192", [_.dim])} ${style(item.replacement, [_.cyan])}${" ".repeat(Math.max(1, 51 - item.replacement.length))}\u2502`));
59
+ lines.push(t(`\u2502 ${style("\u2514\u2500", [_.dim])} ${autoPr} ${confIcon} ${item.confidence}${" ".repeat(Math.max(1, 35))}\u2502`));
46
60
  }
47
61
  }
48
62
  if (result.mediumImpactReplacements.length > 0) {
49
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
50
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.yellow("\u{1F7E1}")} ${pc.bold(pc.yellow("MEDIUM IMPACT REPLACEMENTS"))}${" ".repeat(20)}\u2502`)));
63
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
64
+ lines.push(t(`\u2502 ${style("\u{1F7E1}", [_.yellow])} ${style("MEDIUM IMPACT REPLACEMENTS", [_.bold, _.yellow])}${" ".repeat(20)}\u2502`));
51
65
  for (const item of result.mediumImpactReplacements) {
52
- const autoPr = item.autoPrReady ? pc.green("\u2713 Auto-PR ready") : pc.dim("Manual review needed");
66
+ const autoPr = item.autoPrReady ? style("\u2713 Auto-PR ready", [_.green]) : style("Manual review needed", [_.dim]);
53
67
  const confIcon = confidenceIcon(item.confidence);
54
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
55
- 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`)));
56
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.dim("\u2192")} ${pc.cyan(item.replacement)}${" ".repeat(Math.max(1, 51 - item.replacement.length))}\u2502`)));
57
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.dim("\u2514\u2500")} ${autoPr} ${confIcon} ${item.confidence}${" ".repeat(Math.max(1, 35))}\u2502`)));
68
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
69
+ lines.push(t(`\u2502 ${style("\u2717", [_.red])} ${style(item.packageName, [_.bold])} (${item.estimatedSizeReduction})${" ".repeat(Math.max(1, 38 - item.estimatedSizeReduction.length))}\u2502`));
70
+ lines.push(t(`\u2502 ${style("\u2192", [_.dim])} ${style(item.replacement, [_.cyan])}${" ".repeat(Math.max(1, 51 - item.replacement.length))}\u2502`));
71
+ lines.push(t(`\u2502 ${style("\u2514\u2500", [_.dim])} ${autoPr} ${confIcon} ${item.confidence}${" ".repeat(Math.max(1, 35))}\u2502`));
58
72
  }
59
73
  }
60
74
  if (result.securityIssues.length > 0) {
61
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
62
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.red("\u{1F534}")} ${pc.bold(pc.red("SECURITY ISSUES"))}${" ".repeat(33)}\u2502`)));
75
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
76
+ lines.push(t(`\u2502 ${style("\u{1F534}", [_.red])} ${style("SECURITY ISSUES", [_.bold, _.red])}${" ".repeat(33)}\u2502`));
63
77
  for (const issue of result.securityIssues) {
64
- lines.push(pc.bold(pc.cyan(`\u251C${"\u2500".repeat(58)}\u2524`)));
65
- 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`)));
66
- lines.push(pc.bold(pc.cyan(`\u2502 ${pc.dim("\u2192")} ${issue.fix}${" ".repeat(Math.max(1, 52 - issue.fix.length))}\u2502`)));
78
+ lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
79
+ lines.push(t(`\u2502 ${severityColor(issue.severity)} ${style(issue.cveId, [_.bold])} in ${issue.packageName}${" ".repeat(Math.max(1, 40 - issue.packageName.length))}\u2502`));
80
+ lines.push(t(`\u2502 ${style("\u2192", [_.dim])} ${issue.fix}${" ".repeat(Math.max(1, 52 - issue.fix.length))}\u2502`));
67
81
  }
68
82
  }
69
- lines.push(pc.bold(pc.cyan(`\u2514${"\u2500".repeat(58)}\u2518`)));
83
+ lines.push(t(`\u2514${"\u2500".repeat(58)}\u2518`));
70
84
  return lines.join("\n");
71
85
  }
72
86
  export {