diff --git a/bin/index.js b/bin/index.js index 3e66794..acb7400 100644 --- a/bin/index.js +++ b/bin/index.js @@ -1,151 +1,33 @@ -#!/usr/bin/env node +const database = require('../lib/database'); +const Fuse = require('fuse.js'); +const { Command } = require('commander'); -const { Command } = require("commander"); -const { spawn } = require("child_process"); -const path = require("path"); -const { findError } = require("../lib/matcher"); -const { formatError } = require("../lib/formatter"); -const { version } = require("../package.json"); +const fuse = new Fuse(database, { keys: ['pattern'] }); const program = new Command(); program - .name("errlens") - .description("Professional JS Error Analytics") - .version(version) - .option("--json", "Output JSON instead of pretty UI"); // ✅ GLOBAL OPTION + .name('errlens') + .description('Translate errors to human-readable insights') + .version('1.0.9'); -// ----------------- RUN COMMAND ----------------- program - .command("run ") - .description("Run a Javascript file and analyze crashes") - .action(async (file) => { - const { default: ora } = await import("ora"); - const { default: chalk } = await import("chalk"); - - const isJson = Boolean(program.opts().json); - const filePath = path.resolve(process.cwd(), file); - const spinner = isJson - ? null - : ora(`Running ${chalk.yellow(file)}...`).start(); - - const child = spawn(process.execPath, [filePath], { - stdio: ["inherit", "pipe", "pipe"], - }); - - let errorOutput = ""; - - // Stream stdout only in pretty mode - child.stdout.on("data", (data) => { - if (!isJson) { - spinner.stop(); - process.stdout.write(data); - spinner.start(); - } - }); - - // Capture stderr (DO NOT print in JSON mode) - child.stderr.on("data", (data) => { - errorOutput += data.toString(); - - if (!isJson) { - process.stderr.write(data); - } - }); - - child.on("close", (code, signal) => { - if (!isJson && spinner) { - spinner.stop(); - } - - const { count, matches } = findError(errorOutput); - - // Process killed by signal - if (code === null) { - const result = { code: 1, count, matches }; - - if (isJson) { - console.log(JSON.stringify(result, null, 2)); - } else { - console.log( - chalk.red.bold(`\n⚠️ Process killed by signal: ${signal}`) - ); - } - - process.exit(1); - } - - // JSON MODE - if (isJson) { - console.log(JSON.stringify({ code, count, matches }, null, 2)); - process.exit(code ?? 1); - } - - // PRETTY MODE - if (code === 0) { - console.log(chalk.green.bold("\n✨ Process finished successfully.")); - } else { - if (count > 0) { - console.log( - chalk.bold.cyan(`\n🚀 ErrLens Analysis (${count} Issue(s)):`) - ); - matches.forEach((m) => console.log(formatError(m))); - } else { - console.log( - chalk.red.bold("\n❌ Crash detected (No known fix in database):") - ); - console.log(chalk.gray(errorOutput)); - } - } - - process.exit(code ?? 1); - }); - - child.on("error", (err) => { - const result = { code: 1, count: 0, matches: [] }; - - if (isJson) { - console.log(JSON.stringify(result, null, 2)); + .command('explain') + .argument('', 'error message to explain') + .option('--json', 'output in json format') + .action((message, options) => { + const results = fuse.search(message); + const result = results.length > 0 ? results[0].item : null; + + if (options.json) { + console.log(JSON.stringify(result || { message: "No explanation found" })); + } else { + if (result) { + console.log(`Explanation: ${result.explanation}\nCause: ${result.cause}\nFix: ${result.fix}`); } else { - if (spinner) spinner.stop(); - console.log(chalk.red(`System Error: ${err.message}`)); + console.log("No specific explanation found for this error."); } - - process.exit(1); - }); - }); - -// ----------------- ANALYZE COMMAND ----------------- -program - .command("analyze ") - .description("Analyze a specific error string") - .action(async (errorString) => { - const { default: chalk } = await import("chalk"); - const isJson = Boolean(program.opts().json); - const { count, matches } = findError(errorString); - const exitCode = count > 0 ? 1 : 0; - - if (isJson) { - console.log( - JSON.stringify({ code: exitCode, count, matches }, null, 2) - ); - process.exit(exitCode); } - - if (count > 0) { - console.log( - chalk.bold.cyan(`\n🚀 ErrLens Analysis (${count} Issue(s)):`) - ); - matches.forEach((m) => console.log(formatError(m))); - } else { - console.log( - chalk.red.bold("\n❌ Crash detected (No known fix in database):") - ); - console.log(chalk.gray(errorString)); - } - - process.exit(exitCode); }); -// ----------------- PARSE ----------------- program.parse(process.argv); \ No newline at end of file diff --git a/lib/database.js b/lib/database.js new file mode 100644 index 0000000..858d3f0 --- /dev/null +++ b/lib/database.js @@ -0,0 +1,32 @@ +module.exports = [ + { + pattern: "is not defined", + explanation: "You are trying to use a variable that hasn't been declared or is out of scope.", + cause: "Commonly caused by typos, missing variable declarations (var/let/const), or trying to access a variable before it is defined.", + fix: "Check for typos in the variable name. Ensure the variable is declared in the correct scope before accessing it." + }, + { + pattern: "is not a function", + explanation: "You are trying to call a value as if it were a function, but the value is of a different type (like undefined, null, or a string).", + cause: "Often happens when an object property is missing, or an asynchronous function returns an unexpected result.", + fix: "Verify that the object or property you are calling is actually a function. Use 'typeof' to check if necessary." + }, + { + pattern: "Cannot read property of undefined", + explanation: "You are trying to access a property on an object that is currently undefined.", + cause: "The object you are accessing hasn't been initialized or the API response you expected is missing.", + fix: "Use optional chaining (e.g., obj?.property) or add a null check before accessing the property." + }, + { + pattern: "Maximum call stack size exceeded", + explanation: "Your code is hitting the recursion limit of the JavaScript engine.", + cause: "Typically caused by an infinite loop in a recursive function or missing a base case.", + fix: "Review your recursive function to ensure there is a clear exit condition and that it is reachable." + }, + { + pattern: "Unexpected token", + explanation: "The JavaScript engine encountered a character it did not expect while parsing your code.", + cause: "Missing closing braces, parentheses, or commas in your syntax.", + fix: "Use an IDE with linting (like ESLint) to identify missing brackets or incorrect syntax patterns." + } +]; \ No newline at end of file