eslint-interactive 13.0.0 → 14.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.
- package/README.md +19 -10
- package/dist/action/convert-error-to-warning-per-file.d.ts +4 -0
- package/dist/action/convert-error-to-warning-per-file.d.ts.map +1 -0
- package/dist/action/convert-error-to-warning-per-file.js +8 -0
- package/dist/action/convert-error-to-warning-per-file.js.map +1 -0
- package/dist/action/disable-per-file.d.ts +4 -0
- package/dist/action/disable-per-file.d.ts.map +1 -0
- package/dist/action/disable-per-file.js +12 -0
- package/dist/action/disable-per-file.js.map +1 -0
- package/dist/action/disable-per-line.d.ts +4 -0
- package/dist/action/disable-per-line.d.ts.map +1 -0
- package/dist/action/disable-per-line.js +12 -0
- package/dist/action/disable-per-line.js.map +1 -0
- package/dist/action/fix.d.ts +4 -0
- package/dist/action/fix.d.ts.map +1 -0
- package/dist/action/fix.js +6 -0
- package/dist/action/fix.js.map +1 -0
- package/dist/action/index.d.ts +6 -0
- package/dist/action/index.d.ts.map +1 -0
- package/dist/action/index.js +6 -0
- package/dist/action/index.js.map +1 -0
- package/dist/action/print-result-details.d.ts +4 -0
- package/dist/action/print-result-details.d.ts.map +1 -0
- package/dist/action/print-result-details.js +36 -0
- package/dist/action/print-result-details.js.map +1 -0
- package/dist/cli/log.d.ts +7 -0
- package/dist/cli/log.d.ts.map +1 -0
- package/dist/cli/log.js +35 -0
- package/dist/cli/log.js.map +1 -0
- package/dist/cli/package.d.ts +2 -0
- package/dist/cli/package.d.ts.map +1 -0
- package/dist/cli/package.js +6 -0
- package/dist/cli/package.js.map +1 -0
- package/dist/cli/pager.d.ts +2 -0
- package/dist/cli/pager.d.ts.map +1 -0
- package/dist/cli/pager.js +34 -0
- package/dist/cli/pager.js.map +1 -0
- package/dist/cli/parse-argv.d.ts +4 -0
- package/dist/cli/parse-argv.d.ts.map +1 -0
- package/dist/cli/parse-argv.js +103 -0
- package/dist/cli/parse-argv.js.map +1 -0
- package/dist/cli/prompt.d.ts +51 -0
- package/dist/cli/prompt.d.ts.map +1 -0
- package/dist/cli/prompt.js +97 -0
- package/dist/cli/prompt.js.map +1 -0
- package/dist/cli/run.d.ts +6 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +28 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/core.d.ts +82 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +189 -0
- package/dist/core.js.map +1 -0
- package/dist/eslint/linter.d.ts +18 -0
- package/dist/eslint/linter.d.ts.map +1 -0
- package/dist/eslint/linter.js +71 -0
- package/dist/eslint/linter.js.map +1 -0
- package/dist/eslint/report-translator.d.ts +9 -0
- package/dist/eslint/report-translator.d.ts.map +1 -0
- package/dist/eslint/report-translator.js +75 -0
- package/dist/eslint/report-translator.js.map +1 -0
- package/dist/eslint/rule-fixer.d.ts +80 -0
- package/dist/eslint/rule-fixer.d.ts.map +1 -0
- package/dist/eslint/rule-fixer.js +114 -0
- package/dist/eslint/rule-fixer.js.map +1 -0
- package/dist/eslint/source-code-fixer.d.ts +15 -0
- package/dist/eslint/source-code-fixer.d.ts.map +1 -0
- package/dist/eslint/source-code-fixer.js +131 -0
- package/dist/eslint/source-code-fixer.js.map +1 -0
- package/dist/fix/apply-auto-fixes.d.ts +8 -0
- package/dist/fix/apply-auto-fixes.d.ts.map +1 -0
- package/dist/fix/apply-auto-fixes.js +8 -0
- package/dist/fix/apply-auto-fixes.js.map +1 -0
- package/dist/fix/apply-suggestions.d.ts +11 -0
- package/dist/fix/apply-suggestions.d.ts.map +1 -0
- package/dist/fix/apply-suggestions.js +25 -0
- package/dist/fix/apply-suggestions.js.map +1 -0
- package/dist/fix/convert-error-to-warning-per-file.d.ts +10 -0
- package/dist/fix/convert-error-to-warning-per-file.d.ts.map +1 -0
- package/dist/fix/convert-error-to-warning-per-file.js +28 -0
- package/dist/fix/convert-error-to-warning-per-file.js.map +1 -0
- package/dist/fix/disable-per-file.d.ts +12 -0
- package/dist/fix/disable-per-file.d.ts.map +1 -0
- package/dist/fix/disable-per-file.js +63 -0
- package/dist/fix/disable-per-file.js.map +1 -0
- package/dist/fix/disable-per-line.d.ts +12 -0
- package/dist/fix/disable-per-line.d.ts.map +1 -0
- package/dist/fix/disable-per-line.js +72 -0
- package/dist/fix/disable-per-line.js.map +1 -0
- package/dist/fix/index.d.ts +19 -0
- package/dist/fix/index.d.ts.map +1 -0
- package/dist/fix/index.js +8 -0
- package/dist/fix/index.js.map +1 -0
- package/dist/fix/make-fixable-and-fix.d.ts +11 -0
- package/dist/fix/make-fixable-and-fix.d.ts.map +1 -0
- package/dist/fix/make-fixable-and-fix.js +35 -0
- package/dist/fix/make-fixable-and-fix.js.map +1 -0
- package/dist/formatter/colors.d.ts +4 -0
- package/dist/formatter/colors.d.ts.map +1 -0
- package/dist/formatter/colors.js +5 -0
- package/dist/formatter/colors.js.map +1 -0
- package/dist/formatter/filter-rule-statistics.d.ts +9 -0
- package/dist/formatter/filter-rule-statistics.d.ts.map +1 -0
- package/dist/formatter/filter-rule-statistics.js +22 -0
- package/dist/formatter/filter-rule-statistics.js.map +1 -0
- package/dist/formatter/format-by-files.d.ts +3 -0
- package/dist/formatter/format-by-files.d.ts.map +1 -0
- package/dist/formatter/format-by-files.js +42 -0
- package/dist/formatter/format-by-files.js.map +1 -0
- package/dist/formatter/format-by-rules.d.ts +9 -0
- package/dist/formatter/format-by-rules.d.ts.map +1 -0
- package/dist/formatter/format-by-rules.js +33 -0
- package/dist/formatter/format-by-rules.js.map +1 -0
- package/dist/formatter/format-table.d.ts +4 -0
- package/dist/formatter/format-table.d.ts.map +1 -0
- package/dist/formatter/format-table.js +62 -0
- package/dist/formatter/format-table.js.map +1 -0
- package/dist/formatter/index.d.ts +7 -0
- package/dist/formatter/index.d.ts.map +1 -0
- package/dist/formatter/index.js +9 -0
- package/dist/formatter/index.js.map +1 -0
- package/dist/formatter/sort-rule-statistics.d.ts +5 -0
- package/dist/formatter/sort-rule-statistics.d.ts.map +1 -0
- package/dist/formatter/sort-rule-statistics.js +34 -0
- package/dist/formatter/sort-rule-statistics.js.map +1 -0
- package/dist/formatter/take-rule-statistics.d.ts +18 -0
- package/dist/formatter/take-rule-statistics.d.ts.map +1 -0
- package/dist/formatter/take-rule-statistics.js +51 -0
- package/dist/formatter/take-rule-statistics.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.d.ts +4 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +87 -0
- package/dist/plugin.js.map +1 -0
- package/dist/scene/check-results.d.ts +21 -0
- package/dist/scene/check-results.d.ts.map +1 -0
- package/dist/scene/check-results.js +19 -0
- package/dist/scene/check-results.js.map +1 -0
- package/dist/scene/index.d.ts +25 -0
- package/dist/scene/index.d.ts.map +1 -0
- package/dist/scene/index.js +6 -0
- package/dist/scene/index.js.map +1 -0
- package/dist/scene/lint.d.ts +7 -0
- package/dist/scene/lint.d.ts.map +1 -0
- package/dist/scene/lint.js +34 -0
- package/dist/scene/lint.js.map +1 -0
- package/dist/scene/select-action.d.ts +19 -0
- package/dist/scene/select-action.d.ts.map +1 -0
- package/dist/scene/select-action.js +44 -0
- package/dist/scene/select-action.js.map +1 -0
- package/dist/scene/select-rule-ids.d.ts +14 -0
- package/dist/scene/select-rule-ids.d.ts.map +1 -0
- package/dist/scene/select-rule-ids.js +10 -0
- package/dist/scene/select-rule-ids.js.map +1 -0
- package/dist/type.d.ts +14 -0
- package/dist/type.d.ts.map +1 -0
- package/dist/type.js +2 -0
- package/dist/type.js.map +1 -0
- package/dist/util/array.d.ts +3 -0
- package/dist/util/array.d.ts.map +1 -0
- package/dist/util/array.js +14 -0
- package/dist/util/array.js.map +1 -0
- package/dist/util/eslint.d.ts +103 -0
- package/dist/util/eslint.d.ts.map +1 -0
- package/dist/util/eslint.js +220 -0
- package/dist/util/eslint.js.map +1 -0
- package/dist/util/terminal-link.d.ts +2 -0
- package/dist/util/terminal-link.d.ts.map +1 -0
- package/dist/util/terminal-link.js +16 -0
- package/dist/util/terminal-link.js.map +1 -0
- package/dist/util/type-check.d.ts +3 -0
- package/dist/util/type-check.d.ts.map +1 -0
- package/dist/util/type-check.js +8 -0
- package/dist/util/type-check.js.map +1 -0
- package/package.json +22 -24
- package/src/action/convert-error-to-warning-per-file.ts +4 -6
- package/src/action/disable-per-file.ts +4 -6
- package/src/action/disable-per-line.ts +4 -6
- package/src/action/fix.ts +4 -10
- package/src/action/print-result-details.ts +5 -9
- package/src/cli/log.ts +25 -0
- package/src/cli/parse-argv.ts +32 -11
- package/src/cli/prompt.ts +56 -92
- package/src/cli/run.ts +3 -29
- package/src/core.ts +13 -6
- package/src/fix/disable-per-file.ts +1 -1
- package/src/fix/disable-per-line.ts +1 -1
- package/src/formatter/filter-rule-statistics.ts +27 -0
- package/src/formatter/format-by-rules.ts +10 -7
- package/src/formatter/index.ts +4 -3
- package/src/index.ts +1 -1
- package/src/scene/check-results.ts +2 -5
- package/src/scene/lint.ts +14 -12
- package/src/scene/select-action.ts +2 -4
- package/src/scene/select-rule-ids.ts +2 -6
- package/src/type.ts +2 -0
- package/src/util/terminal-link.ts +16 -0
- package/src/cli/spinner.ts +0 -22
- package/src/core-worker.ts +0 -55
- package/src/typings/enquirer.d.ts +0 -7
package/src/cli/prompt.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
/* istanbul ignore file */
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import { isCancel, multiselect, select, text } from '@clack/prompts';
|
|
4
4
|
import type { ESLint } from 'eslint';
|
|
5
5
|
import { takeRuleStatistics } from '../formatter/index.js';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
function exitIfCancel<T>(value: T | symbol): T {
|
|
8
|
+
if (isCancel(value)) {
|
|
9
|
+
// eslint-disable-next-line n/no-process-exit
|
|
10
|
+
process.exit();
|
|
11
|
+
}
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* The type that indicates what to do with the problems of selected rules.
|
|
@@ -45,21 +46,13 @@ export type DescriptionPosition = 'sameLine' | 'previousLine';
|
|
|
45
46
|
* @returns The rule ids
|
|
46
47
|
*/
|
|
47
48
|
export async function promptToInputRuleIds(ruleIdsInResults: string[]): Promise<string[]> {
|
|
48
|
-
|
|
49
|
-
{
|
|
50
|
-
name: 'ruleIds',
|
|
51
|
-
type: 'multiselect',
|
|
49
|
+
return exitIfCancel(
|
|
50
|
+
await multiselect<string>({
|
|
52
51
|
message: 'Which rules would you like to apply action?',
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return value.length === 0 ? `Select at least one rule with <space> key.` : true;
|
|
58
|
-
},
|
|
59
|
-
onCancel,
|
|
60
|
-
},
|
|
61
|
-
]);
|
|
62
|
-
return ruleIds;
|
|
52
|
+
options: ruleIdsInResults.map((ruleId) => ({ value: ruleId })),
|
|
53
|
+
required: true,
|
|
54
|
+
}),
|
|
55
|
+
);
|
|
63
56
|
}
|
|
64
57
|
|
|
65
58
|
/**
|
|
@@ -81,29 +74,21 @@ export async function promptToInputAction(
|
|
|
81
74
|
{ isFixableCount: 0 },
|
|
82
75
|
);
|
|
83
76
|
|
|
84
|
-
|
|
85
|
-
{
|
|
86
|
-
{ name: 'applyAutoFixes', message: '🔧 Run `eslint --fix`', disabled: foldedStatistics.isFixableCount === 0 },
|
|
87
|
-
{ name: 'disablePerLine', message: '🔧 Disable per line' },
|
|
88
|
-
{ name: 'disablePerFile', message: '🔧 Disable per file' },
|
|
89
|
-
{ name: 'convertErrorToWarningPerFile', message: '🔧 Convert error to warning per file' },
|
|
90
|
-
{ name: 'relintAndReselectRules', message: '↩️ Go back (with re-lint)' },
|
|
91
|
-
{ name: 'reselectRules', message: '↩️ Go back' },
|
|
92
|
-
];
|
|
93
|
-
|
|
94
|
-
const { action } = await prompt<{
|
|
95
|
-
action: Action;
|
|
96
|
-
}>([
|
|
97
|
-
{
|
|
98
|
-
name: 'action',
|
|
99
|
-
type: 'select',
|
|
77
|
+
return exitIfCancel(
|
|
78
|
+
await select<Action>({
|
|
100
79
|
message: 'Which action do you want to do?',
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
80
|
+
options: [
|
|
81
|
+
{ value: 'printResultDetails', label: '🔎 Display details of lint results' },
|
|
82
|
+
{ value: 'applyAutoFixes', label: '🔧 Run `eslint --fix`', disabled: foldedStatistics.isFixableCount === 0 },
|
|
83
|
+
{ value: 'disablePerLine', label: '🔧 Disable per line' },
|
|
84
|
+
{ value: 'disablePerFile', label: '🔧 Disable per file' },
|
|
85
|
+
{ value: 'convertErrorToWarningPerFile', label: '🔧 Convert error to warning per file' },
|
|
86
|
+
{ value: 'relintAndReselectRules', label: '↩️ Go back (with re-lint)' },
|
|
87
|
+
{ value: 'reselectRules', label: '↩️ Go back' },
|
|
88
|
+
],
|
|
89
|
+
initialValue: initialAction,
|
|
90
|
+
}),
|
|
91
|
+
);
|
|
107
92
|
}
|
|
108
93
|
|
|
109
94
|
/**
|
|
@@ -111,22 +96,16 @@ export async function promptToInputAction(
|
|
|
111
96
|
* @returns How to display
|
|
112
97
|
*/
|
|
113
98
|
export async function promptToInputDisplayMode(): Promise<DisplayMode> {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}>([
|
|
117
|
-
{
|
|
118
|
-
name: 'displayMode',
|
|
119
|
-
type: 'select',
|
|
99
|
+
return exitIfCancel(
|
|
100
|
+
await select<DisplayMode>({
|
|
120
101
|
message: 'In what way are the details displayed?',
|
|
121
|
-
|
|
122
|
-
{
|
|
123
|
-
{
|
|
124
|
-
{
|
|
102
|
+
options: [
|
|
103
|
+
{ value: 'printInTerminal', label: '🖨 Print in terminal' },
|
|
104
|
+
{ value: 'printInTerminalWithPager', label: '↕️ Print in terminal with pager' },
|
|
105
|
+
{ value: 'writeToFile', label: '📝 Write to file' },
|
|
125
106
|
],
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
]);
|
|
129
|
-
return displayMode;
|
|
107
|
+
}),
|
|
108
|
+
);
|
|
130
109
|
}
|
|
131
110
|
|
|
132
111
|
/**
|
|
@@ -134,17 +113,12 @@ export async function promptToInputDisplayMode(): Promise<DisplayMode> {
|
|
|
134
113
|
* @returns The description
|
|
135
114
|
*/
|
|
136
115
|
export async function promptToInputDescription(): Promise<string | undefined> {
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
}>([
|
|
140
|
-
{
|
|
141
|
-
name: 'description',
|
|
142
|
-
type: 'input',
|
|
116
|
+
const description = exitIfCancel(
|
|
117
|
+
await text({
|
|
143
118
|
message: 'Leave a code comment with your reason for fixing (Optional)',
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
return description === '' ? undefined : description;
|
|
119
|
+
}),
|
|
120
|
+
);
|
|
121
|
+
return description.trim() === '' ? undefined : description.trim();
|
|
148
122
|
}
|
|
149
123
|
|
|
150
124
|
/**
|
|
@@ -152,21 +126,15 @@ export async function promptToInputDescription(): Promise<string | undefined> {
|
|
|
152
126
|
* @returns The description position
|
|
153
127
|
*/
|
|
154
128
|
export async function promptToInputDescriptionPosition(): Promise<DescriptionPosition> {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}>([
|
|
158
|
-
{
|
|
159
|
-
name: 'descriptionPosition',
|
|
160
|
-
type: 'select',
|
|
129
|
+
return exitIfCancel(
|
|
130
|
+
await select<DescriptionPosition>({
|
|
161
131
|
message: 'Where would you like to position the code comment?',
|
|
162
|
-
|
|
163
|
-
{
|
|
164
|
-
{
|
|
132
|
+
options: [
|
|
133
|
+
{ value: 'sameLine', label: "Same Line - Place on the same line as the eslint's disable comment." },
|
|
134
|
+
{ value: 'previousLine', label: "Previous Line - Place on the line before the eslint's disable comment." },
|
|
165
135
|
],
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
]);
|
|
169
|
-
return descriptionPosition;
|
|
136
|
+
}),
|
|
137
|
+
);
|
|
170
138
|
}
|
|
171
139
|
|
|
172
140
|
/**
|
|
@@ -174,18 +142,14 @@ export async function promptToInputDescriptionPosition(): Promise<DescriptionPos
|
|
|
174
142
|
* @returns What to do next.
|
|
175
143
|
*/
|
|
176
144
|
export async function promptToInputWhatToDoNext(): Promise<NextStep> {
|
|
177
|
-
|
|
178
|
-
{
|
|
179
|
-
name: 'nextStep',
|
|
180
|
-
type: 'select',
|
|
145
|
+
return exitIfCancel(
|
|
146
|
+
await select<NextStep>({
|
|
181
147
|
message: "What's the next step?",
|
|
182
|
-
|
|
183
|
-
{
|
|
184
|
-
{
|
|
185
|
-
{
|
|
148
|
+
options: [
|
|
149
|
+
{ value: 'fixOtherRules', label: '🔧 Fix other rules' },
|
|
150
|
+
{ value: 'undoTheFix', label: '↩️ Undo the fix' },
|
|
151
|
+
{ value: 'exit', label: '💚 Exit' },
|
|
186
152
|
],
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
]);
|
|
190
|
-
return nextStep;
|
|
153
|
+
}),
|
|
154
|
+
);
|
|
191
155
|
}
|
package/src/cli/run.ts
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
import { dirname, join } from 'node:path';
|
|
2
|
-
import { fileURLToPath } from 'node:url';
|
|
3
|
-
import { Worker } from 'node:worker_threads';
|
|
4
|
-
import { wrap } from 'comlink';
|
|
5
|
-
import nodeEndpoint from 'comlink/dist/esm/node-adapter.mjs';
|
|
6
|
-
import terminalLink from 'terminal-link';
|
|
7
1
|
import { parseArgv } from '../cli/parse-argv.js';
|
|
8
|
-
import
|
|
2
|
+
import { Core } from '../core.js';
|
|
9
3
|
import type { NextScene } from '../scene/index.js';
|
|
10
4
|
import { checkResults, lint, selectAction, selectRuleIds } from '../scene/index.js';
|
|
11
5
|
|
|
@@ -13,29 +7,10 @@ export type Options = {
|
|
|
13
7
|
argv: string[];
|
|
14
8
|
};
|
|
15
9
|
|
|
16
|
-
/**
|
|
17
|
-
* Run eslint-interactive.
|
|
18
|
-
*/
|
|
10
|
+
/** Run eslint-interactive. */
|
|
19
11
|
export async function run(options: Options) {
|
|
20
12
|
const config = parseArgv(options.argv);
|
|
21
|
-
|
|
22
|
-
// Directly executing the Core API will hog the main thread and halt the spinner.
|
|
23
|
-
// So we wrap it with comlink and run it on the Worker.
|
|
24
|
-
const worker = new Worker(join(dirname(fileURLToPath(import.meta.url)), '..', 'core-worker.js'), {
|
|
25
|
-
env: {
|
|
26
|
-
// In worker threads, stdin is recognized as noTTY. Therefore, `util.styleText` and `terminalLink` disable colors and links.
|
|
27
|
-
// To work around this, we use environment variables to force colors and links to be enabled.
|
|
28
|
-
// ref: https://github.com/nodejs/node/issues/26946
|
|
29
|
-
FORCE_COLOR: process.stdin.isTTY ? '1' : '0',
|
|
30
|
-
FORCE_HYPERLINK: terminalLink.isSupported ? '1' : '0',
|
|
31
|
-
...process.env,
|
|
32
|
-
},
|
|
33
|
-
// NOTE: Pass CLI options (--unhandled-rejections=strict, etc.) to the worker
|
|
34
|
-
execArgv: process.execArgv,
|
|
35
|
-
});
|
|
36
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
37
|
-
const ProxiedCore = wrap<typeof SerializableCore>((nodeEndpoint as any)(worker));
|
|
38
|
-
const core = await new ProxiedCore(config);
|
|
13
|
+
const core = new Core(config);
|
|
39
14
|
|
|
40
15
|
let nextScene: NextScene = { name: 'lint' };
|
|
41
16
|
while (nextScene.name !== 'exit') {
|
|
@@ -53,5 +28,4 @@ export async function run(options: Options) {
|
|
|
53
28
|
nextScene = await checkResults(nextScene.args);
|
|
54
29
|
}
|
|
55
30
|
}
|
|
56
|
-
await worker.terminate();
|
|
57
31
|
}
|
package/src/core.ts
CHANGED
|
@@ -12,9 +12,9 @@ import {
|
|
|
12
12
|
createFixToMakeFixableAndFix,
|
|
13
13
|
verifyAndFix,
|
|
14
14
|
} from './fix/index.js';
|
|
15
|
-
import { format, sortRuleStatistics, takeRuleStatistics } from './formatter/index.js';
|
|
15
|
+
import { filterRuleStatistics, format, sortRuleStatistics, takeRuleStatistics } from './formatter/index.js';
|
|
16
16
|
import { plugin } from './plugin.js';
|
|
17
|
-
import type { Config, SortField, SortOrder } from './type.js';
|
|
17
|
+
import type { Config, FilterCriterion, SortField, SortOrder } from './type.js';
|
|
18
18
|
import { filterResultsByRuleId } from './util/eslint.js';
|
|
19
19
|
|
|
20
20
|
/**
|
|
@@ -42,6 +42,7 @@ export class Core {
|
|
|
42
42
|
readonly #formatterName: string | undefined;
|
|
43
43
|
readonly #sort: SortField | undefined;
|
|
44
44
|
readonly #sortOrder: SortOrder | undefined;
|
|
45
|
+
readonly #filters: FilterCriterion[] | undefined;
|
|
45
46
|
readonly #eslint: ESLint;
|
|
46
47
|
|
|
47
48
|
constructor(config: Config) {
|
|
@@ -51,10 +52,11 @@ export class Core {
|
|
|
51
52
|
this.#formatterName = config.formatterName;
|
|
52
53
|
this.#sort = config.sort;
|
|
53
54
|
this.#sortOrder = config.sortOrder;
|
|
55
|
+
this.#filters = config.filters;
|
|
54
56
|
|
|
55
57
|
// NOTE: Passing an option that does not exist to `new ESLint(...)` will throw an error.
|
|
56
58
|
// Therefore, only options supported by ESLint are extracted into the `eslintOptions` variable.
|
|
57
|
-
const { formatterName, patterns, quiet, sort, sortOrder, ...eslintOptions } = config;
|
|
59
|
+
const { formatterName, patterns, quiet, sort, sortOrder, filters, ...eslintOptions } = config;
|
|
58
60
|
const overrideConfigs =
|
|
59
61
|
Array.isArray(eslintOptions.overrideConfig) ? eslintOptions.overrideConfig
|
|
60
62
|
: eslintOptions.overrideConfig ? [eslintOptions.overrideConfig]
|
|
@@ -89,15 +91,20 @@ export class Core {
|
|
|
89
91
|
*/
|
|
90
92
|
formatResultSummary(results: ESLint.LintResult[]): string {
|
|
91
93
|
const rulesMeta = this.#eslint.getRulesMetaForResults(results);
|
|
92
|
-
return format(
|
|
94
|
+
return format(
|
|
95
|
+
results,
|
|
96
|
+
{ rulesMeta, cwd: this.#cwd },
|
|
97
|
+
{ sort: this.#sort, sortOrder: this.#sortOrder, filters: this.#filters },
|
|
98
|
+
);
|
|
93
99
|
}
|
|
94
100
|
|
|
95
101
|
/**
|
|
96
|
-
* Returns ruleIds from lint results, sorted according to the configured
|
|
102
|
+
* Returns ruleIds from lint results, filtered and sorted according to the configured options.
|
|
97
103
|
* @param results The lint results of the project
|
|
98
104
|
*/
|
|
99
|
-
|
|
105
|
+
getFilteredAndSortedRuleIds(results: ESLint.LintResult[]): string[] {
|
|
100
106
|
let ruleStatistics = takeRuleStatistics(results);
|
|
107
|
+
ruleStatistics = filterRuleStatistics(ruleStatistics, this.#filters);
|
|
101
108
|
if (this.#sort) {
|
|
102
109
|
ruleStatistics = sortRuleStatistics(ruleStatistics, this.#sort, this.#sortOrder);
|
|
103
110
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Rule, SourceCode } from 'eslint';
|
|
2
|
-
import type { DescriptionPosition } from '
|
|
2
|
+
import type { DescriptionPosition } from '../cli/prompt.js';
|
|
3
3
|
import { mergeFixes } from '../eslint/report-translator.js';
|
|
4
4
|
import { unique } from '../util/array.js';
|
|
5
5
|
import type { DisableComment } from '../util/eslint.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Linter, Rule, SourceCode } from 'eslint';
|
|
2
|
-
import type { DescriptionPosition } from '
|
|
2
|
+
import type { DescriptionPosition } from '../cli/prompt.js';
|
|
3
3
|
import { mergeFixes } from '../eslint/report-translator.js';
|
|
4
4
|
import { groupBy, unique } from '../util/array.js';
|
|
5
5
|
import type { DisableComment } from '../util/eslint.js';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { FilterCriterion } from '../type.js';
|
|
2
|
+
import { unreachable } from '../util/type-check.js';
|
|
3
|
+
import type { RuleStatistic } from './take-rule-statistics.js';
|
|
4
|
+
|
|
5
|
+
function matchesCriterion(statistic: RuleStatistic, criterion: FilterCriterion): boolean {
|
|
6
|
+
switch (criterion) {
|
|
7
|
+
case 'fixable':
|
|
8
|
+
return statistic.isFixableCount > 0;
|
|
9
|
+
case 'has-suggestions':
|
|
10
|
+
return statistic.hasSuggestionsCount > 0;
|
|
11
|
+
default:
|
|
12
|
+
return unreachable(`Invalid filter criterion: ${criterion as string}`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Filter rule statistics by the given criteria.
|
|
18
|
+
* Multiple criteria are OR-ed together; a statistic is kept if it matches any of them.
|
|
19
|
+
* When `criteria` is undefined or empty, the input is returned unchanged.
|
|
20
|
+
*/
|
|
21
|
+
export function filterRuleStatistics(
|
|
22
|
+
statistics: RuleStatistic[],
|
|
23
|
+
criteria: readonly FilterCriterion[] | undefined,
|
|
24
|
+
): RuleStatistic[] {
|
|
25
|
+
if (!criteria || criteria.length === 0) return statistics;
|
|
26
|
+
return statistics.filter((statistic) => criteria.some((criterion) => matchesCriterion(statistic, criterion)));
|
|
27
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// eslint-disable-next-line n/no-unsupported-features/node-builtins
|
|
2
2
|
import { styleText } from 'node:util';
|
|
3
3
|
import type { ESLint } from 'eslint';
|
|
4
|
-
import
|
|
5
|
-
import
|
|
4
|
+
import type { FilterCriterion, SortField, SortOrder } from '../type.js';
|
|
5
|
+
import { terminalLink } from '../util/terminal-link.js';
|
|
6
6
|
import { ERROR_COLOR } from './colors.js';
|
|
7
|
+
import { filterRuleStatistics } from './filter-rule-statistics.js';
|
|
7
8
|
import { formatTable } from './format-table.js';
|
|
8
9
|
import { sortRuleStatistics } from './sort-rule-statistics.js';
|
|
9
10
|
import { takeRuleStatistics } from './take-rule-statistics.js';
|
|
@@ -18,9 +19,10 @@ type Row = [
|
|
|
18
19
|
hasSuggestionsCount: string,
|
|
19
20
|
];
|
|
20
21
|
|
|
21
|
-
export type
|
|
22
|
+
export type FormatByRulesOptions = {
|
|
22
23
|
sort?: SortField | undefined;
|
|
23
24
|
sortOrder?: SortOrder | undefined;
|
|
25
|
+
filters?: FilterCriterion[] | undefined;
|
|
24
26
|
};
|
|
25
27
|
|
|
26
28
|
function numCell(num: number): string {
|
|
@@ -30,11 +32,12 @@ function numCell(num: number): string {
|
|
|
30
32
|
export function formatByRules(
|
|
31
33
|
results: ESLint.LintResult[],
|
|
32
34
|
data?: ESLint.LintResultData,
|
|
33
|
-
|
|
35
|
+
options?: FormatByRulesOptions,
|
|
34
36
|
): string {
|
|
35
37
|
let ruleStatistics = takeRuleStatistics(results);
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
ruleStatistics = filterRuleStatistics(ruleStatistics, options?.filters);
|
|
39
|
+
if (options?.sort) {
|
|
40
|
+
ruleStatistics = sortRuleStatistics(ruleStatistics, options.sort, options.sortOrder);
|
|
38
41
|
}
|
|
39
42
|
|
|
40
43
|
const rows: Row[] = [];
|
|
@@ -42,7 +45,7 @@ export function formatByRules(
|
|
|
42
45
|
const { ruleId, errorCount, warningCount, isFixableCount, hasSuggestionsCount } = ruleStatistic;
|
|
43
46
|
const ruleMetaData = data?.rulesMeta[ruleId];
|
|
44
47
|
rows.push([
|
|
45
|
-
ruleMetaData?.docs?.url ? terminalLink(ruleId, ruleMetaData?.docs.url
|
|
48
|
+
ruleMetaData?.docs?.url ? terminalLink(ruleId, ruleMetaData?.docs.url) : ruleId,
|
|
46
49
|
numCell(errorCount),
|
|
47
50
|
numCell(warningCount),
|
|
48
51
|
numCell(isFixableCount),
|
package/src/formatter/index.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import type { ESLint } from 'eslint';
|
|
2
2
|
import { formatByFiles } from './format-by-files.js';
|
|
3
|
-
import { formatByRules, type
|
|
3
|
+
import { formatByRules, type FormatByRulesOptions } from './format-by-rules.js';
|
|
4
4
|
|
|
5
5
|
export { takeRuleStatistics, type RuleStatistic } from './take-rule-statistics.js';
|
|
6
6
|
export { sortRuleStatistics } from './sort-rule-statistics.js';
|
|
7
|
+
export { filterRuleStatistics } from './filter-rule-statistics.js';
|
|
7
8
|
|
|
8
9
|
export function format(
|
|
9
10
|
results: ESLint.LintResult[],
|
|
10
11
|
data?: ESLint.LintResultData,
|
|
11
|
-
|
|
12
|
+
options?: FormatByRulesOptions,
|
|
12
13
|
): string {
|
|
13
|
-
return `${formatByFiles(results)}\n${formatByRules(results, data,
|
|
14
|
+
return `${formatByFiles(results)}\n${formatByRules(results, data, options)}`;
|
|
14
15
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { run, type Options } from './cli/run.js';
|
|
2
2
|
export { Core } from './core.js';
|
|
3
|
-
export { type SortField, type SortOrder, type Config } from './type.js';
|
|
3
|
+
export { type SortField, type SortOrder, type FilterCriterion, type Config } from './type.js';
|
|
4
4
|
export { takeRuleStatistics, type RuleStatistic, sortRuleStatistics } from './formatter/index.js';
|
|
5
5
|
export { type FixableMaker, type SuggestionFilter, type FixContext } from './fix/index.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ESLint } from 'eslint';
|
|
2
|
+
import { withProgress } from '../cli/log.js';
|
|
2
3
|
import type { Action } from '../cli/prompt.js';
|
|
3
4
|
import { promptToInputWhatToDoNext } from '../cli/prompt.js';
|
|
4
|
-
import { undoingSpinner } from '../cli/spinner.js';
|
|
5
5
|
import type { Undo } from '../core.js';
|
|
6
6
|
import type { NextScene } from './index.js';
|
|
7
7
|
|
|
@@ -31,14 +31,11 @@ export async function checkResults({
|
|
|
31
31
|
const nextStep = await promptToInputWhatToDoNext();
|
|
32
32
|
if (nextStep === 'exit') return { name: 'exit' };
|
|
33
33
|
if (nextStep === 'undoTheFix') {
|
|
34
|
-
await
|
|
34
|
+
await withProgress('Undoing', async () => undo());
|
|
35
35
|
return {
|
|
36
36
|
name: 'selectAction',
|
|
37
37
|
args: { results, ruleIdsInResults, selectedRuleIds, initialAction: selectedAction },
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
|
-
console.log();
|
|
41
|
-
console.log('─'.repeat(process.stdout.columns));
|
|
42
|
-
console.log();
|
|
43
40
|
return { name: 'lint' };
|
|
44
41
|
}
|
package/src/scene/lint.ts
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { error } from '../cli/log.js';
|
|
3
|
-
import {
|
|
4
|
-
import type { SerializableCore } from '../core-worker.js';
|
|
1
|
+
import { log } from '@clack/prompts';
|
|
2
|
+
import { error, withProgress } from '../cli/log.js';
|
|
3
|
+
import type { Core } from '../core.js';
|
|
5
4
|
import type { NextScene } from './index.js';
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* Run the scene to lint.
|
|
9
8
|
*/
|
|
10
|
-
export async function lint(core:
|
|
11
|
-
const results = await
|
|
12
|
-
console.log();
|
|
9
|
+
export async function lint(core: Core): Promise<NextScene> {
|
|
10
|
+
const results = await withProgress('Linting', async () => core.lint());
|
|
13
11
|
|
|
14
12
|
// Check for ESLint core problems (ruleId === null) first.
|
|
15
13
|
// These represent config errors, syntax errors, etc. that eslint-interactive cannot fix.
|
|
@@ -21,19 +19,23 @@ export async function lint(core: Remote<SerializableCore>): Promise<NextScene> {
|
|
|
21
19
|
'Check the details of the problem and fix it. ' +
|
|
22
20
|
'This is usually caused by the invalid eslint config or the invalid syntax of the linted code.',
|
|
23
21
|
);
|
|
24
|
-
|
|
22
|
+
log.message(await core.formatResultDetails(results, [null]), {});
|
|
25
23
|
// eslint-disable-next-line n/no-process-exit
|
|
26
24
|
process.exit(1);
|
|
27
25
|
}
|
|
28
26
|
|
|
29
|
-
const ruleIdsInResults =
|
|
27
|
+
const ruleIdsInResults = core.getFilteredAndSortedRuleIds(results);
|
|
30
28
|
|
|
31
29
|
if (ruleIdsInResults.length === 0) {
|
|
32
|
-
|
|
30
|
+
const hasAnyMessage = results.some((result) => result.messages.length > 0);
|
|
31
|
+
if (hasAnyMessage) {
|
|
32
|
+
log.message('💚 No rules match the given --filter.');
|
|
33
|
+
} else {
|
|
34
|
+
log.message('💚 No rules with problems.');
|
|
35
|
+
}
|
|
33
36
|
return { name: 'exit' };
|
|
34
37
|
}
|
|
35
|
-
|
|
38
|
+
log.message(core.formatResultSummary(results));
|
|
36
39
|
|
|
37
|
-
console.log();
|
|
38
40
|
return { name: 'selectRuleIds', args: { results, ruleIdsInResults } };
|
|
39
41
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { Remote } from 'comlink';
|
|
2
1
|
import type { ESLint } from 'eslint';
|
|
3
2
|
import {
|
|
4
3
|
doConvertErrorToWarningPerFileAction,
|
|
@@ -9,8 +8,7 @@ import {
|
|
|
9
8
|
} from '../action/index.js';
|
|
10
9
|
import type { Action } from '../cli/prompt.js';
|
|
11
10
|
import { promptToInputAction } from '../cli/prompt.js';
|
|
12
|
-
import type { Undo } from '../core.js';
|
|
13
|
-
import type { SerializableCore } from '../core-worker.js';
|
|
11
|
+
import type { Core, Undo } from '../core.js';
|
|
14
12
|
import { unreachable } from '../util/type-check.js';
|
|
15
13
|
import type { NextScene } from './index.js';
|
|
16
14
|
|
|
@@ -29,7 +27,7 @@ export type SelectActionArgs = {
|
|
|
29
27
|
* Run the scene where a user select the action to be performed for the problems of selected rules.
|
|
30
28
|
*/
|
|
31
29
|
export async function selectAction(
|
|
32
|
-
core:
|
|
30
|
+
core: Core,
|
|
33
31
|
{ results, ruleIdsInResults, selectedRuleIds, initialAction }: SelectActionArgs,
|
|
34
32
|
): Promise<NextScene> {
|
|
35
33
|
const selectedAction = await promptToInputAction(results, selectedRuleIds, initialAction);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import type { Remote } from 'comlink';
|
|
2
1
|
import type { ESLint } from 'eslint';
|
|
3
2
|
import { promptToInputRuleIds } from '../cli/prompt.js';
|
|
4
|
-
import type {
|
|
3
|
+
import type { Core } from '../core.js';
|
|
5
4
|
import type { NextScene } from './index.js';
|
|
6
5
|
import { selectAction } from './select-action.js';
|
|
7
6
|
|
|
@@ -15,10 +14,7 @@ export type SelectRuleIdsArgs = {
|
|
|
15
14
|
/**
|
|
16
15
|
* Run the scene where a user select rule ids.
|
|
17
16
|
*/
|
|
18
|
-
export async function selectRuleIds(
|
|
19
|
-
core: Remote<SerializableCore>,
|
|
20
|
-
{ results, ruleIdsInResults }: SelectRuleIdsArgs,
|
|
21
|
-
): Promise<NextScene> {
|
|
17
|
+
export async function selectRuleIds(core: Core, { results, ruleIdsInResults }: SelectRuleIdsArgs): Promise<NextScene> {
|
|
22
18
|
const selectedRuleIds = await promptToInputRuleIds(ruleIdsInResults);
|
|
23
19
|
return selectAction(core, { results, ruleIdsInResults, selectedRuleIds });
|
|
24
20
|
}
|
package/src/type.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { ESLint } from 'eslint';
|
|
|
2
2
|
|
|
3
3
|
export type SortField = 'rule' | 'error' | 'warning' | 'fixable' | 'suggestions';
|
|
4
4
|
export type SortOrder = 'asc' | 'desc';
|
|
5
|
+
export type FilterCriterion = 'fixable' | 'has-suggestions';
|
|
5
6
|
|
|
6
7
|
/** The config of eslint-interactive */
|
|
7
8
|
export type Config = ESLint.Options & {
|
|
@@ -10,4 +11,5 @@ export type Config = ESLint.Options & {
|
|
|
10
11
|
quiet?: boolean | undefined;
|
|
11
12
|
sort?: SortField | undefined;
|
|
12
13
|
sortOrder?: SortOrder | undefined;
|
|
14
|
+
filters?: FilterCriterion[] | undefined;
|
|
13
15
|
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const OSC = '\x1B]';
|
|
2
|
+
const BEL = '\x07';
|
|
3
|
+
|
|
4
|
+
function buildOsc8Link(text: string, url: string): string {
|
|
5
|
+
return `${OSC}8;;${url}${BEL}${text}${OSC}8;;${BEL}`;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function supportsHyperlinks(): boolean {
|
|
9
|
+
if (process.env['FORCE_HYPERLINK'] === '1') return true;
|
|
10
|
+
if (process.env['FORCE_HYPERLINK'] === '0') return false;
|
|
11
|
+
return process.stdout.isTTY;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function terminalLink(text: string, url: string): string {
|
|
15
|
+
return supportsHyperlinks() ? buildOsc8Link(text, url) : text;
|
|
16
|
+
}
|
package/src/cli/spinner.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { createSpinner } from 'nanospinner';
|
|
2
|
-
|
|
3
|
-
export async function lintingSpinner<T>(cb: () => Promise<T>): Promise<T> {
|
|
4
|
-
const spinner = createSpinner('Linting...').start();
|
|
5
|
-
const result = await cb();
|
|
6
|
-
spinner.success();
|
|
7
|
-
return result;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export async function fixingSpinner<T>(cb: () => Promise<T>): Promise<T> {
|
|
11
|
-
const spinner = createSpinner('Fixing...').start();
|
|
12
|
-
const result = await cb();
|
|
13
|
-
spinner.success();
|
|
14
|
-
return result;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export async function undoingSpinner<T>(cb: () => Promise<T>): Promise<T> {
|
|
18
|
-
const spinner = createSpinner('Undoing...').start();
|
|
19
|
-
const result = await cb();
|
|
20
|
-
spinner.success();
|
|
21
|
-
return result;
|
|
22
|
-
}
|