backend-diet 1.0.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.

Potentially problematic release.


This version of backend-diet might be problematic. Click here for more details.

@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts","../src/scanner/walker.ts","../src/scanner/parser.ts","../src/database/packs/lodash.ts","../src/database/packs/moment.ts","../src/database/packs/axios.ts","../src/database/packs/uuid.ts","../src/database/packs/bluebird.ts","../src/database/packs/underscore.ts","../src/database/index.ts","../src/scorer.ts","../src/reporter/terminal.ts","../src/reporter/json.ts","../src/patcher.ts","../src/badger.ts","../src/time-machine.ts"],"sourcesContent":["import { Command } from 'commander';\r\nimport ora from 'ora';\r\nimport path from 'path';\r\nimport chalk from 'chalk';\r\nimport { walkFiles } from './scanner/walker.js';\r\nimport { parseFiles } from './scanner/parser.js';\r\nimport { matchImports } from './database/index.js';\r\nimport { buildScanResult } from './scorer.js';\r\nimport {\r\n printHeader,\r\n printScoreCard,\r\n printMatchesTable,\r\n printSuggestions,\r\n printFooter,\r\n printError,\r\n printInfo,\r\n printTimeMachine,\r\n printPatchPreview,\r\n} from './reporter/terminal.js';\r\nimport { printJsonReport } from './reporter/json.js';\r\nimport { computePatches, applyPatches } from './patcher.js';\r\nimport { printBadge } from './badger.js';\r\nimport { recordScanResult, getHistory, analyzeTimeMachineTrend } from './time-machine.js';\r\n\r\nconst VERSION = '1.0.0';\r\n\r\ninterface ScanOptions {\r\n fix?: boolean;\r\n yes?: boolean;\r\n badge?: boolean;\r\n since?: string;\r\n format: string;\r\n ignore?: string[];\r\n noHeader?: boolean;\r\n}\r\n\r\nasync function runScan(directory: string | undefined, options: ScanOptions): Promise<void> {\r\n const targetDir = path.resolve(directory ?? process.cwd());\r\n const isJson = options.format === 'json';\r\n\r\n if (!isJson && !options.noHeader) {\r\n printHeader();\r\n }\r\n\r\n const spinner = isJson ? null : ora({ text: 'Scanning files…', color: 'cyan' }).start();\r\n\r\n try {\r\n const startMs = Date.now();\r\n\r\n // 1. Walk files\r\n const files = await walkFiles(targetDir, options.ignore ?? []);\r\n\r\n if (spinner) spinner.text = `Parsing ${files.length} files…`;\r\n\r\n // 2. Parse AST\r\n const imports = await parseFiles(files);\r\n\r\n if (spinner) spinner.text = 'Matching against diet database…';\r\n\r\n // 3. Match against database\r\n const matches = matchImports(imports);\r\n\r\n const scanDurationMs = Date.now() - startMs;\r\n\r\n // 4. Build result\r\n const result = buildScanResult(targetDir, files.length, imports, matches, scanDurationMs);\r\n\r\n if (spinner) spinner.succeed(chalk.green(`Scanned ${files.length} files in ${scanDurationMs}ms`));\r\n\r\n // 5. Record to history\r\n recordScanResult(result, targetDir);\r\n\r\n // 6. Output\r\n if (isJson) {\r\n printJsonReport(result);\r\n return;\r\n }\r\n\r\n printScoreCard(result);\r\n printMatchesTable(matches);\r\n\r\n if (matches.length > 0) {\r\n printSuggestions(matches);\r\n }\r\n\r\n // 7. Time Machine\r\n if (options.since) {\r\n printInfo('Time Machine: comparing score trend…');\r\n const history = getHistory(targetDir);\r\n analyzeTimeMachineTrend(history, result.refactorScore);\r\n\r\n printTimeMachine(\r\n history.map((h) => ({\r\n timestamp: h.timestamp,\r\n score: h.score,\r\n gitRef: h.gitRef,\r\n grade: h.grade,\r\n })),\r\n result.refactorScore\r\n );\r\n }\r\n\r\n // 8. Badge\r\n if (options.badge) {\r\n printBadge(result.refactorScore, result.grade);\r\n }\r\n\r\n // 9. Auto-patch\r\n if (options.fix) {\r\n const patches = computePatches(matches, targetDir);\r\n\r\n if (patches.length === 0) {\r\n printInfo('No trivial patches available for automatic rewriting.');\r\n } else {\r\n console.log(\r\n chalk.bold.white(\r\n `\\n AUTO-PATCH PREVIEW (${patches.length} trivial replacement${patches.length === 1 ? '' : 's'})\\n`\r\n )\r\n );\r\n\r\n for (const patch of patches) {\r\n printPatchPreview(patch.file, patch.before, patch.after);\r\n }\r\n\r\n if (options.yes) {\r\n const applied = applyPatches(patches, targetDir);\r\n console.log(\r\n chalk.green(`\\n ✓ Applied ${applied.length} patch${applied.length === 1 ? '' : 'es'} successfully.\\n`)\r\n );\r\n } else {\r\n console.log(chalk.dim(' Add --yes to apply these patches in-place.\\n'));\r\n }\r\n }\r\n }\r\n\r\n printFooter(result, !!options.fix && !options.yes);\r\n\r\n // Exit with non-zero code if score is CRITICAL (useful for CI)\r\n if (result.grade === 'CRITICAL') {\r\n process.exit(1);\r\n }\r\n } catch (err) {\r\n if (spinner) spinner.fail('Scan failed');\r\n printError(err instanceof Error ? err.message : String(err));\r\n process.exit(1);\r\n }\r\n}\r\n\r\n// ─── CLI Definition ───────────────────────────────────────────────────────────\r\nconst program = new Command();\r\n\r\nprogram\r\n .name('backend-diet')\r\n .version(VERSION, '-v, --version')\r\n .description('Put your project on a diet. Find heavy packages, get native alternatives.')\r\n .helpOption('-h, --help', 'Display help');\r\n\r\nprogram\r\n .command('scan [directory]', { isDefault: true })\r\n .description('Scan source files for heavy library usage and suggest native alternatives')\r\n .option('--fix', 'Preview trivial auto-patches (dry run by default)')\r\n .option('--yes', 'Apply --fix patches in-place (requires --fix)')\r\n .option('--badge', 'Print a Shields.io badge for your README')\r\n .option('--since <ref>', 'Show score trend since a git ref (e.g. HEAD~10)')\r\n .option('--format <fmt>', 'Output format: terminal | json', 'terminal')\r\n .option('--ignore <patterns...>', 'Glob patterns to ignore (e.g. \"vendor/**\")')\r\n .option('--no-header', 'Suppress the ASCII art header')\r\n .action(async (directory: string | undefined, options: {\r\n fix?: boolean;\r\n yes?: boolean;\r\n badge?: boolean;\r\n since?: string;\r\n format: string;\r\n ignore?: string[];\r\n header: boolean;\r\n }) => {\r\n await runScan(directory, {\r\n ...options,\r\n noHeader: !options.header,\r\n });\r\n });\r\n\r\nprogram.parse(process.argv);\r\n","import fg from 'fast-glob';\r\nimport path from 'path';\r\n\r\nconst SOURCE_EXTENSIONS = ['js', 'ts', 'jsx', 'tsx', 'mjs', 'cjs'];\r\n\r\nconst DEFAULT_IGNORE = [\r\n '**/node_modules/**',\r\n '**/dist/**',\r\n '**/build/**',\r\n '**/.next/**',\r\n '**/.nuxt/**',\r\n '**/coverage/**',\r\n '**/*.min.js',\r\n '**/*.bundle.js',\r\n];\r\n\r\nexport async function walkFiles(\r\n targetDir: string,\r\n extraIgnore: string[] = []\r\n): Promise<string[]> {\r\n const pattern = `**/*.{${SOURCE_EXTENSIONS.join(',')}}`;\r\n const ignore = [...DEFAULT_IGNORE, ...extraIgnore];\r\n\r\n const files = await fg(pattern, {\r\n cwd: path.resolve(targetDir),\r\n absolute: true,\r\n ignore,\r\n followSymbolicLinks: false,\r\n onlyFiles: true,\r\n });\r\n\r\n return files.sort();\r\n}\r\n","import * as babelParser from '@babel/parser';\r\nimport traverse from '@babel/traverse';\r\nimport * as t from '@babel/types';\r\nimport fs from 'fs';\r\nimport path from 'path';\r\nimport type { ImportRecord } from '../types.js';\r\n\r\nconst BABEL_PLUGINS: babelParser.ParserPlugin[] = [\r\n 'typescript',\r\n 'jsx',\r\n ['decorators', { decoratorsBeforeExport: true }],\r\n 'classProperties',\r\n 'classPrivateProperties',\r\n 'classPrivateMethods',\r\n 'exportDefaultFrom',\r\n 'exportNamespaceFrom',\r\n 'dynamicImport',\r\n 'nullishCoalescingOperator',\r\n 'optionalChaining',\r\n 'optionalCatchBinding',\r\n 'logicalAssignment',\r\n 'numericSeparator',\r\n 'bigInt',\r\n 'importMeta',\r\n];\r\n\r\nfunction safeParseCode(code: string): ReturnType<typeof babelParser.parse> | null {\r\n try {\r\n return babelParser.parse(code, {\r\n sourceType: 'module',\r\n allowImportExportEverywhere: true,\r\n allowReturnOutsideFunction: true,\r\n allowSuperOutsideMethod: true,\r\n plugins: BABEL_PLUGINS,\r\n errorRecovery: true,\r\n });\r\n } catch {\r\n try {\r\n return babelParser.parse(code, {\r\n sourceType: 'script',\r\n allowImportExportEverywhere: true,\r\n allowReturnOutsideFunction: true,\r\n plugins: ['jsx', 'classProperties'],\r\n errorRecovery: true,\r\n });\r\n } catch {\r\n return null;\r\n }\r\n }\r\n}\r\n\r\nfunction normalizePackageName(source: string): string {\r\n // \"lodash/cloneDeep\" → \"lodash\"\r\n // \"@scope/pkg/sub\" → \"@scope/pkg\"\r\n if (source.startsWith('@')) {\r\n const parts = source.split('/');\r\n return parts.slice(0, 2).join('/');\r\n }\r\n return source.split('/')[0];\r\n}\r\n\r\nfunction getSubPath(source: string): string | null {\r\n // \"lodash/cloneDeep\" → \"cloneDeep\"\r\n const parts = source.split('/');\r\n if (source.startsWith('@') && parts.length > 2) {\r\n return parts.slice(2).join('/');\r\n }\r\n if (!source.startsWith('@') && parts.length > 1) {\r\n return parts.slice(1).join('/');\r\n }\r\n return null;\r\n}\r\n\r\nexport function parseFile(filePath: string): ImportRecord[] {\r\n const records: ImportRecord[] = [];\r\n let code: string;\r\n\r\n try {\r\n code = fs.readFileSync(filePath, 'utf-8');\r\n } catch {\r\n return records;\r\n }\r\n\r\n const ast = safeParseCode(code);\r\n if (!ast) return records;\r\n\r\n const relPath = path.relative(process.cwd(), filePath);\r\n\r\n traverse(ast, {\r\n // Pattern 1: import { cloneDeep, merge } from 'lodash'\r\n // Pattern 2: import cloneDeep from 'lodash/cloneDeep'\r\n ImportDeclaration(nodePath) {\r\n const source = nodePath.node.source.value;\r\n if (!isThirdParty(source)) return;\r\n\r\n const packageName = normalizePackageName(source);\r\n const subPath = getSubPath(source);\r\n const line = nodePath.node.loc?.start.line ?? 0;\r\n const col = nodePath.node.loc?.start.column ?? 0;\r\n const raw = code.split('\\n')[line - 1]?.trim() ?? '';\r\n\r\n for (const specifier of nodePath.node.specifiers) {\r\n let functionName: string;\r\n\r\n if (t.isImportSpecifier(specifier)) {\r\n // import { cloneDeep as cd } from 'lodash'\r\n functionName = t.isIdentifier(specifier.imported)\r\n ? specifier.imported.name\r\n : specifier.imported.value;\r\n } else if (t.isImportDefaultSpecifier(specifier)) {\r\n // import cloneDeep from 'lodash/cloneDeep'\r\n functionName = subPath ?? specifier.local.name;\r\n } else if (t.isImportNamespaceSpecifier(specifier)) {\r\n // import * as _ from 'lodash' — record the namespace\r\n functionName = '*';\r\n } else {\r\n continue;\r\n }\r\n\r\n records.push({ file: relPath, packageName, functionName, line, col, raw });\r\n }\r\n },\r\n\r\n // Pattern 3: const { cloneDeep } = require('lodash')\r\n VariableDeclarator(nodePath) {\r\n const init = nodePath.node.init;\r\n if (!t.isCallExpression(init)) return;\r\n if (!t.isIdentifier(init.callee, { name: 'require' })) return;\r\n if (init.arguments.length === 0) return;\r\n\r\n const arg = init.arguments[0];\r\n if (!t.isStringLiteral(arg)) return;\r\n if (!isThirdParty(arg.value)) return;\r\n\r\n const source = arg.value;\r\n const packageName = normalizePackageName(source);\r\n const subPath = getSubPath(source);\r\n const line = nodePath.node.loc?.start.line ?? 0;\r\n const col = nodePath.node.loc?.start.column ?? 0;\r\n const raw = code.split('\\n')[line - 1]?.trim() ?? '';\r\n\r\n if (t.isObjectPattern(nodePath.node.id)) {\r\n // const { cloneDeep, merge } = require('lodash')\r\n for (const prop of nodePath.node.id.properties) {\r\n if (t.isObjectProperty(prop) && t.isIdentifier(prop.key)) {\r\n records.push({\r\n file: relPath,\r\n packageName,\r\n functionName: prop.key.name,\r\n line,\r\n col,\r\n raw,\r\n });\r\n }\r\n }\r\n } else if (t.isIdentifier(nodePath.node.id)) {\r\n // const _ = require('lodash')\r\n const functionName = subPath ?? '*';\r\n records.push({ file: relPath, packageName, functionName, line, col, raw });\r\n }\r\n },\r\n\r\n // Pattern 4: _.cloneDeep(obj) — namespace call detection\r\n CallExpression(nodePath) {\r\n const callee = nodePath.node.callee;\r\n if (!t.isMemberExpression(callee)) return;\r\n if (!t.isIdentifier(callee.object)) return;\r\n if (!t.isIdentifier(callee.property)) return;\r\n\r\n // We can't know if `_` is lodash without scope analysis,\r\n // so we record it with a special marker and let the database\r\n // matcher resolve it via namespace import tracking.\r\n const nsName = callee.object.name;\r\n const methodName = callee.property.name;\r\n\r\n // Only record if we saw a namespace import for this identifier\r\n // (this is handled in the match phase via the '*' functionName records)\r\n const line = nodePath.node.loc?.start.line ?? 0;\r\n const col = nodePath.node.loc?.start.column ?? 0;\r\n const raw = code.split('\\n')[line - 1]?.trim() ?? '';\r\n\r\n records.push({\r\n file: relPath,\r\n packageName: `__ns__${nsName}`,\r\n functionName: methodName,\r\n line,\r\n col,\r\n raw,\r\n });\r\n },\r\n });\r\n\r\n return records;\r\n}\r\n\r\nfunction isThirdParty(source: string): boolean {\r\n if (source.startsWith('.')) return false;\r\n if (source.startsWith('/')) return false;\r\n if (source.startsWith('node:')) return false;\r\n // Built-in Node modules\r\n const builtins = new Set([\r\n 'fs', 'path', 'os', 'crypto', 'http', 'https', 'url', 'util',\r\n 'stream', 'child_process', 'cluster', 'events', 'net', 'tls',\r\n 'dns', 'readline', 'repl', 'vm', 'zlib', 'buffer', 'assert',\r\n 'perf_hooks', 'worker_threads', 'module', 'process', 'v8', 'inspector',\r\n ]);\r\n return !builtins.has(source.split('/')[0]);\r\n}\r\n\r\nexport async function parseFiles(files: string[]): Promise<ImportRecord[]> {\r\n const allRecords: ImportRecord[] = [];\r\n for (const file of files) {\r\n const records = parseFile(file);\r\n allRecords.push(...records);\r\n }\r\n return allRecords;\r\n}\r\n","import type { PackageEntry } from '../../types.js';\r\n\r\nexport const lodash: PackageEntry = {\r\n packageName: 'lodash',\r\n description: 'A modern JavaScript utility library delivering modularity, performance & extras.',\r\n gzippedSize: 24_000,\r\n canFullyReplace: true,\r\n functions: [\r\n {\r\n name: 'cloneDeep',\r\n importPaths: ['lodash/cloneDeep'],\r\n alternatives: [\r\n {\r\n api: 'structuredClone',\r\n minNodeVersion: '17.0.0',\r\n bytesSaved: 3_200,\r\n difficulty: 'trivial',\r\n docsUrl: 'https://developer.mozilla.org/en-US/docs/Web/API/structuredClone',\r\n snippet: {\r\n before: `import { cloneDeep } from 'lodash';\\nconst copy = cloneDeep(obj);`,\r\n after: `const copy = structuredClone(obj);`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'merge',\r\n importPaths: ['lodash/merge'],\r\n alternatives: [\r\n {\r\n api: 'Object.assign / spread',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 900,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `import { merge } from 'lodash';\\nconst result = merge({}, defaults, overrides);`,\r\n after: `const result = { ...defaults, ...overrides };`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'get',\r\n importPaths: ['lodash/get'],\r\n alternatives: [\r\n {\r\n api: 'Optional Chaining (?.)',\r\n minNodeVersion: '14.0.0',\r\n bytesSaved: 700,\r\n difficulty: 'trivial',\r\n docsUrl: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining',\r\n snippet: {\r\n before: `import { get } from 'lodash';\\nconst val = get(obj, 'a.b.c', defaultVal);`,\r\n after: `const val = obj?.a?.b?.c ?? defaultVal;`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'flatten',\r\n importPaths: ['lodash/flatten'],\r\n alternatives: [\r\n {\r\n api: 'Array.prototype.flat',\r\n minNodeVersion: '11.0.0',\r\n bytesSaved: 400,\r\n difficulty: 'trivial',\r\n docsUrl: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat',\r\n snippet: {\r\n before: `import { flatten } from 'lodash';\\nconst flat = flatten(arr);`,\r\n after: `const flat = arr.flat();`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'flattenDeep',\r\n importPaths: ['lodash/flattenDeep'],\r\n alternatives: [\r\n {\r\n api: 'Array.prototype.flat(Infinity)',\r\n minNodeVersion: '11.0.0',\r\n bytesSaved: 500,\r\n difficulty: 'trivial',\r\n snippet: {\r\n before: `import { flattenDeep } from 'lodash';\\nconst flat = flattenDeep(arr);`,\r\n after: `const flat = arr.flat(Infinity);`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'uniq',\r\n importPaths: ['lodash/uniq'],\r\n alternatives: [\r\n {\r\n api: 'Set',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 350,\r\n difficulty: 'trivial',\r\n snippet: {\r\n before: `import { uniq } from 'lodash';\\nconst unique = uniq(arr);`,\r\n after: `const unique = [...new Set(arr)];`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'uniqBy',\r\n importPaths: ['lodash/uniqBy'],\r\n alternatives: [\r\n {\r\n api: 'Map + Array.from',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 450,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `import { uniqBy } from 'lodash';\\nconst unique = uniqBy(arr, (x) => x.id);`,\r\n after: `const unique = Array.from(new Map(arr.map((x) => [x.id, x])).values());`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'debounce',\r\n importPaths: ['lodash/debounce'],\r\n alternatives: [\r\n {\r\n api: 'Custom closure',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 600,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `import { debounce } from 'lodash';\\nconst handler = debounce(fn, 300);`,\r\n after: `function debounce(fn, ms) {\\n let timer;\\n return (...args) => { clearTimeout(timer); timer = setTimeout(() => fn(...args), ms); };\\n}\\nconst handler = debounce(fn, 300);`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'throttle',\r\n importPaths: ['lodash/throttle'],\r\n alternatives: [\r\n {\r\n api: 'Custom closure',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 600,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `import { throttle } from 'lodash';\\nconst handler = throttle(fn, 300);`,\r\n after: `function throttle(fn, ms) {\\n let last = 0;\\n return (...args) => { const now = Date.now(); if (now - last >= ms) { last = now; fn(...args); } };\\n}\\nconst handler = throttle(fn, 300);`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'isEmpty',\r\n importPaths: ['lodash/isEmpty'],\r\n alternatives: [\r\n {\r\n api: 'Native checks',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 300,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `import { isEmpty } from 'lodash';\\nif (isEmpty(value)) { ... }`,\r\n after: `// For arrays:\\nif (!arr.length) { ... }\\n// For objects:\\nif (!Object.keys(obj).length) { ... }\\n// For strings:\\nif (!str) { ... }`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'isEqual',\r\n importPaths: ['lodash/isEqual'],\r\n alternatives: [\r\n {\r\n api: 'JSON.stringify (shallow use case)',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 800,\r\n difficulty: 'moderate',\r\n snippet: {\r\n before: `import { isEqual } from 'lodash';\\nif (isEqual(a, b)) { ... }`,\r\n after: `// For simple serializable objects (no functions/undefined):\\nif (JSON.stringify(a) === JSON.stringify(b)) { ... }\\n// For deep equality with full support, keep lodash.isEqual.`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'omit',\r\n importPaths: ['lodash/omit'],\r\n alternatives: [\r\n {\r\n api: 'Destructuring',\r\n minNodeVersion: '6.0.0',\r\n bytesSaved: 350,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `import { omit } from 'lodash';\\nconst clean = omit(obj, ['password', 'token']);`,\r\n after: `const { password, token, ...clean } = obj;`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'pick',\r\n importPaths: ['lodash/pick'],\r\n alternatives: [\r\n {\r\n api: 'Object.fromEntries',\r\n minNodeVersion: '12.0.0',\r\n bytesSaved: 350,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `import { pick } from 'lodash';\\nconst subset = pick(obj, ['name', 'age']);`,\r\n after: `const keys = ['name', 'age'];\\nconst subset = Object.fromEntries(keys.map((k) => [k, obj[k]]));`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'chunk',\r\n importPaths: ['lodash/chunk'],\r\n alternatives: [\r\n {\r\n api: 'Array.from + slice',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 400,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `import { chunk } from 'lodash';\\nconst chunks = chunk(arr, 3);`,\r\n after: `const chunk = (arr, size) =>\\n Array.from({ length: Math.ceil(arr.length / size) }, (_, i) =>\\n arr.slice(i * size, i * size + size)\\n );\\nconst chunks = chunk(arr, 3);`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'groupBy',\r\n importPaths: ['lodash/groupBy'],\r\n alternatives: [\r\n {\r\n api: 'Array.prototype.reduce',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 500,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `import { groupBy } from 'lodash';\\nconst groups = groupBy(arr, (x) => x.category);`,\r\n after: `const groups = arr.reduce((acc, x) => {\\n (acc[x.category] ??= []).push(x);\\n return acc;\\n}, {});`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'sortBy',\r\n importPaths: ['lodash/sortBy'],\r\n alternatives: [\r\n {\r\n api: 'Array.prototype.sort',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 400,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `import { sortBy } from 'lodash';\\nconst sorted = sortBy(arr, (x) => x.name);`,\r\n after: `const sorted = [...arr].sort((a, b) => a.name.localeCompare(b.name));`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'mapValues',\r\n importPaths: ['lodash/mapValues'],\r\n alternatives: [\r\n {\r\n api: 'Object.fromEntries + Object.entries',\r\n minNodeVersion: '12.0.0',\r\n bytesSaved: 350,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `import { mapValues } from 'lodash';\\nconst result = mapValues(obj, (v) => v * 2);`,\r\n after: `const result = Object.fromEntries(\\n Object.entries(obj).map(([k, v]) => [k, v * 2])\\n);`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'keyBy',\r\n importPaths: ['lodash/keyBy'],\r\n alternatives: [\r\n {\r\n api: 'Array.prototype.reduce',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 400,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `import { keyBy } from 'lodash';\\nconst byId = keyBy(users, 'id');`,\r\n after: `const byId = users.reduce((acc, u) => ({ ...acc, [u.id]: u }), {});`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'startCase',\r\n importPaths: ['lodash/startCase'],\r\n alternatives: [\r\n {\r\n api: 'Regex + replace',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 300,\r\n difficulty: 'moderate',\r\n snippet: {\r\n before: `import { startCase } from 'lodash';\\nconst title = startCase('helloWorld');`,\r\n after: `const startCase = (s) =>\\n s.replace(/([A-Z])/g, ' $1')\\n .replace(/[-_]/g, ' ')\\n .replace(/\\\\b\\\\w/g, (c) => c.toUpperCase())\\n .trim();\\nconst title = startCase('helloWorld');`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'camelCase',\r\n importPaths: ['lodash/camelCase'],\r\n alternatives: [\r\n {\r\n api: 'Regex + replace',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 300,\r\n difficulty: 'moderate',\r\n snippet: {\r\n before: `import { camelCase } from 'lodash';\\nconst name = camelCase('hello-world');`,\r\n after: `const camelCase = (s) =>\\n s.toLowerCase().replace(/[-_\\\\s]+(\\\\w)/g, (_, c) => c.toUpperCase());\\nconst name = camelCase('hello-world');`,\r\n },\r\n },\r\n ],\r\n },\r\n ],\r\n};\r\n","import type { PackageEntry } from '../../types.js';\r\n\r\nexport const moment: PackageEntry = {\r\n packageName: 'moment',\r\n description: 'Parse, validate, manipulate, and display dates in JavaScript.',\r\n gzippedSize: 72_000,\r\n canFullyReplace: true,\r\n functions: [\r\n {\r\n name: 'default',\r\n alternatives: [\r\n {\r\n api: 'Intl.DateTimeFormat / Date',\r\n minNodeVersion: '12.0.0',\r\n bytesSaved: 72_000,\r\n difficulty: 'moderate',\r\n docsUrl: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat',\r\n snippet: {\r\n before: `import moment from 'moment';\\nconst formatted = moment().format('YYYY-MM-DD');`,\r\n after: `const formatted = new Date().toISOString().slice(0, 10);\\n// Or with Intl:\\nconst formatted = new Intl.DateTimeFormat('en-CA').format(new Date());`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'format',\r\n alternatives: [\r\n {\r\n api: 'Intl.DateTimeFormat',\r\n minNodeVersion: '12.0.0',\r\n bytesSaved: 72_000,\r\n difficulty: 'moderate',\r\n docsUrl: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat',\r\n snippet: {\r\n before: `moment(date).format('MMM D, YYYY')`,\r\n after: `new Intl.DateTimeFormat('en-US', { month: 'short', day: 'numeric', year: 'numeric' }).format(date)`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'diff',\r\n alternatives: [\r\n {\r\n api: 'Date arithmetic',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 5_000,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `moment(end).diff(moment(start), 'days')`,\r\n after: `Math.round((new Date(end) - new Date(start)) / (1000 * 60 * 60 * 24))`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'add',\r\n alternatives: [\r\n {\r\n api: 'Date manipulation',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 3_000,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `moment().add(7, 'days').toDate()`,\r\n after: `const d = new Date();\\nd.setDate(d.getDate() + 7);`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'fromNow',\r\n alternatives: [\r\n {\r\n api: 'Intl.RelativeTimeFormat',\r\n minNodeVersion: '12.0.0',\r\n bytesSaved: 5_000,\r\n difficulty: 'moderate',\r\n docsUrl: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat',\r\n snippet: {\r\n before: `moment(date).fromNow()`,\r\n after: `const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });\\nconst diffMs = date - Date.now();\\nconst diffDays = Math.round(diffMs / 86_400_000);\\nrtf.format(diffDays, 'day');`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'isBefore',\r\n alternatives: [\r\n {\r\n api: 'Date comparison',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 1_000,\r\n difficulty: 'trivial',\r\n snippet: {\r\n before: `moment(a).isBefore(moment(b))`,\r\n after: `new Date(a) < new Date(b)`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'isAfter',\r\n alternatives: [\r\n {\r\n api: 'Date comparison',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 1_000,\r\n difficulty: 'trivial',\r\n snippet: {\r\n before: `moment(a).isAfter(moment(b))`,\r\n after: `new Date(a) > new Date(b)`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'unix',\r\n alternatives: [\r\n {\r\n api: 'Date.now() / 1000',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 500,\r\n difficulty: 'trivial',\r\n snippet: {\r\n before: `moment().unix()`,\r\n after: `Math.floor(Date.now() / 1000)`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'utc',\r\n alternatives: [\r\n {\r\n api: 'toUTCString / toISOString',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 1_000,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `moment.utc(date).format()`,\r\n after: `new Date(date).toISOString()`,\r\n },\r\n },\r\n ],\r\n },\r\n ],\r\n};\r\n","import type { PackageEntry } from '../../types.js';\r\n\r\nexport const axios: PackageEntry = {\r\n packageName: 'axios',\r\n description: 'Promise based HTTP client for the browser and Node.js.',\r\n gzippedSize: 14_000,\r\n canFullyReplace: true,\r\n functions: [\r\n {\r\n name: 'default',\r\n alternatives: [\r\n {\r\n api: 'fetch',\r\n minNodeVersion: '18.0.0',\r\n bytesSaved: 14_000,\r\n difficulty: 'easy',\r\n docsUrl: 'https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API',\r\n snippet: {\r\n before: `import axios from 'axios';\\nconst { data } = await axios.get('/api/users');`,\r\n after: `const data = await fetch('/api/users').then((r) => r.json());`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'get',\r\n alternatives: [\r\n {\r\n api: 'fetch',\r\n minNodeVersion: '18.0.0',\r\n bytesSaved: 14_000,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `import axios from 'axios';\\nconst { data } = await axios.get(url, { params: { id: 1 } });`,\r\n after: `const url = new URL('/api/users', baseUrl);\\nurl.searchParams.set('id', '1');\\nconst data = await fetch(url).then((r) => r.json());`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'post',\r\n alternatives: [\r\n {\r\n api: 'fetch (POST)',\r\n minNodeVersion: '18.0.0',\r\n bytesSaved: 14_000,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `import axios from 'axios';\\nawait axios.post('/api/users', { name: 'Alice' });`,\r\n after: `await fetch('/api/users', {\\n method: 'POST',\\n headers: { 'Content-Type': 'application/json' },\\n body: JSON.stringify({ name: 'Alice' }),\\n});`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'put',\r\n alternatives: [\r\n {\r\n api: 'fetch (PUT)',\r\n minNodeVersion: '18.0.0',\r\n bytesSaved: 14_000,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `await axios.put('/api/users/1', payload);`,\r\n after: `await fetch('/api/users/1', {\\n method: 'PUT',\\n headers: { 'Content-Type': 'application/json' },\\n body: JSON.stringify(payload),\\n});`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'delete',\r\n alternatives: [\r\n {\r\n api: 'fetch (DELETE)',\r\n minNodeVersion: '18.0.0',\r\n bytesSaved: 14_000,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `await axios.delete('/api/users/1');`,\r\n after: `await fetch('/api/users/1', { method: 'DELETE' });`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'create',\r\n alternatives: [\r\n {\r\n api: 'fetch wrapper',\r\n minNodeVersion: '18.0.0',\r\n bytesSaved: 14_000,\r\n difficulty: 'moderate',\r\n snippet: {\r\n before: `const api = axios.create({ baseURL: 'https://api.example.com', timeout: 5000 });`,\r\n after: `const apiFetch = (path, init = {}) =>\\n fetch(\\`https://api.example.com\\${path}\\`, {\\n signal: AbortSignal.timeout(5000),\\n ...init,\\n }).then((r) => { if (!r.ok) throw new Error(r.statusText); return r.json(); });`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'all',\r\n alternatives: [\r\n {\r\n api: 'Promise.all',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 500,\r\n difficulty: 'trivial',\r\n snippet: {\r\n before: `await axios.all([axios.get('/a'), axios.get('/b')]);`,\r\n after: `await Promise.all([fetch('/a').then(r => r.json()), fetch('/b').then(r => r.json())]);`,\r\n },\r\n },\r\n ],\r\n },\r\n ],\r\n};\r\n","import type { PackageEntry } from '../../types.js';\r\n\r\nexport const uuid: PackageEntry = {\r\n packageName: 'uuid',\r\n description: 'RFC4122 UUIDs generator.',\r\n gzippedSize: 3_700,\r\n canFullyReplace: true,\r\n functions: [\r\n {\r\n name: 'v4',\r\n importPaths: ['uuid/v4'],\r\n alternatives: [\r\n {\r\n api: 'crypto.randomUUID',\r\n minNodeVersion: '14.17.0',\r\n bytesSaved: 3_700,\r\n difficulty: 'trivial',\r\n docsUrl: 'https://nodejs.org/api/crypto.html#cryptorandomuuidoptions',\r\n snippet: {\r\n before: `import { v4 as uuidv4 } from 'uuid';\\nconst id = uuidv4();`,\r\n after: `const id = crypto.randomUUID();`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'v1',\r\n importPaths: ['uuid/v1'],\r\n alternatives: [\r\n {\r\n api: 'crypto.randomUUID (v4 alternative)',\r\n minNodeVersion: '14.17.0',\r\n bytesSaved: 3_700,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `import { v1 as uuidv1 } from 'uuid';\\nconst id = uuidv1();`,\r\n after: `// v1 (timestamp-based) has no direct native equivalent.\\n// If timestamp ordering isn't required, use:\\nconst id = crypto.randomUUID();`,\r\n },\r\n },\r\n ],\r\n },\r\n ],\r\n};\r\n","import type { PackageEntry } from '../../types.js';\r\n\r\nexport const bluebird: PackageEntry = {\r\n packageName: 'bluebird',\r\n description: 'A full featured promise library with unmatched performance.',\r\n gzippedSize: 17_000,\r\n canFullyReplace: true,\r\n functions: [\r\n {\r\n name: 'default',\r\n alternatives: [\r\n {\r\n api: 'Native Promise',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 17_000,\r\n difficulty: 'moderate',\r\n docsUrl: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise',\r\n snippet: {\r\n before: `const Promise = require('bluebird');\\nconst result = new Promise((resolve) => resolve(42));`,\r\n after: `const result = Promise.resolve(42);`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'all',\r\n alternatives: [\r\n {\r\n api: 'Promise.all',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 2_000,\r\n difficulty: 'trivial',\r\n snippet: {\r\n before: `Promise.all([p1, p2, p3])`,\r\n after: `Promise.all([p1, p2, p3]) // Native — same API!`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'map',\r\n alternatives: [\r\n {\r\n api: 'Promise.all + Array.map',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 1_500,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `import Promise from 'bluebird';\\nawait Promise.map(ids, fetchUser, { concurrency: 3 });`,\r\n after: `// Simple version (no concurrency limit):\\nawait Promise.all(ids.map(fetchUser));\\n\\n// With concurrency control (p-limit):\\nimport pLimit from 'p-limit';\\nconst limit = pLimit(3);\\nawait Promise.all(ids.map((id) => limit(() => fetchUser(id))));`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'mapSeries',\r\n alternatives: [\r\n {\r\n api: 'for...of + await',\r\n minNodeVersion: '10.0.0',\r\n bytesSaved: 1_200,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `await Promise.mapSeries(items, processItem);`,\r\n after: `const results = [];\\nfor (const item of items) {\\n results.push(await processItem(item));\\n}`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'filter',\r\n alternatives: [\r\n {\r\n api: 'Promise.all + Array.filter',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 1_000,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `await Promise.filter(items, asyncPredicate);`,\r\n after: `const flags = await Promise.all(items.map(asyncPredicate));\\nconst result = items.filter((_, i) => flags[i]);`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'props',\r\n alternatives: [\r\n {\r\n api: 'Promise.all + Object.fromEntries',\r\n minNodeVersion: '12.0.0',\r\n bytesSaved: 1_000,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `await Promise.props({ user: fetchUser(), posts: fetchPosts() });`,\r\n after: `const [user, posts] = await Promise.all([fetchUser(), fetchPosts()]);\\nconst result = { user, posts };`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'each',\r\n alternatives: [\r\n {\r\n api: 'for...of + await',\r\n minNodeVersion: '10.0.0',\r\n bytesSaved: 800,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `await Promise.each(items, async (item) => { await process(item); });`,\r\n after: `for (const item of items) { await process(item); }`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'any',\r\n alternatives: [\r\n {\r\n api: 'Promise.any',\r\n minNodeVersion: '15.0.0',\r\n bytesSaved: 500,\r\n difficulty: 'trivial',\r\n snippet: {\r\n before: `await Promise.any([p1, p2, p3]);`,\r\n after: `await Promise.any([p1, p2, p3]); // Native — same API!`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'reflect',\r\n alternatives: [\r\n {\r\n api: 'Promise.allSettled',\r\n minNodeVersion: '12.9.0',\r\n bytesSaved: 800,\r\n difficulty: 'easy',\r\n snippet: {\r\n before: `const results = await Promise.all(promises.map((p) => p.reflect()));\\nresults.filter((r) => r.isFulfilled());`,\r\n after: `const results = await Promise.allSettled(promises);\\nresults.filter((r) => r.status === 'fulfilled');`,\r\n },\r\n },\r\n ],\r\n },\r\n ],\r\n};\r\n","import type { PackageEntry } from '../../types.js';\r\n\r\nexport const underscore: PackageEntry = {\r\n packageName: 'underscore',\r\n description: 'A JavaScript utility library providing lots of useful functional programming helpers.',\r\n gzippedSize: 6_800,\r\n canFullyReplace: true,\r\n functions: [\r\n {\r\n name: 'each',\r\n alternatives: [\r\n {\r\n api: 'Array.prototype.forEach',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 400,\r\n difficulty: 'trivial',\r\n snippet: {\r\n before: `import _ from 'underscore';\\n_.each(arr, (item) => console.log(item));`,\r\n after: `arr.forEach((item) => console.log(item));`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'map',\r\n alternatives: [\r\n {\r\n api: 'Array.prototype.map',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 400,\r\n difficulty: 'trivial',\r\n snippet: {\r\n before: `_.map(arr, (x) => x * 2)`,\r\n after: `arr.map((x) => x * 2)`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'filter',\r\n alternatives: [\r\n {\r\n api: 'Array.prototype.filter',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 300,\r\n difficulty: 'trivial',\r\n snippet: {\r\n before: `_.filter(arr, (x) => x > 0)`,\r\n after: `arr.filter((x) => x > 0)`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'reduce',\r\n alternatives: [\r\n {\r\n api: 'Array.prototype.reduce',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 300,\r\n difficulty: 'trivial',\r\n snippet: {\r\n before: `_.reduce(arr, (acc, x) => acc + x, 0)`,\r\n after: `arr.reduce((acc, x) => acc + x, 0)`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'find',\r\n alternatives: [\r\n {\r\n api: 'Array.prototype.find',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 300,\r\n difficulty: 'trivial',\r\n snippet: {\r\n before: `_.find(arr, (x) => x.id === id)`,\r\n after: `arr.find((x) => x.id === id)`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'contains',\r\n alternatives: [\r\n {\r\n api: 'Array.prototype.includes',\r\n minNodeVersion: '6.0.0',\r\n bytesSaved: 200,\r\n difficulty: 'trivial',\r\n snippet: {\r\n before: `_.contains(arr, value)`,\r\n after: `arr.includes(value)`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'keys',\r\n alternatives: [\r\n {\r\n api: 'Object.keys',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 200,\r\n difficulty: 'trivial',\r\n snippet: {\r\n before: `_.keys(obj)`,\r\n after: `Object.keys(obj)`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'values',\r\n alternatives: [\r\n {\r\n api: 'Object.values',\r\n minNodeVersion: '7.0.0',\r\n bytesSaved: 200,\r\n difficulty: 'trivial',\r\n snippet: {\r\n before: `_.values(obj)`,\r\n after: `Object.values(obj)`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'extend',\r\n alternatives: [\r\n {\r\n api: 'Object.assign',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 200,\r\n difficulty: 'trivial',\r\n snippet: {\r\n before: `_.extend(target, source)`,\r\n after: `Object.assign(target, source)`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'clone',\r\n alternatives: [\r\n {\r\n api: 'structuredClone / spread',\r\n minNodeVersion: '17.0.0',\r\n bytesSaved: 300,\r\n difficulty: 'trivial',\r\n snippet: {\r\n before: `_.clone(obj)`,\r\n after: `structuredClone(obj) // deep clone\\n// or { ...obj } for shallow`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'flatten',\r\n alternatives: [\r\n {\r\n api: 'Array.prototype.flat',\r\n minNodeVersion: '11.0.0',\r\n bytesSaved: 300,\r\n difficulty: 'trivial',\r\n snippet: {\r\n before: `_.flatten(arr)`,\r\n after: `arr.flat()`,\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n name: 'uniq',\r\n alternatives: [\r\n {\r\n api: 'Set',\r\n minNodeVersion: '4.0.0',\r\n bytesSaved: 250,\r\n difficulty: 'trivial',\r\n snippet: {\r\n before: `_.uniq(arr)`,\r\n after: `[...new Set(arr)]`,\r\n },\r\n },\r\n ],\r\n },\r\n ],\r\n};\r\n","import type { PackageEntry, FunctionEntry, Match, ImportRecord } from '../types.js';\r\nimport { lodash } from './packs/lodash.js';\r\nimport { moment } from './packs/moment.js';\r\nimport { axios } from './packs/axios.js';\r\nimport { uuid } from './packs/uuid.js';\r\nimport { bluebird } from './packs/bluebird.js';\r\nimport { underscore } from './packs/underscore.js';\r\n\r\nconst ALL_PACKAGES: PackageEntry[] = [lodash, moment, axios, uuid, bluebird, underscore];\r\n\r\nconst packageRegistry = new Map<string, PackageEntry>();\r\nconst functionRegistry = new Map<string, Map<string, FunctionEntry>>();\r\nconst subPathRegistry = new Map<string, { packageName: string; functionName: string }>();\r\n\r\nfor (const pkg of ALL_PACKAGES) {\r\n packageRegistry.set(pkg.packageName, pkg);\r\n const fnMap = new Map<string, FunctionEntry>();\r\n\r\n for (const fn of pkg.functions) {\r\n fnMap.set(fn.name, fn);\r\n if (fn.importPaths) {\r\n for (const subPath of fn.importPaths) {\r\n subPathRegistry.set(subPath, { packageName: pkg.packageName, functionName: fn.name });\r\n }\r\n }\r\n }\r\n\r\n functionRegistry.set(pkg.packageName, fnMap);\r\n}\r\n\r\nexport function lookupPackage(packageName: string): PackageEntry | undefined {\r\n return packageRegistry.get(packageName);\r\n}\r\n\r\nexport function lookupFunction(packageName: string, functionName: string): FunctionEntry | undefined {\r\n return functionRegistry.get(packageName)?.get(functionName);\r\n}\r\n\r\nexport function lookupSubPath(subPath: string): { packageName: string; functionName: string } | undefined {\r\n return subPathRegistry.get(subPath);\r\n}\r\n\r\nexport function getAllPackages(): PackageEntry[] {\r\n return ALL_PACKAGES;\r\n}\r\n\r\n/**\r\n * Resolve namespace usages. When a file has `import * as _ from 'lodash'`,\r\n * we track it as a '*' import. Subsequent `__ns__<name>.method` calls\r\n * are then linked back to the package.\r\n */\r\nexport function matchImports(imports: ImportRecord[]): Match[] {\r\n const matches: Match[] = [];\r\n\r\n // Build namespace identifier → package map\r\n // e.g. `import * as _ from 'lodash'` creates ns record with packageName='lodash', functionName='*'\r\n // `_.cloneDeep()` creates ns record with packageName='__ns___', functionName='cloneDeep'\r\n const namespaceToPackage = new Map<string, string>();\r\n for (const rec of imports) {\r\n if (rec.functionName === '*' && !rec.packageName.startsWith('__ns__')) {\r\n // We need the local identifier — it's encoded in subsequent ns calls\r\n // The ns identifier is keyed to the package\r\n namespaceToPackage.set(rec.packageName, rec.packageName);\r\n }\r\n }\r\n\r\n // Build a map of local alias → packageName from namespace imports\r\n // We reconstruct this from the '*' records and match __ns__ records by file\r\n const fileNsMap = new Map<string, Map<string, string>>();\r\n for (const rec of imports) {\r\n if (rec.functionName === '*' && !rec.packageName.startsWith('__ns__')) {\r\n // We need the local identifier name — not available directly in current schema\r\n // Use a heuristic: if the package is lodash/underscore, assume '_' as namespace\r\n const commonNs = rec.packageName === 'lodash' || rec.packageName === 'underscore' ? '_' : rec.packageName;\r\n if (!fileNsMap.has(rec.file)) fileNsMap.set(rec.file, new Map());\r\n fileNsMap.get(rec.file)!.set(commonNs, rec.packageName);\r\n }\r\n }\r\n\r\n for (const rec of imports) {\r\n // Skip internal namespace tracking records\r\n if (rec.functionName === '*') continue;\r\n\r\n let packageName = rec.packageName;\r\n let functionName = rec.functionName;\r\n\r\n // Resolve namespace calls: __ns__<identifier>\r\n if (packageName.startsWith('__ns__')) {\r\n const nsId = packageName.replace('__ns__', '');\r\n const filePkg = fileNsMap.get(rec.file)?.get(nsId);\r\n if (!filePkg) continue;\r\n packageName = filePkg;\r\n }\r\n\r\n // Try direct lookup\r\n let pkgEntry = lookupPackage(packageName);\r\n let fnEntry = pkgEntry ? lookupFunction(packageName, functionName) : undefined;\r\n\r\n // Try sub-path lookup (e.g. \"lodash/cloneDeep\")\r\n if (!fnEntry) {\r\n const subPathKey = `${packageName}/${functionName}`;\r\n const resolved = lookupSubPath(subPathKey);\r\n if (resolved) {\r\n pkgEntry = lookupPackage(resolved.packageName);\r\n fnEntry = pkgEntry ? lookupFunction(resolved.packageName, resolved.functionName) : undefined;\r\n if (pkgEntry) packageName = resolved.packageName;\r\n if (fnEntry) functionName = resolved.functionName;\r\n }\r\n }\r\n\r\n // Try 'default' entry for default imports\r\n if (!fnEntry && pkgEntry) {\r\n fnEntry = lookupFunction(packageName, 'default');\r\n }\r\n\r\n if (!pkgEntry || !fnEntry) continue;\r\n\r\n matches.push({\r\n importRecord: { ...rec, packageName, functionName },\r\n packageEntry: pkgEntry,\r\n functionEntry: fnEntry,\r\n });\r\n }\r\n\r\n // Deduplicate: one match per (file, packageName, functionName) combo\r\n const seen = new Set<string>();\r\n return matches.filter((m) => {\r\n const key = `${m.importRecord.file}::${m.importRecord.packageName}::${m.importRecord.functionName}`;\r\n if (seen.has(key)) return false;\r\n seen.add(key);\r\n return true;\r\n });\r\n}\r\n","import fs from 'fs';\r\nimport path from 'path';\r\nimport type { Match, ScanResult, ScoreGrade, ImportRecord } from './types.js';\r\nimport { getAllPackages } from './database/index.js';\r\n\r\ninterface PackageJson {\r\n dependencies?: Record<string, string>;\r\n devDependencies?: Record<string, string>;\r\n}\r\n\r\nfunction loadPackageJson(targetDir: string): PackageJson {\r\n const pkgPath = path.join(targetDir, 'package.json');\r\n try {\r\n const raw = fs.readFileSync(pkgPath, 'utf-8');\r\n return JSON.parse(raw) as PackageJson;\r\n } catch {\r\n return {};\r\n }\r\n}\r\n\r\nfunction getTotalDepsSize(targetDir: string): number {\r\n const pkg = loadPackageJson(targetDir);\r\n const allDeps = {\r\n ...pkg.dependencies,\r\n ...pkg.devDependencies,\r\n };\r\n\r\n const allPkgs = getAllPackages();\r\n const knownSizes = new Map(allPkgs.map((p) => [p.packageName, p.gzippedSize]));\r\n\r\n let total = 0;\r\n for (const depName of Object.keys(allDeps)) {\r\n const size = knownSizes.get(depName);\r\n if (size) total += size;\r\n }\r\n\r\n // If we couldn't read any sizes from known packages, use a reasonable baseline\r\n // so the score is still meaningful\r\n if (total === 0) {\r\n total = allPkgs.reduce((sum, p) => sum + p.gzippedSize, 0);\r\n }\r\n\r\n return total;\r\n}\r\n\r\nexport function getScoreGrade(score: number): ScoreGrade {\r\n if (score >= 90) return 'SVELTE';\r\n if (score >= 70) return 'HEALTHY';\r\n if (score >= 40) return 'NEEDS WORK';\r\n return 'CRITICAL';\r\n}\r\n\r\nexport function computeScore(totalBytesSaved: number, totalDepsSize: number): number {\r\n if (totalDepsSize === 0) return 100;\r\n const wasteRatio = Math.min(totalBytesSaved / totalDepsSize, 1);\r\n return Math.max(0, Math.round(100 - wasteRatio * 100));\r\n}\r\n\r\nexport function buildScanResult(\r\n targetDir: string,\r\n filesScanned: number,\r\n imports: ImportRecord[],\r\n matches: Match[],\r\n scanDurationMs: number\r\n): ScanResult {\r\n const totalBytesSaved = matches.reduce((sum, m) => {\r\n const maxSaving = Math.max(...m.functionEntry.alternatives.map((a) => a.bytesSaved));\r\n return sum + maxSaving;\r\n }, 0);\r\n\r\n const totalDepsSize = getTotalDepsSize(targetDir);\r\n const refactorScore = computeScore(totalBytesSaved, totalDepsSize);\r\n const grade = getScoreGrade(refactorScore);\r\n\r\n return {\r\n targetDir,\r\n filesScanned,\r\n imports,\r\n matches,\r\n totalBytesSaved,\r\n totalDepsSize,\r\n refactorScore,\r\n grade,\r\n scanDurationMs,\r\n };\r\n}\r\n\r\nexport function formatBytes(bytes: number): string {\r\n if (bytes >= 1_000_000) return `${(bytes / 1_000_000).toFixed(1)} MB`;\r\n if (bytes >= 1_000) return `${(bytes / 1_000).toFixed(1)} KB`;\r\n return `${bytes} B`;\r\n}\r\n","import chalk, { type ChalkInstance } from 'chalk';\r\nimport boxen from 'boxen';\r\nimport Table from 'cli-table3';\r\nimport gradient from 'gradient-string';\r\nimport type { ScanResult, Match, ScoreGrade, NativeAlternative, Difficulty } from '../types.js';\r\nimport { formatBytes } from '../scorer.js';\r\n\r\n// ─── Colour palette ──────────────────────────────────────────────────────────\r\nconst BRAND = gradient(['#FF6B6B', '#FFD93D', '#6BCB77', '#4D96FF']);\r\n\r\nconst gradeColor: Record<ScoreGrade, ChalkInstance> = {\r\n CRITICAL: chalk.red.bold,\r\n 'NEEDS WORK': chalk.yellow.bold,\r\n HEALTHY: chalk.green.bold,\r\n SVELTE: chalk.cyan.bold,\r\n};\r\n\r\nconst gradeIcon: Record<ScoreGrade, string> = {\r\n CRITICAL: '💀',\r\n 'NEEDS WORK': '⚠️ ',\r\n HEALTHY: '✅',\r\n SVELTE: '🥗',\r\n};\r\n\r\nconst difficultyColor: Record<Difficulty, ChalkInstance> = {\r\n trivial: chalk.green,\r\n easy: chalk.cyan,\r\n moderate: chalk.yellow,\r\n hard: chalk.red,\r\n};\r\n\r\nconst difficultyLabel: Record<Difficulty, string> = {\r\n trivial: 'TRIVIAL',\r\n easy: 'EASY',\r\n moderate: 'MODERATE',\r\n hard: 'HARD',\r\n};\r\n\r\n// ─── Helpers ─────────────────────────────────────────────────────────────────\r\nfunction scoreBar(score: number): string {\r\n const filled = Math.round(score / 5);\r\n const empty = 20 - filled;\r\n const bar = '█'.repeat(filled) + '░'.repeat(empty);\r\n if (score >= 90) return chalk.cyan(bar);\r\n if (score >= 70) return chalk.green(bar);\r\n if (score >= 40) return chalk.yellow(bar);\r\n return chalk.red(bar);\r\n}\r\n\r\nfunction sparkline(values: number[]): string {\r\n const BLOCKS = ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'];\r\n const min = Math.min(...values);\r\n const max = Math.max(...values);\r\n const range = max - min || 1;\r\n return values\r\n .map((v) => {\r\n const idx = Math.round(((v - min) / range) * (BLOCKS.length - 1));\r\n return BLOCKS[idx];\r\n })\r\n .join('');\r\n}\r\n\r\nfunction formatDiff(before: string, after: string): string {\r\n const beforeLines = before.split('\\n').map((l) => chalk.red(`- ${l}`));\r\n const afterLines = after.split('\\n').map((l) => chalk.green(`+ ${l}`));\r\n return [...beforeLines, ...afterLines].join('\\n');\r\n}\r\n\r\nfunction wrapSnippet(alternative: NativeAlternative): string {\r\n return [\r\n chalk.dim(' ┌── Before ──────────────────────────────'),\r\n ...alternative.snippet.before.split('\\n').map((l) => chalk.red(` │ ${l}`)),\r\n chalk.dim(' ├── After ───────────────────────────────'),\r\n ...alternative.snippet.after.split('\\n').map((l) => chalk.green(` │ ${l}`)),\r\n chalk.dim(' └────────────────────────────────────────'),\r\n ].join('\\n');\r\n}\r\n\r\n// ─── Header ──────────────────────────────────────────────────────────────────\r\nexport function printHeader(): void {\r\n const title = BRAND(\r\n ' ██████╗ ██╗ ██╗ ██████╗ ██████╗ ██╗███████╗████████╗\\n' +\r\n ' ██╔══██╗██║ ██╔╝██╔════╝ ██╔══██╗██║██╔════╝╚══██╔══╝\\n' +\r\n ' ██████╔╝█████╔╝ ██║ ███╗█████╗██║ ██║██║█████╗ ██║ \\n' +\r\n ' ██╔═══╝ ██╔═██╗ ██║ ██║╚════╝██║ ██║██║██╔══╝ ██║ \\n' +\r\n ' ██║ ██║ ██╗╚██████╔╝ ██████╔╝██║███████╗ ██║ \\n' +\r\n ' ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝╚══════╝ ╚═╝ '\r\n );\r\n\r\n console.log(\r\n boxen(title, {\r\n padding: 1,\r\n borderStyle: 'round',\r\n borderColor: 'magenta',\r\n })\r\n );\r\n console.log(\r\n chalk.dim(' Put your project on a diet. Find heavy packages, go native.\\n')\r\n );\r\n}\r\n\r\n// ─── Score card ──────────────────────────────────────────────────────────────\r\nexport function printScoreCard(result: ScanResult): void {\r\n const { refactorScore, grade, totalBytesSaved, filesScanned, matches, scanDurationMs } = result;\r\n\r\n const uniquePackages = new Set(matches.map((m) => m.packageEntry.packageName));\r\n const colorFn = gradeColor[grade];\r\n const icon = gradeIcon[grade];\r\n\r\n const content = [\r\n '',\r\n ` ${BRAND('REFACTOR SCORE')}`,\r\n '',\r\n ` ${scoreBar(refactorScore)} ${colorFn(`${refactorScore}/100`)}`,\r\n '',\r\n ` Grade: ${colorFn(`${icon} ${grade}`)}`,\r\n '',\r\n ` ${chalk.dim('─'.repeat(44))}`,\r\n '',\r\n ` ${chalk.white('Potential savings:')} ${chalk.yellow.bold(formatBytes(totalBytesSaved))}`,\r\n ` ${chalk.white('Packages to replace:')} ${chalk.yellow.bold(String(uniquePackages.size))}`,\r\n ` ${chalk.white('Usage sites found:')} ${chalk.yellow.bold(String(matches.length))}`,\r\n ` ${chalk.white('Files scanned:')} ${chalk.dim(String(filesScanned))}`,\r\n ` ${chalk.white('Scan duration:')} ${chalk.dim(`${scanDurationMs}ms`)}`,\r\n '',\r\n ].join('\\n');\r\n\r\n console.log(\r\n boxen(content, {\r\n borderStyle: 'double',\r\n borderColor: grade === 'CRITICAL' ? 'red' : grade === 'SVELTE' ? 'cyan' : 'yellow',\r\n padding: 0,\r\n })\r\n );\r\n}\r\n\r\n// ─── Matches table ────────────────────────────────────────────────────────────\r\nexport function printMatchesTable(matches: Match[]): void {\r\n if (matches.length === 0) {\r\n console.log(chalk.green('\\n ✓ No heavy library usage found. Your project is already lean!\\n'));\r\n return;\r\n }\r\n\r\n console.log(chalk.bold.white('\\n DETECTED USAGE\\n'));\r\n\r\n const table = new Table({\r\n head: [\r\n chalk.bold.cyan('Package'),\r\n chalk.bold.cyan('Function'),\r\n chalk.bold.cyan('File'),\r\n chalk.bold.cyan('Line'),\r\n chalk.bold.cyan('Savings'),\r\n chalk.bold.cyan('Effort'),\r\n ],\r\n style: { head: [], border: ['dim'] },\r\n colWidths: [16, 16, 36, 6, 12, 12],\r\n wordWrap: true,\r\n });\r\n\r\n for (const match of matches) {\r\n const best = match.functionEntry.alternatives[0];\r\n if (!best) continue;\r\n\r\n const diffColor = difficultyColor[best.difficulty];\r\n const shortFile = match.importRecord.file.length > 34\r\n ? '…' + match.importRecord.file.slice(-33)\r\n : match.importRecord.file;\r\n\r\n table.push([\r\n chalk.magenta(match.packageEntry.packageName),\r\n chalk.white(match.importRecord.functionName),\r\n chalk.dim(shortFile),\r\n chalk.dim(String(match.importRecord.line)),\r\n chalk.yellow(formatBytes(best.bytesSaved)),\r\n diffColor(difficultyLabel[best.difficulty]),\r\n ]);\r\n }\r\n\r\n console.log(table.toString());\r\n}\r\n\r\n// ─── Detailed suggestions ─────────────────────────────────────────────────────\r\nexport function printSuggestions(matches: Match[]): void {\r\n if (matches.length === 0) return;\r\n\r\n // Group by package\r\n const byPackage = new Map<string, Match[]>();\r\n for (const m of matches) {\r\n const key = m.packageEntry.packageName;\r\n if (!byPackage.has(key)) byPackage.set(key, []);\r\n byPackage.get(key)!.push(m);\r\n }\r\n\r\n console.log(chalk.bold.white('\\n NATIVE ALTERNATIVES\\n'));\r\n\r\n for (const [packageName, pkgMatches] of byPackage) {\r\n const totalSavings = pkgMatches.reduce((sum, m) => {\r\n const best = m.functionEntry.alternatives[0];\r\n return sum + (best?.bytesSaved ?? 0);\r\n }, 0);\r\n\r\n console.log(\r\n boxen(\r\n ` ${chalk.bold.magenta(packageName)} ${chalk.dim(`→ could save ${formatBytes(totalSavings)}`)}`,\r\n { padding: 0, borderStyle: 'single', borderColor: 'magenta' }\r\n )\r\n );\r\n console.log();\r\n\r\n // Deduplicate by function name within this package\r\n const seenFunctions = new Set<string>();\r\n for (const match of pkgMatches) {\r\n const fnName = match.functionEntry.name;\r\n if (seenFunctions.has(fnName)) continue;\r\n seenFunctions.add(fnName);\r\n\r\n const alt = match.functionEntry.alternatives[0];\r\n if (!alt) continue;\r\n\r\n const diffColor = difficultyColor[alt.difficulty];\r\n\r\n console.log(\r\n ` ${chalk.bold.white(fnName)} ` +\r\n `${chalk.dim('→')} ${chalk.cyan(alt.api)} ` +\r\n `${chalk.dim('|')} Node ≥ ${chalk.dim(alt.minNodeVersion)} ` +\r\n `${chalk.dim('|')} ${diffColor(difficultyLabel[alt.difficulty])}` +\r\n (alt.docsUrl ? `\\n ${chalk.dim.underline(alt.docsUrl)}` : '')\r\n );\r\n console.log();\r\n console.log(wrapSnippet(alt));\r\n console.log();\r\n }\r\n }\r\n}\r\n\r\n// ─── Time Machine ────────────────────────────────────────────────────────────\r\nexport function printTimeMachine(\r\n history: Array<{ timestamp: string; score: number; gitRef?: string; grade: string }>,\r\n currentScore: number\r\n): void {\r\n if (history.length === 0) {\r\n console.log(chalk.dim('\\n No history yet — run again to build a trend.\\n'));\r\n return;\r\n }\r\n\r\n const scores = [...history.map((h) => h.score), currentScore];\r\n const spark = sparkline(scores);\r\n const trend = scores[scores.length - 1] - scores[0];\r\n const trendStr = trend > 0\r\n ? chalk.green(`▲ +${trend} (leaner!)`)\r\n : trend < 0\r\n ? chalk.red(`▼ ${trend} (getting fatter!)`)\r\n : chalk.dim('━ no change');\r\n\r\n console.log(chalk.bold.white('\\n TIME MACHINE\\n'));\r\n console.log(` Score trend: ${chalk.cyan(spark)} ${trendStr}`);\r\n console.log();\r\n\r\n const table = new Table({\r\n head: [chalk.bold.cyan('Date'), chalk.bold.cyan('Ref'), chalk.bold.cyan('Score'), chalk.bold.cyan('Grade')],\r\n style: { head: [], border: ['dim'] },\r\n });\r\n\r\n for (const entry of history.slice(-8)) {\r\n const color = gradeColor[entry.grade as ScoreGrade] ?? chalk.white;\r\n table.push([\r\n chalk.dim(new Date(entry.timestamp).toLocaleDateString()),\r\n chalk.dim(entry.gitRef ?? '—'),\r\n color(String(entry.score)),\r\n color(entry.grade as string),\r\n ]);\r\n }\r\n\r\n console.log(table.toString());\r\n console.log();\r\n}\r\n\r\n// ─── Summary footer ───────────────────────────────────────────────────────────\r\nexport function printFooter(_result: ScanResult, fixMode: boolean): void {\r\n const lines: string[] = [];\r\n\r\n if (fixMode) {\r\n lines.push(chalk.green(' ✦ Run with --fix --yes to auto-apply trivial patches.'));\r\n }\r\n\r\n lines.push(\r\n chalk.dim(' ✦ Add to CI: ') + chalk.white('npx backend-diet scan --format json')\r\n );\r\n lines.push(\r\n chalk.dim(' ✦ Get badge: ') + chalk.white('npx backend-diet scan --badge')\r\n );\r\n lines.push(\r\n chalk.dim(' ✦ Track trend:') + chalk.white(' npx backend-diet scan --since HEAD~10')\r\n );\r\n lines.push('');\r\n lines.push(\r\n chalk.dim(' Built by ') + chalk.white('Marwan Said') + chalk.dim(' · github.com/1iPluto/backend-diet')\r\n );\r\n\r\n console.log(\r\n boxen(lines.join('\\n'), {\r\n borderStyle: 'round',\r\n borderColor: 'dim',\r\n padding: 0,\r\n margin: { top: 1, bottom: 0, left: 0, right: 0 },\r\n })\r\n );\r\n}\r\n\r\n// ─── Error / info printers ────────────────────────────────────────────────────\r\nexport function printError(msg: string): void {\r\n console.error(chalk.red(`\\n ✗ ${msg}\\n`));\r\n}\r\n\r\nexport function printInfo(msg: string): void {\r\n console.log(chalk.dim(` ℹ ${msg}`));\r\n}\r\n\r\nexport function printPatchPreview(file: string, before: string, after: string): void {\r\n console.log(chalk.bold.white(`\\n 📄 ${file}\\n`));\r\n console.log(formatDiff(before, after));\r\n console.log();\r\n}\r\n","import type { ScanResult } from '../types.js';\r\n\r\nexport interface JsonReport {\r\n version: string;\r\n timestamp: string;\r\n targetDir: string;\r\n summary: {\r\n filesScanned: number;\r\n matchesFound: number;\r\n uniquePackages: string[];\r\n totalBytesSaved: number;\r\n totalBytesSavedFormatted: string;\r\n refactorScore: number;\r\n grade: string;\r\n scanDurationMs: number;\r\n };\r\n matches: Array<{\r\n file: string;\r\n line: number;\r\n packageName: string;\r\n functionName: string;\r\n raw: string;\r\n alternatives: Array<{\r\n api: string;\r\n minNodeVersion: string;\r\n bytesSaved: number;\r\n difficulty: string;\r\n snippet: { before: string; after: string };\r\n docsUrl?: string;\r\n }>;\r\n }>;\r\n}\r\n\r\nfunction formatBytes(bytes: number): string {\r\n if (bytes >= 1_000_000) return `${(bytes / 1_000_000).toFixed(1)} MB`;\r\n if (bytes >= 1_000) return `${(bytes / 1_000).toFixed(1)} KB`;\r\n return `${bytes} B`;\r\n}\r\n\r\nexport function buildJsonReport(result: ScanResult): JsonReport {\r\n const uniquePackages = [...new Set(result.matches.map((m) => m.packageEntry.packageName))];\r\n\r\n return {\r\n version: '1.0.0',\r\n timestamp: new Date().toISOString(),\r\n targetDir: result.targetDir,\r\n summary: {\r\n filesScanned: result.filesScanned,\r\n matchesFound: result.matches.length,\r\n uniquePackages,\r\n totalBytesSaved: result.totalBytesSaved,\r\n totalBytesSavedFormatted: formatBytes(result.totalBytesSaved),\r\n refactorScore: result.refactorScore,\r\n grade: result.grade,\r\n scanDurationMs: result.scanDurationMs,\r\n },\r\n matches: result.matches.map((m) => ({\r\n file: m.importRecord.file,\r\n line: m.importRecord.line,\r\n packageName: m.importRecord.packageName,\r\n functionName: m.importRecord.functionName,\r\n raw: m.importRecord.raw,\r\n alternatives: m.functionEntry.alternatives.map((a) => ({\r\n api: a.api,\r\n minNodeVersion: a.minNodeVersion,\r\n bytesSaved: a.bytesSaved,\r\n difficulty: a.difficulty,\r\n snippet: a.snippet,\r\n ...(a.docsUrl ? { docsUrl: a.docsUrl } : {}),\r\n })),\r\n })),\r\n };\r\n}\r\n\r\nexport function printJsonReport(result: ScanResult): void {\r\n const report = buildJsonReport(result);\r\n console.log(JSON.stringify(report, null, 2));\r\n}\r\n","import fs from 'fs';\r\nimport path from 'path';\r\nimport type { Match, PatchResult } from './types.js';\r\n\r\n/**\r\n * For each match with difficulty='trivial', attempt to rewrite the source file\r\n * by replacing the import line with the native alternative.\r\n *\r\n * In dry-run mode (apply=false), only computes what WOULD be changed.\r\n * In apply mode (apply=true), writes the changes back to disk.\r\n */\r\nexport function computePatches(matches: Match[], targetDir: string): PatchResult[] {\r\n const results: PatchResult[] = [];\r\n\r\n // Only patch trivial replacements\r\n const trivial = matches.filter((m) =>\r\n m.functionEntry.alternatives.some((a) => a.difficulty === 'trivial')\r\n );\r\n\r\n // Group by file to batch edits\r\n const byFile = new Map<string, Match[]>();\r\n for (const m of trivial) {\r\n const absFile = path.resolve(targetDir, m.importRecord.file);\r\n if (!byFile.has(absFile)) byFile.set(absFile, []);\r\n byFile.get(absFile)!.push(m);\r\n }\r\n\r\n for (const [absFile, fileMatches] of byFile) {\r\n let source: string;\r\n try {\r\n source = fs.readFileSync(absFile, 'utf-8');\r\n } catch {\r\n continue;\r\n }\r\n\r\n const lines = source.split('\\n');\r\n\r\n for (const match of fileMatches) {\r\n const alt = match.functionEntry.alternatives.find((a) => a.difficulty === 'trivial');\r\n if (!alt) continue;\r\n\r\n const lineIdx = match.importRecord.line - 1;\r\n const originalLine = lines[lineIdx];\r\n if (originalLine === undefined) continue;\r\n\r\n results.push({\r\n file: match.importRecord.file,\r\n originalLine: match.importRecord.line,\r\n before: originalLine,\r\n after: alt.snippet.after,\r\n applied: false,\r\n });\r\n }\r\n }\r\n\r\n return results;\r\n}\r\n\r\nexport function applyPatches(patches: PatchResult[], targetDir: string): PatchResult[] {\r\n // Group by file\r\n const byFile = new Map<string, PatchResult[]>();\r\n for (const p of patches) {\r\n const absFile = path.resolve(targetDir, p.file);\r\n if (!byFile.has(absFile)) byFile.set(absFile, []);\r\n byFile.get(absFile)!.push(p);\r\n }\r\n\r\n const applied: PatchResult[] = [];\r\n\r\n for (const [absFile, filePatches] of byFile) {\r\n let source: string;\r\n try {\r\n source = fs.readFileSync(absFile, 'utf-8');\r\n } catch {\r\n continue;\r\n }\r\n\r\n let modified = source;\r\n for (const patch of filePatches) {\r\n if (modified.includes(patch.before)) {\r\n modified = modified.replace(patch.before, patch.after);\r\n applied.push({ ...patch, applied: true });\r\n }\r\n }\r\n\r\n try {\r\n fs.writeFileSync(absFile, modified, 'utf-8');\r\n } catch {\r\n // Skip files we can't write\r\n }\r\n }\r\n\r\n return applied;\r\n}\r\n","import type { ScoreGrade } from './types.js';\r\n\r\nconst BADGE_COLORS: Record<ScoreGrade, string> = {\r\n CRITICAL: 'red',\r\n 'NEEDS WORK': 'yellow',\r\n HEALTHY: 'green',\r\n SVELTE: 'brightgreen',\r\n};\r\n\r\n/**\r\n * Generates a Shields.io badge URL for the given score.\r\n * Output is markdown-ready for pasting into README.md.\r\n */\r\nexport function generateBadge(score: number, grade: ScoreGrade): string {\r\n const color = BADGE_COLORS[grade];\r\n const label = encodeURIComponent('backend-diet');\r\n const message = encodeURIComponent(`${score}% lean`);\r\n const badgeUrl = `https://img.shields.io/badge/${label}-${message}-${color}?style=flat-square&logo=npm`;\r\n\r\n return `[![backend-diet score](${badgeUrl})](https://github.com/1iPluto/backend-diet)`;\r\n}\r\n\r\n/**\r\n * Prints the badge markdown and instructions to stdout.\r\n */\r\nexport function printBadge(score: number, grade: ScoreGrade): void {\r\n const badge = generateBadge(score, grade);\r\n console.log('\\n Paste this into your README.md:\\n');\r\n console.log(` ${badge}`);\r\n console.log();\r\n}\r\n","import fs from 'fs';\r\nimport path from 'path';\r\nimport { execSync } from 'child_process';\r\nimport type { HistoryEntry, ScanResult } from './types.js';\r\n\r\nconst HISTORY_FILE = '.backend-diet-history.json';\r\n\r\nfunction loadHistory(cwd: string): HistoryEntry[] {\r\n const histPath = path.join(cwd, HISTORY_FILE);\r\n try {\r\n const raw = fs.readFileSync(histPath, 'utf-8');\r\n return JSON.parse(raw) as HistoryEntry[];\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\nfunction saveHistory(cwd: string, history: HistoryEntry[]): void {\r\n const histPath = path.join(cwd, HISTORY_FILE);\r\n try {\r\n fs.writeFileSync(histPath, JSON.stringify(history, null, 2), 'utf-8');\r\n } catch {\r\n // Fail silently — history is a nice-to-have\r\n }\r\n}\r\n\r\nfunction getCurrentGitRef(cwd: string): string | undefined {\r\n try {\r\n return execSync('git rev-parse --short HEAD', { cwd, stdio: ['pipe', 'pipe', 'pipe'] })\r\n .toString()\r\n .trim();\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\nexport function recordScanResult(result: ScanResult, cwd: string): void {\r\n const history = loadHistory(cwd);\r\n const gitRef = getCurrentGitRef(cwd);\r\n\r\n const entry: HistoryEntry = {\r\n timestamp: new Date().toISOString(),\r\n gitRef,\r\n score: result.refactorScore,\r\n grade: result.grade,\r\n totalBytesSaved: result.totalBytesSaved,\r\n };\r\n\r\n // Keep last 50 entries\r\n history.push(entry);\r\n if (history.length > 50) history.splice(0, history.length - 50);\r\n\r\n saveHistory(cwd, history);\r\n}\r\n\r\nexport function getHistory(cwd: string): HistoryEntry[] {\r\n return loadHistory(cwd);\r\n}\r\n\r\nexport function analyzeTimeMachineTrend(\r\n history: HistoryEntry[],\r\n currentScore: number\r\n): {\r\n isImproving: boolean;\r\n delta: number;\r\n sparkValues: number[];\r\n} {\r\n const allScores = [...history.map((h) => h.score), currentScore];\r\n const delta = allScores.length > 1\r\n ? allScores[allScores.length - 1] - allScores[0]\r\n : 0;\r\n\r\n return {\r\n isImproving: delta >= 0,\r\n delta,\r\n sparkValues: allScores,\r\n };\r\n}\r\n"],"mappings":"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","names":["import_path","import_chalk","fg","path","import_path","fs","path","traverse","import_fs","import_path","path","fs","gradient","chalk","boxen","Table","formatBytes","import_fs","import_path","path","fs","import_fs","import_path","path","fs","path","ora","chalk"]}
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "backend-diet",
3
+ "version": "1.0.0",
4
+ "description": "Scan your source code, find heavy library usage, and get native alternatives with code snippets — right in your terminal.",
5
+ "author": "Marwan Said <1iPluto@github>",
6
+ "license": "MIT",
7
+ "homepage": "https://github.com/1iPluto/backend-diet#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/1iPluto/backend-diet.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/1iPluto/backend-diet/issues"
14
+ },
15
+ "keywords": [
16
+ "cli",
17
+ "nodejs",
18
+ "ast",
19
+ "bundle-size",
20
+ "developer-tools",
21
+ "npm",
22
+ "dependencies",
23
+ "performance",
24
+ "babel",
25
+ "tree-shaking"
26
+ ],
27
+ "bin": {
28
+ "backend-diet": "./bin/backend-diet.js"
29
+ },
30
+ "main": "./dist/cli.js",
31
+ "files": [
32
+ "dist",
33
+ "bin"
34
+ ],
35
+ "scripts": {
36
+ "build": "tsup",
37
+ "dev": "tsup --watch",
38
+ "start": "node bin/backend-diet.js",
39
+ "test": "vitest run",
40
+ "test:watch": "vitest",
41
+ "lint": "eslint src --ext .ts",
42
+ "typecheck": "tsc --noEmit",
43
+ "prepublishOnly": "npm run build"
44
+ },
45
+ "publishConfig": {
46
+ "access": "public"
47
+ },
48
+ "engines": {
49
+ "node": ">=18.0.0"
50
+ },
51
+ "dependencies": {
52
+ "@babel/parser": "^7.29.2",
53
+ "@babel/traverse": "^7.29.0",
54
+ "@babel/types": "^7.29.0",
55
+ "boxen": "^8.0.1",
56
+ "chalk": "^5.6.2",
57
+ "cli-table3": "^0.6.5",
58
+ "commander": "^14.0.3",
59
+ "fast-glob": "^3.3.3",
60
+ "gradient-string": "^3.0.0",
61
+ "ora": "^9.3.0"
62
+ },
63
+ "devDependencies": {
64
+ "@babel/core": "^7.29.0",
65
+ "@types/babel__traverse": "^7.28.0",
66
+ "@types/node": "^25.5.0",
67
+ "tsup": "^8.5.1",
68
+ "typescript": "^6.0.2",
69
+ "vitest": "^4.1.2"
70
+ }
71
+ }