oxlint-tui 1.0.15 → 1.0.17
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 +5 -5
- package/package.json +1 -1
- package/tui.js +91 -47
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
A lightweight, dependency-free Node.js Terminal User Interface (TUI) for browsing, toggling and visualizing [oxlint](https://github.com/oxc-project/oxc) rules and the number of warnings/errors they produce when toggled ON.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+

|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
It automatically loads your local configuration to show you the status of the rules toggled in your project and allows you to toggle them by selecting a rule in the Rules pane and pressing <kbd>1</kbd>, <kbd>2</kbd>, or <kbd>3</kbd>. The config file is modified in real-time.
|
|
8
8
|
|
|
9
9
|
**NOTE**: At the moment, comments will be erased from your configuration file when adding or toggling rules.
|
|
10
10
|
|
|
@@ -60,8 +60,8 @@ oxlint-tui
|
|
|
60
60
|
| **1** | Set selected rule to "off" |
|
|
61
61
|
| **2** | Set selected rule to "warn" |
|
|
62
62
|
| **3** | Set selected rule to "error" |
|
|
63
|
-
| **
|
|
64
|
-
| **
|
|
63
|
+
| **x** | Run "oxlint" with the selected rule |
|
|
64
|
+
| **r** | Run "oxlint with all enabled rules |
|
|
65
65
|
| **Enter** | Open Rule Documentation in Browser |
|
|
66
66
|
| **q** / **Esc** | Quit |
|
|
67
67
|
|
|
@@ -78,4 +78,4 @@ If you're willing and able, please feel free to [contribute to this project](htt
|
|
|
78
78
|
|
|
79
79
|
## License
|
|
80
80
|
|
|
81
|
-
MIT
|
|
81
|
+
MIT
|
package/package.json
CHANGED
package/tui.js
CHANGED
|
@@ -37,7 +37,7 @@ const KEY_MAP = {
|
|
|
37
37
|
3: { type: "SET_STATUS", value: "error" },
|
|
38
38
|
q: { type: "EXIT" },
|
|
39
39
|
r: { type: "RUN_LINT" },
|
|
40
|
-
|
|
40
|
+
x: { type: "RUN_SINGLE_RULE" },
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
let state = {
|
|
@@ -81,19 +81,40 @@ function updateConfig(rule, newStatus) {
|
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
function runLint(
|
|
84
|
+
function runLint({ typeAware = false, rule = null } = {}) {
|
|
85
85
|
if (state.isLinting) return;
|
|
86
86
|
|
|
87
87
|
state.isLinting = true;
|
|
88
|
-
|
|
88
|
+
|
|
89
|
+
let ruleName = rule ? `${rule.scope}/${rule.value}` : null;
|
|
90
|
+
typeAware = typeAware || rule?.type_aware;
|
|
91
|
+
|
|
92
|
+
state.message = "Linting";
|
|
93
|
+
if (ruleName) state.message += ` [${ruleName}]`;
|
|
94
|
+
if (typeAware) state.message += " with --type-aware";
|
|
95
|
+
state.message += "...";
|
|
96
|
+
|
|
89
97
|
state.messageType = "info";
|
|
98
|
+
|
|
90
99
|
render();
|
|
91
100
|
|
|
92
101
|
const npxCmd = platform === "win32" ? "npx.cmd" : "npx";
|
|
93
102
|
|
|
94
|
-
const args =
|
|
95
|
-
|
|
96
|
-
|
|
103
|
+
const args = ["-q", "--yes", "--package", `oxlint@${OXLINT_VERSION}`];
|
|
104
|
+
|
|
105
|
+
if (typeAware) {
|
|
106
|
+
args.push("--package", `oxlint-tsgolint@${TSGOLINT_VERSION}`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
args.push("--", "oxlint");
|
|
110
|
+
|
|
111
|
+
if (typeAware) {
|
|
112
|
+
args.push("--type-aware");
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (ruleName) {
|
|
116
|
+
args.push("-A", "all", "-D", ruleName);
|
|
117
|
+
}
|
|
97
118
|
|
|
98
119
|
const child = spawn(npxCmd, args);
|
|
99
120
|
|
|
@@ -116,14 +137,17 @@ function runLint(type_aware) {
|
|
|
116
137
|
);
|
|
117
138
|
|
|
118
139
|
if (summaryMatch) {
|
|
119
|
-
state.message = summaryMatch[0];
|
|
120
140
|
const errors = parseInt(summaryMatch[2]);
|
|
141
|
+
state.message = ruleName
|
|
142
|
+
? `[${ruleName}] Found ${errors} issue${errors === 1 ? "" : "s"}`
|
|
143
|
+
: (state.message = summaryMatch[0]);
|
|
121
144
|
state.messageType = errors > 0 ? "error" : "warn";
|
|
122
145
|
} else if (
|
|
123
146
|
stdoutData.toLowerCase().includes("finished") ||
|
|
124
147
|
(code === 0 && stdoutData.length < 200)
|
|
125
148
|
) {
|
|
126
149
|
state.message = "Linting passed! 0 issues found.";
|
|
150
|
+
if (ruleName) state.message = `[${ruleName}] ${state.message}`;
|
|
127
151
|
state.messageType = "success";
|
|
128
152
|
} else {
|
|
129
153
|
const cleanError = stderrData
|
|
@@ -145,7 +169,9 @@ function runLint(type_aware) {
|
|
|
145
169
|
});
|
|
146
170
|
}
|
|
147
171
|
|
|
148
|
-
function
|
|
172
|
+
function execute(action) {
|
|
173
|
+
if (!action) return;
|
|
174
|
+
|
|
149
175
|
const {
|
|
150
176
|
categories,
|
|
151
177
|
rulesByCategory,
|
|
@@ -160,10 +186,39 @@ function reducer(state, action) {
|
|
|
160
186
|
const catViewHeight = viewHeight - statsHeight;
|
|
161
187
|
|
|
162
188
|
switch (action.type) {
|
|
189
|
+
case "EXIT":
|
|
190
|
+
exitAltScreen();
|
|
191
|
+
exit(0);
|
|
192
|
+
return;
|
|
193
|
+
|
|
194
|
+
case "RUN_LINT":
|
|
195
|
+
const allRules = Object.values(state.rulesByCategory).flat();
|
|
196
|
+
const hasActiveTypeAwareRule = allRules.some(
|
|
197
|
+
(rule) => rule.isActive && rule.type_aware === true
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
runLint({ typeAware: hasActiveTypeAwareRule });
|
|
201
|
+
runLint();
|
|
202
|
+
return;
|
|
203
|
+
|
|
204
|
+
case "RUN_SINGLE_RULE": {
|
|
205
|
+
const rule = currentRules[selectedRuleIdx];
|
|
206
|
+
if (rule) runLint({ rule });
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
case "OPEN_DOCS": {
|
|
211
|
+
if (activePane === 1) {
|
|
212
|
+
const rule = currentRules[selectedRuleIdx];
|
|
213
|
+
if (rule) openUrl(rule.docs_url || rule.url);
|
|
214
|
+
}
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
163
218
|
case "SET_STATUS": {
|
|
164
|
-
if (activePane !== 1) return
|
|
219
|
+
if (activePane !== 1) return;
|
|
165
220
|
const rule = currentRules[selectedRuleIdx];
|
|
166
|
-
if (!rule) return
|
|
221
|
+
if (!rule) return;
|
|
167
222
|
updateConfig(rule, action.value);
|
|
168
223
|
const updatedRules = [...currentRules];
|
|
169
224
|
updatedRules[selectedRuleIdx] = {
|
|
@@ -171,7 +226,7 @@ function reducer(state, action) {
|
|
|
171
226
|
configStatus: action.value,
|
|
172
227
|
isActive: action.value === "error" || action.value === "warn",
|
|
173
228
|
};
|
|
174
|
-
|
|
229
|
+
state = {
|
|
175
230
|
...state,
|
|
176
231
|
message: `Rule '${rule.value}' set to: ${action.value}`,
|
|
177
232
|
messageType: "info",
|
|
@@ -180,19 +235,29 @@ function reducer(state, action) {
|
|
|
180
235
|
[currentCat]: updatedRules,
|
|
181
236
|
},
|
|
182
237
|
};
|
|
238
|
+
render();
|
|
239
|
+
return;
|
|
183
240
|
}
|
|
241
|
+
|
|
184
242
|
case "MOVE_RIGHT":
|
|
185
|
-
if (activePane !== 1)
|
|
186
|
-
|
|
243
|
+
if (activePane !== 1) {
|
|
244
|
+
state = { ...state, activePane: activePane + 1 };
|
|
245
|
+
render();
|
|
246
|
+
}
|
|
247
|
+
return;
|
|
187
248
|
|
|
188
249
|
case "MOVE_LEFT":
|
|
189
|
-
if (activePane !== 0)
|
|
190
|
-
|
|
250
|
+
if (activePane !== 0) {
|
|
251
|
+
state = { ...state, activePane: activePane - 1 };
|
|
252
|
+
render();
|
|
253
|
+
}
|
|
254
|
+
return;
|
|
255
|
+
|
|
191
256
|
case "MOVE_UP":
|
|
192
257
|
if (activePane === 0) {
|
|
193
258
|
const nextIdx =
|
|
194
259
|
selectedCatIdx === 0 ? categories.length - 1 : selectedCatIdx - 1;
|
|
195
|
-
|
|
260
|
+
state = {
|
|
196
261
|
...state,
|
|
197
262
|
selectedCatIdx: nextIdx,
|
|
198
263
|
selectedRuleIdx: 0,
|
|
@@ -202,18 +267,20 @@ function reducer(state, action) {
|
|
|
202
267
|
} else if (activePane === 1) {
|
|
203
268
|
const nextIdx =
|
|
204
269
|
selectedRuleIdx === 0 ? currentRules.length - 1 : selectedRuleIdx - 1;
|
|
205
|
-
|
|
270
|
+
state = {
|
|
206
271
|
...state,
|
|
207
272
|
selectedRuleIdx: nextIdx,
|
|
208
273
|
scrollRule: updateScroll(nextIdx, state.scrollRule, viewHeight),
|
|
209
274
|
};
|
|
210
275
|
}
|
|
211
|
-
|
|
276
|
+
render();
|
|
277
|
+
return;
|
|
278
|
+
|
|
212
279
|
case "MOVE_DOWN":
|
|
213
280
|
if (activePane === 0) {
|
|
214
281
|
const nextIdx =
|
|
215
282
|
selectedCatIdx === categories.length - 1 ? 0 : selectedCatIdx + 1;
|
|
216
|
-
|
|
283
|
+
state = {
|
|
217
284
|
...state,
|
|
218
285
|
selectedCatIdx: nextIdx,
|
|
219
286
|
selectedRuleIdx: 0,
|
|
@@ -223,15 +290,14 @@ function reducer(state, action) {
|
|
|
223
290
|
} else if (activePane === 1) {
|
|
224
291
|
const nextIdx =
|
|
225
292
|
selectedRuleIdx === currentRules.length - 1 ? 0 : selectedRuleIdx + 1;
|
|
226
|
-
|
|
293
|
+
state = {
|
|
227
294
|
...state,
|
|
228
295
|
selectedRuleIdx: nextIdx,
|
|
229
296
|
scrollRule: updateScroll(nextIdx, state.scrollRule, viewHeight),
|
|
230
297
|
};
|
|
231
298
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
return state;
|
|
299
|
+
render();
|
|
300
|
+
return;
|
|
235
301
|
}
|
|
236
302
|
}
|
|
237
303
|
|
|
@@ -553,7 +619,7 @@ function render() {
|
|
|
553
619
|
? `Config: ${state.configPath}`
|
|
554
620
|
: "No config loaded";
|
|
555
621
|
buffer.push(
|
|
556
|
-
`\x1b[${rows - 1};2H${COLORS.dim}Arrows/HJKL: Nav | 1-3: Status | R: Lint |
|
|
622
|
+
`\x1b[${rows - 1};2H${COLORS.dim}Arrows/HJKL: Nav | 1-3: Status | R: Lint | X: Run rule | Enter: Docs | Q: Quit | ${footerConfig}${COLORS.reset}`,
|
|
557
623
|
);
|
|
558
624
|
write(buffer.join(""));
|
|
559
625
|
}
|
|
@@ -567,29 +633,7 @@ stdin.on("keypress", (_, key) => {
|
|
|
567
633
|
(key.ctrl && key.name === "c"
|
|
568
634
|
? { type: "EXIT" }
|
|
569
635
|
: KEY_MAP[key.sequence] || null);
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
if (action.type === "EXIT") {
|
|
573
|
-
exitAltScreen();
|
|
574
|
-
exit(0);
|
|
575
|
-
}
|
|
576
|
-
if (action.type === "RUN_LINT") {
|
|
577
|
-
runLint(false);
|
|
578
|
-
return;
|
|
579
|
-
}
|
|
580
|
-
if (action.type === "RUN_TYPE_AWARE_LINT") {
|
|
581
|
-
runLint(true);
|
|
582
|
-
return;
|
|
583
|
-
}
|
|
584
|
-
if (action.type === "OPEN_DOCS" && state.activePane === 1) {
|
|
585
|
-
const currentCat = state.categories[state.selectedCatIdx];
|
|
586
|
-
const rule = state.rulesByCategory[currentCat]?.[state.selectedRuleIdx];
|
|
587
|
-
if (rule) openUrl(rule.docs_url || rule.url);
|
|
588
|
-
return;
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
state = reducer(state, action);
|
|
592
|
-
render();
|
|
636
|
+
execute(action);
|
|
593
637
|
});
|
|
594
638
|
|
|
595
639
|
stdout.on("resize", render);
|