errlens 1.0.5 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -0
- package/bin/index.js +73 -21
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -84,6 +84,53 @@ Get machine-readable results for your own tooling or automated reports:
|
|
|
84
84
|
errlens "is not a function" --json
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
+
Run a script and write the JSON report directly to a file in CI:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
errlens run test.js --json > ci-report.json
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
In `--json` mode, ErrLens prints only JSON (no spinner, colors, or terminal boxes).
|
|
94
|
+
|
|
95
|
+
Example response from `run`:
|
|
96
|
+
|
|
97
|
+
```json
|
|
98
|
+
{
|
|
99
|
+
"code": 0,
|
|
100
|
+
"count": 0,
|
|
101
|
+
"matches": []
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Example response from `analyze <errorString>` (match found):
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"code": 1,
|
|
110
|
+
"count": 1,
|
|
111
|
+
"matches": [
|
|
112
|
+
{
|
|
113
|
+
"name": "TypeError: Cannot read properties of undefined",
|
|
114
|
+
"match": "Cannot read properties of undefined",
|
|
115
|
+
"explanation": "You are trying to access a property on a variable that is currently empty.",
|
|
116
|
+
"why": "The variable wasn't initialized, or an API call hasn't finished yet.",
|
|
117
|
+
"fixes": [
|
|
118
|
+
"Use optional chaining: user?.name",
|
|
119
|
+
"Set a default value: data || []"
|
|
120
|
+
],
|
|
121
|
+
"example": "const name = user?.name || 'Guest';"
|
|
122
|
+
}
|
|
123
|
+
]
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Exit codes (useful for CI):
|
|
128
|
+
|
|
129
|
+
- `run <file>` exits with the child process exit code.
|
|
130
|
+
- `analyze <errorString>` exits with `1` when matches are found (intentional, so CI can fail when known errors are detected), otherwise `0`.
|
|
131
|
+
|
|
132
|
+
This follows Unix conventions where `0` means success and non-zero means failure. If you prefer success-on-detection in CI, invert the check in your pipeline logic (for example, treat exit code `1` from `analyze <errorString>` as a pass condition).
|
|
133
|
+
|
|
87
134
|
---
|
|
88
135
|
|
|
89
136
|
## 🧠 System Architecture
|
package/bin/index.js
CHANGED
|
@@ -1,75 +1,127 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const { Command } = require("commander");
|
|
4
4
|
const { spawn } = require("child_process");
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
const chalk = require("chalk");
|
|
7
7
|
const path = require("path");
|
|
8
8
|
const { findError } = require("../lib/matcher");
|
|
9
9
|
const { formatError } = require("../lib/formatter");
|
|
10
10
|
|
|
11
|
+
const { version } = require("../package.json");
|
|
11
12
|
const program = new Command();
|
|
12
13
|
|
|
13
14
|
program
|
|
14
15
|
.name("errlens")
|
|
15
16
|
.description("Professional JS Error Analytics")
|
|
16
|
-
.version(
|
|
17
|
+
.version(version);
|
|
17
18
|
|
|
19
|
+
// ----------------- RUN COMMAND -----------------
|
|
18
20
|
program
|
|
19
21
|
.command("run <file>")
|
|
22
|
+
.option('--json', 'Output JSON instead of pretty UI')
|
|
20
23
|
.description("Run a Javascript file and analyze crashes")
|
|
21
|
-
.action((file) => {
|
|
24
|
+
.action(async (file, options) => {
|
|
25
|
+
const { default: ora } = await import("ora");
|
|
22
26
|
const filePath = path.resolve(process.cwd(), file);
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
// This allows us to pipe stdout and stderr while keeping the process interactive
|
|
27
|
+
const isJson = Boolean(options.json);
|
|
28
|
+
const spinner = isJson ? null : ora(`Running ${chalk.yellow(file)}...`).start();
|
|
29
|
+
|
|
27
30
|
const child = spawn(process.execPath, [filePath], { stdio: ["inherit", "pipe", "pipe"] });
|
|
28
31
|
|
|
29
32
|
let errorOutput = "";
|
|
30
33
|
|
|
31
|
-
// Stream logs to terminal in
|
|
34
|
+
// Stream logs to terminal in real-time
|
|
32
35
|
child.stdout.on("data", (data) => {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
if (!isJson) {
|
|
37
|
+
spinner.stop();
|
|
38
|
+
process.stdout.write(data);
|
|
39
|
+
spinner.start();
|
|
40
|
+
}
|
|
37
41
|
});
|
|
38
42
|
|
|
39
43
|
// Capture stderr for analysis
|
|
40
44
|
child.stderr.on("data", (data) => {
|
|
41
45
|
errorOutput += data.toString();
|
|
46
|
+
|
|
47
|
+
if (!isJson) {
|
|
48
|
+
process.stderr.write(data);
|
|
49
|
+
}
|
|
42
50
|
});
|
|
43
51
|
|
|
44
52
|
child.on("close", (code, signal) => {
|
|
45
|
-
|
|
53
|
+
if (!isJson) {
|
|
54
|
+
spinner.stop();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const { count, matches } = findError(errorOutput);
|
|
46
58
|
|
|
47
59
|
if (code === null) {
|
|
48
|
-
|
|
60
|
+
if (isJson) {
|
|
61
|
+
const result = { code: 1, count, matches };
|
|
62
|
+
console.log(JSON.stringify(result, null, 2));
|
|
63
|
+
} else {
|
|
64
|
+
console.log(chalk.red.bold(`\n⚠️ Process killed by signal: ${signal}`));
|
|
65
|
+
}
|
|
49
66
|
process.exit(1);
|
|
50
67
|
return;
|
|
51
68
|
}
|
|
52
69
|
|
|
53
|
-
if (
|
|
54
|
-
|
|
70
|
+
if (isJson) {
|
|
71
|
+
const result = { code, count, matches };
|
|
72
|
+
console.log(JSON.stringify(result, null, 2));
|
|
73
|
+
} else if (code === 0) {
|
|
74
|
+
console.log(chalk.green.bold("\n✨ Process finished successfully."));
|
|
55
75
|
} else {
|
|
56
|
-
const { count, matches } = findError(errorOutput);
|
|
57
|
-
|
|
58
76
|
if (count > 0) {
|
|
59
77
|
console.log(chalk.bold.cyan(`\n🚀 ErrLens Analysis (${count} Issue(s)):`));
|
|
60
|
-
matches.forEach(m => console.log(formatError(m)));
|
|
78
|
+
matches.forEach(m => { console.log(formatError(m)); }); // Pretty UI only here
|
|
61
79
|
} else {
|
|
62
80
|
console.log(chalk.red.bold("\n❌ Crash detected (No known fix in database):"));
|
|
63
81
|
console.log(chalk.gray(errorOutput));
|
|
64
82
|
}
|
|
65
83
|
}
|
|
84
|
+
|
|
66
85
|
process.exit(code ?? 1);
|
|
67
86
|
});
|
|
68
87
|
|
|
69
88
|
child.on("error", (err) => {
|
|
70
|
-
|
|
89
|
+
if (isJson) {
|
|
90
|
+
const result = { code: 1, count: 0, matches: [] };
|
|
91
|
+
console.log(JSON.stringify(result, null, 2));
|
|
92
|
+
} else {
|
|
93
|
+
spinner.fail(chalk.red(`System Error: ${err.message}`));
|
|
94
|
+
}
|
|
71
95
|
process.exit(1);
|
|
72
96
|
});
|
|
73
97
|
});
|
|
74
98
|
|
|
99
|
+
// ----------------- ANALYZE COMMAND -----------------
|
|
100
|
+
program
|
|
101
|
+
.arguments("<errorString>") // default command if no "run"
|
|
102
|
+
.description("Analyze a specific error string")
|
|
103
|
+
.option('--json', 'Output result in JSON format')
|
|
104
|
+
.action((errorString, options) => {
|
|
105
|
+
const { count, matches } = findError(errorString);
|
|
106
|
+
const exitCode = count > 0 ? 1 : 0;
|
|
107
|
+
const isJson = Boolean(options.json);
|
|
108
|
+
|
|
109
|
+
if (isJson) {
|
|
110
|
+
console.log(JSON.stringify({ code: exitCode, count, matches }, null, 2));
|
|
111
|
+
process.exit(exitCode);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (count > 0) {
|
|
116
|
+
console.log(chalk.bold.cyan(`\n🚀 ErrLens Analysis (${count} Issue(s)):`));
|
|
117
|
+
matches.forEach(m => { console.log(formatError(m)); }); // Pretty UI
|
|
118
|
+
} else {
|
|
119
|
+
console.log(chalk.red.bold("\n❌ Crash detected (No known fix in database):"));
|
|
120
|
+
console.log(chalk.gray(errorString));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
process.exit(exitCode);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// ----------------- PARSE ARGUMENTS -----------------
|
|
75
127
|
program.parse(process.argv);
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "errlens",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "Professional CLI tool that explains JavaScript and Node.js errors in plain English with actionable fixes directly in your terminal.",
|
|
5
5
|
"main": "./bin/index.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"errlens": "
|
|
7
|
+
"errlens": "bin/index.js"
|
|
8
8
|
},
|
|
9
9
|
"author": "BeyteFlow (https://github.com/BeyteFlow)",
|
|
10
10
|
"license": "MIT",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
},
|
|
37
37
|
"repository": {
|
|
38
38
|
"type": "git",
|
|
39
|
-
"url": "https://github.com/BeyteFlow/errlens.git"
|
|
39
|
+
"url": "git+https://github.com/BeyteFlow/errlens.git"
|
|
40
40
|
},
|
|
41
41
|
"bugs": {
|
|
42
42
|
"url": "https://github.com/BeyteFlow/errlens/issues"
|