eslint-interactive 9.0.0 → 10.2.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.
Files changed (73) hide show
  1. package/README.md +8 -0
  2. package/dist/action/convert-error-to-warning-per-file.d.ts +6 -0
  3. package/dist/action/convert-error-to-warning-per-file.d.ts.map +1 -0
  4. package/dist/action/convert-error-to-warning-per-file.js +8 -0
  5. package/dist/action/convert-error-to-warning-per-file.js.map +1 -0
  6. package/dist/action/index.d.ts +1 -0
  7. package/dist/action/index.d.ts.map +1 -1
  8. package/dist/action/index.js +1 -0
  9. package/dist/action/index.js.map +1 -1
  10. package/dist/cli/parse-argv.d.ts.map +1 -1
  11. package/dist/cli/parse-argv.js +8 -1
  12. package/dist/cli/parse-argv.js.map +1 -1
  13. package/dist/cli/prompt.d.ts +2 -2
  14. package/dist/cli/prompt.d.ts.map +1 -1
  15. package/dist/cli/prompt.js +3 -2
  16. package/dist/cli/prompt.js.map +1 -1
  17. package/dist/core-worker.d.ts +1 -0
  18. package/dist/core-worker.d.ts.map +1 -1
  19. package/dist/core-worker.js +3 -0
  20. package/dist/core-worker.js.map +1 -1
  21. package/dist/core.d.ts +11 -12
  22. package/dist/core.d.ts.map +1 -1
  23. package/dist/core.js +28 -19
  24. package/dist/core.js.map +1 -1
  25. package/dist/formatter/format-by-rules.d.ts.map +1 -1
  26. package/dist/formatter/format-by-rules.js +1 -4
  27. package/dist/formatter/format-by-rules.js.map +1 -1
  28. package/dist/plugin/fix/convert-error-to-warning-per-file.d.ts +10 -0
  29. package/dist/plugin/fix/convert-error-to-warning-per-file.d.ts.map +1 -0
  30. package/dist/plugin/fix/convert-error-to-warning-per-file.js +29 -0
  31. package/dist/plugin/fix/convert-error-to-warning-per-file.js.map +1 -0
  32. package/dist/plugin/fix/disable-per-line.d.ts.map +1 -1
  33. package/dist/plugin/fix/disable-per-line.js +9 -2
  34. package/dist/plugin/fix/disable-per-line.js.map +1 -1
  35. package/dist/plugin/fix/index.d.ts +1 -0
  36. package/dist/plugin/fix/index.d.ts.map +1 -1
  37. package/dist/plugin/fix/index.js +1 -0
  38. package/dist/plugin/fix/index.js.map +1 -1
  39. package/dist/plugin/fix-rule.d.ts.map +1 -1
  40. package/dist/plugin/fix-rule.js +4 -1
  41. package/dist/plugin/fix-rule.js.map +1 -1
  42. package/dist/plugin/index.d.ts +6 -3
  43. package/dist/plugin/index.d.ts.map +1 -1
  44. package/dist/plugin/index.js.map +1 -1
  45. package/dist/scene/select-action.d.ts.map +1 -1
  46. package/dist/scene/select-action.js +5 -1
  47. package/dist/scene/select-action.js.map +1 -1
  48. package/dist/tsconfig.src.tsbuildinfo +1 -1
  49. package/dist/util/cache.d.ts.map +1 -1
  50. package/dist/util/cache.js +1 -4
  51. package/dist/util/cache.js.map +1 -1
  52. package/dist/util/eslint.d.ts +10 -1
  53. package/dist/util/eslint.d.ts.map +1 -1
  54. package/dist/util/eslint.js +18 -0
  55. package/dist/util/eslint.js.map +1 -1
  56. package/package.json +49 -40
  57. package/src/action/convert-error-to-warning-per-file.ts +18 -0
  58. package/src/action/index.ts +1 -0
  59. package/src/cli/parse-argv.ts +8 -1
  60. package/src/cli/prompt.ts +4 -2
  61. package/src/core-worker.ts +5 -0
  62. package/src/core.ts +39 -24
  63. package/src/formatter/format-by-rules.ts +1 -2
  64. package/src/index.ts +0 -0
  65. package/src/plugin/fix/convert-error-to-warning-per-file.ts +45 -0
  66. package/src/plugin/fix/disable-per-line.ts +13 -2
  67. package/src/plugin/fix/index.ts +4 -0
  68. package/src/plugin/fix-rule.ts +3 -0
  69. package/src/plugin/index.ts +11 -1
  70. package/src/scene/select-action.ts +4 -0
  71. package/src/typings/cachedir.d.ts +2 -1
  72. package/src/util/cache.ts +1 -2
  73. package/src/util/eslint.ts +25 -1
package/package.json CHANGED
@@ -1,68 +1,64 @@
1
1
  {
2
2
  "name": "eslint-interactive",
3
3
  "description": "The CLI tool to run `eslint --fix` for each rule",
4
- "version": "9.0.0",
4
+ "version": "10.2.0",
5
5
  "repository": "https://github.com/mizdra/eslint-interactive.git",
6
6
  "author": "mizdra <pp.mizdra@gmail.com>",
7
7
  "license": "MIT",
8
8
  "private": false,
9
9
  "type": "module",
10
- "exports": "./dist/index.js",
11
- "scripts": {
12
- "build": "tsc -p tsconfig.src.json",
13
- "dev": "tsc-watch -p tsconfig.src.json --onSuccess 'bin/eslint-interactive.js fixtures --rulesdir fixtures/rules --ext .js,.jsx,.mjs'",
14
- "lint": "run-s -c lint:*",
15
- "lint:tsc": "run-s -c lint:tsc:*",
16
- "lint:tsc:src": "tsc -p tsconfig.src.json --noEmit",
17
- "lint:tsc:test": "tsc -p tsconfig.test.json --noEmit",
18
- "lint:eslint": "eslint --ignore-pattern '/fixtures/' --ignore-pattern '/e2e-test/' .",
19
- "lint:prettier": "prettier --check .",
20
- "test": "FORCE_HYPERLINK=1 NODE_OPTIONS=--experimental-vm-modules jest --colors",
21
- "postbuild:test": "./run-e2e-test.sh",
22
- "postbuild:benchmark": "node benchmark/run.js"
10
+ "exports": {
11
+ ".": {
12
+ "import": {
13
+ "types": "./dist/index.d.ts",
14
+ "default": "./dist/index.js"
15
+ }
16
+ }
23
17
  },
24
18
  "prettier": "@mizdra/prettier-config-mizdra",
25
- "renovate": "github>mizdra/renovate-config-mizdra",
19
+ "packageManager": "pnpm@7.5.1",
26
20
  "devDependencies": {
27
- "@jest/types": "^27.5.1",
28
- "@mizdra/eslint-config-mizdra": "^1.1.0",
29
- "@mizdra/prettier-config-mizdra": "^0.4.0",
30
- "@types/eslint": "^8.4.1",
21
+ "@babel/core": "^7.18.13",
22
+ "@babel/preset-typescript": "^7.18.6",
23
+ "@jest/types": "^29.0.1",
24
+ "@mizdra/eslint-config-mizdra": "^1.2.0",
25
+ "@mizdra/prettier-config-mizdra": "^1.0.0",
26
+ "@types/eslint": "^8.4.6",
31
27
  "@types/estraverse": "^5.1.1",
32
- "@types/estree": "^0.0.51",
33
- "@types/jest": "^27.0.3",
34
- "@types/node": "^14.14.10",
28
+ "@types/estree": "^1.0.0",
29
+ "@types/jest": "^29.0.0",
30
+ "@types/node": "^18.0.5",
35
31
  "@types/terminal-link": "^1.2.0",
36
- "@types/yargs": "^16.0.4",
37
- "@typescript-eslint/eslint-plugin": "^5.16.0",
38
- "@typescript-eslint/parser": "^5.16.0",
39
- "enhanced-resolve": "^5.8.3",
40
- "eslint": "^8.11.0",
32
+ "@types/yargs": "^17.0.10",
33
+ "@typescript-eslint/eslint-plugin": "^5.30.6",
34
+ "@typescript-eslint/parser": "^5.30.6",
35
+ "babel-jest": "^29.0.1",
36
+ "eslint": "^8.23.0",
41
37
  "eslint-config-prettier": "^8.5.0",
42
- "eslint-plugin-import": "^2.25.4",
43
- "jest": "^27.5.1",
44
- "jest-mock-process": "^1.4.1",
38
+ "eslint-plugin-import": "^2.26.0",
39
+ "jest": "^29.0.1",
40
+ "jest-mock-process": "^2.0.0",
45
41
  "npm-run-all": "^4.1.5",
46
- "prettier": "2.6.0",
42
+ "prettier": "2.7.1",
43
+ "resolve-from": "^5.0.0",
47
44
  "strip-ansi": "^7.0.1",
48
- "ts-jest": "^27.1.3",
49
- "tsc-watch": "^4.2.9",
50
- "typescript": "^4.6.0-dev.20220211"
45
+ "tsc-watch": "^5.0.3",
46
+ "typescript": "^4.8.2"
51
47
  },
52
48
  "dependencies": {
53
- "boxen": "^6.2.1",
49
+ "boxen": "^7.0.0",
54
50
  "cachedir": "^2.3.0",
55
- "chalk": "^5.0.0",
51
+ "chalk": "^5.0.1",
56
52
  "comlink": "^4.3.1",
57
53
  "enquirer": "^2.3.6",
58
54
  "eslint-formatter-codeframe": "^7.32.1",
59
55
  "estraverse": "^5.3.0",
60
56
  "is-installed-globally": "^0.4.0",
61
57
  "node-pager": "^0.3.6",
62
- "ora": "^6.0.1",
58
+ "ora": "^6.1.2",
63
59
  "table": "^6.8.0",
64
60
  "terminal-link": "^3.0.0",
65
- "yargs": "^16.2.0"
61
+ "yargs": "^17.5.1"
66
62
  },
67
63
  "peerDependencies": {
68
64
  "eslint": "^7.0.0 || ^8.0.0"
@@ -88,5 +84,18 @@
88
84
  "!src/**/__snapshots__",
89
85
  "dist",
90
86
  "static"
91
- ]
92
- }
87
+ ],
88
+ "scripts": {
89
+ "build": "tsc -p tsconfig.src.json",
90
+ "dev": "tsc-watch -p tsconfig.src.json --onSuccess 'bin/eslint-interactive.js fixtures --rulesdir fixtures/rules --ext .js,.jsx,.mjs'",
91
+ "lint": "run-s -c lint:*",
92
+ "lint:tsc": "run-s -c lint:tsc:*",
93
+ "lint:tsc:src": "tsc -p tsconfig.src.json --noEmit",
94
+ "lint:tsc:test": "tsc -p tsconfig.test.json --noEmit",
95
+ "lint:eslint": "eslint --ignore-pattern '/fixtures/' --ignore-pattern '/e2e-test/' .",
96
+ "lint:prettier": "prettier --check .",
97
+ "test": "FORCE_HYPERLINK=1 NODE_OPTIONS=\"--experimental-vm-modules --experimental-import-meta-resolve $NODE_OPTIONS\" jest --colors",
98
+ "postbuild:test": "./run-e2e-test.sh",
99
+ "postbuild:benchmark": "node benchmark/run.js"
100
+ }
101
+ }
@@ -0,0 +1,18 @@
1
+ import { Remote } from 'comlink';
2
+ import { ESLint } from 'eslint';
3
+ import { fixingSpinner } from '../cli/ora.js';
4
+ import { promptToInputDescription } from '../cli/prompt.js';
5
+ import { SerializableCore } from '../core-worker.js';
6
+ import { Undo } from '../core.js';
7
+
8
+ export async function doConvertErrorToWarningPerFileAction(
9
+ core: Remote<SerializableCore>,
10
+ results: ESLint.LintResult[],
11
+ selectedRuleIds: string[],
12
+ ): Promise<Undo> {
13
+ const description = await promptToInputDescription();
14
+ const undo = await fixingSpinner(async () =>
15
+ core.convertErrorToWarningPerFile(results, selectedRuleIds, description),
16
+ );
17
+ return undo;
18
+ }
@@ -1,6 +1,7 @@
1
1
  export { doApplySuggestionsAction } from './apply-suggestions.js';
2
2
  export { doDisablePerFileAction } from './disable-per-file.js';
3
3
  export { doDisablePerLineAction } from './disable-per-line.js';
4
+ export { doConvertErrorToWarningPerFileAction } from './convert-error-to-warning-per-file.js';
4
5
  export { doFixAction } from './fix.js';
5
6
  export { doMakeFixableAndFixAction } from './make-fixable-and-fix.js';
6
7
  export { doPrintResultDetailsAction } from './print-result-details.js';
@@ -22,6 +22,11 @@ export function parseArgv(argv: string[]): Config {
22
22
  describe: 'Specify the format to be used for the `Display problem messages` action',
23
23
  default: DEFAULT_BASE_CONFIG.formatterName,
24
24
  })
25
+ .option('quiet', {
26
+ type: 'boolean',
27
+ describe: 'Report errors only',
28
+ default: DEFAULT_BASE_CONFIG.quiet,
29
+ })
25
30
  .option('cache', {
26
31
  type: 'boolean',
27
32
  describe: 'Only check changed files',
@@ -31,7 +36,8 @@ export function parseArgv(argv: string[]): Config {
31
36
  type: 'string',
32
37
  describe: `Path to the cache file or directory`,
33
38
  default: DEFAULT_BASE_CONFIG.cacheLocation,
34
- }).argv;
39
+ })
40
+ .parseSync();
35
41
  // NOTE: convert `string` type because yargs convert `'10'` (`string` type) into `10` (`number` type)
36
42
  // and `lintFiles` only accepts `string[]`.
37
43
  const patterns = parsedArgv._.map((pattern) => pattern.toString());
@@ -46,6 +52,7 @@ export function parseArgv(argv: string[]): Config {
46
52
  rulePaths,
47
53
  extensions,
48
54
  formatterName,
55
+ quiet: parsedArgv.quiet,
49
56
  cache: parsedArgv.cache,
50
57
  cacheLocation: parsedArgv['cache-location'],
51
58
  };
package/src/cli/prompt.ts CHANGED
@@ -18,6 +18,7 @@ export type Action =
18
18
  | 'applyAutoFixes'
19
19
  | 'disablePerLine'
20
20
  | 'disablePerFile'
21
+ | 'convertErrorToWarningPerFile'
21
22
  | 'applySuggestions'
22
23
  | 'makeFixableAndFix'
23
24
  | 'reselectRules';
@@ -82,6 +83,7 @@ export async function promptToInputAction(
82
83
  { name: 'applyAutoFixes', message: '🔧 Run `eslint --fix`', disabled: foldedStatistics.isFixableCount === 0 },
83
84
  { name: 'disablePerLine', message: '🔧 Disable per line' },
84
85
  { name: 'disablePerFile', message: '🔧 Disable per file' },
86
+ { name: 'convertErrorToWarningPerFile', message: '🔧 Convert error to warning per file' },
85
87
  {
86
88
  name: 'applySuggestions',
87
89
  message: '🔧 Apply suggestions (experimental, for experts)',
@@ -132,7 +134,7 @@ export async function promptToInputDisplayMode(): Promise<DisplayMode> {
132
134
  }
133
135
 
134
136
  /**
135
- * Ask the user a description to leave in disable comment.
137
+ * Ask the user a description to leave in directive.
136
138
  * @returns The description
137
139
  */
138
140
  export async function promptToInputDescription(): Promise<string | undefined> {
@@ -142,7 +144,7 @@ export async function promptToInputDescription(): Promise<string | undefined> {
142
144
  {
143
145
  name: 'description',
144
146
  type: 'input',
145
- message: 'Leave a code comment with your reason for disabling (Optional)',
147
+ message: 'Leave a code comment with your reason for fixing (Optional)',
146
148
  onCancel,
147
149
  },
148
150
  ]);
@@ -40,6 +40,11 @@ export class SerializableCore {
40
40
  async disablePerFile(...args: Parameters<Core['disablePerFile']>): ReturnType<Core['disablePerFile']> {
41
41
  return proxy(await this.core.disablePerFile(...args));
42
42
  }
43
+ async convertErrorToWarningPerFile(
44
+ ...args: Parameters<Core['convertErrorToWarningPerFile']>
45
+ ): ReturnType<Core['convertErrorToWarningPerFile']> {
46
+ return proxy(await this.core.convertErrorToWarningPerFile(...args));
47
+ }
43
48
  async applySuggestions(
44
49
  results: ESLint.LintResult[],
45
50
  ruleIds: string[],
package/src/core.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  import { join } from 'path';
2
2
  import { fileURLToPath } from 'url';
3
3
  import { ESLint } from 'eslint';
4
- // eslint-disable-next-line @typescript-eslint/no-require-imports
5
- import isInstalledGlobally = require('is-installed-globally');
4
+ import isInstalledGlobally from 'is-installed-globally';
6
5
  import { format } from './formatter/index.js';
7
6
  import {
8
7
  eslintInteractivePlugin,
@@ -51,21 +50,24 @@ async function getUsedRuleIds(targetFilePaths: string[], options: ESLint.Options
51
50
  export type Undo = () => Promise<void>;
52
51
 
53
52
  /** The config of eslint-interactive */
54
- export type Config = {
53
+ export type Config = Pick<
54
+ ESLint.Options,
55
+ 'extensions' | 'rulePaths' | 'cache' | 'cacheLocation' | 'useEslintrc' | 'overrideConfig' | 'cwd'
56
+ > & {
55
57
  patterns: string[];
56
- rulePaths?: string[] | undefined;
57
- extensions?: string[] | undefined;
58
58
  formatterName?: string;
59
- cache?: boolean;
60
- cacheLocation?: string;
61
- cwd?: string;
59
+ quiet?: boolean;
62
60
  };
63
61
 
64
62
  /** Default config of `Core` */
65
- export const DEFAULT_BASE_CONFIG = {
63
+ export const DEFAULT_BASE_CONFIG: Partial<Config> = {
64
+ cwd: undefined,
66
65
  cache: true,
67
66
  cacheLocation: join(getCacheDir(), '.eslintcache'),
67
+ extensions: undefined,
68
68
  formatterName: 'codeframe',
69
+ quiet: false,
70
+ rulePaths: undefined,
69
71
  };
70
72
 
71
73
  /**
@@ -75,17 +77,15 @@ export const DEFAULT_BASE_CONFIG = {
75
77
  export class Core {
76
78
  readonly config: Config;
77
79
  /** The base options of ESLint */
78
- readonly baseOptions: ESLint.Options;
80
+ readonly baseESLintOptions: ESLint.Options;
79
81
 
80
82
  constructor(config: Config) {
81
- this.config = config;
82
- this.baseOptions = {
83
- cache: this.config.cache ?? DEFAULT_BASE_CONFIG.cache,
84
- cacheLocation: this.config.cacheLocation ?? DEFAULT_BASE_CONFIG.cacheLocation,
85
- rulePaths: this.config.rulePaths,
86
- extensions: this.config.extensions,
87
- cwd: this.config.cwd,
83
+ this.config = {
84
+ ...DEFAULT_BASE_CONFIG,
85
+ ...config,
88
86
  };
87
+ const { patterns, formatterName, quiet, ...baseOptions } = this.config;
88
+ this.baseESLintOptions = baseOptions;
89
89
  }
90
90
 
91
91
  /**
@@ -93,8 +93,9 @@ export class Core {
93
93
  * @returns The results of linting
94
94
  */
95
95
  async lint(): Promise<ESLint.LintResult[]> {
96
- const eslint = new ESLint(this.baseOptions);
97
- const results = await eslint.lintFiles(this.config.patterns);
96
+ const eslint = new ESLint(this.baseESLintOptions);
97
+ let results = await eslint.lintFiles(this.config.patterns);
98
+ if (this.config.quiet) results = ESLint.getErrorResults(results);
98
99
  return results;
99
100
  }
100
101
 
@@ -108,8 +109,8 @@ export class Core {
108
109
 
109
110
  // get `rulesMeta` from `results`
110
111
  const eslint = new ESLint({
111
- ...this.baseOptions,
112
- overrideConfig: { plugins },
112
+ ...this.baseESLintOptions,
113
+ overrideConfig: { ...this.baseESLintOptions.overrideConfig, plugins },
113
114
  });
114
115
  // NOTE: `getRulesMetaForResults` is a feature added in ESLint 7.29.0.
115
116
  // Therefore, the function may not exist in versions lower than 7.29.0.
@@ -124,7 +125,7 @@ export class Core {
124
125
  * @param ruleIds The rule ids to print details
125
126
  */
126
127
  async formatResultDetails(results: ESLint.LintResult[], ruleIds: (string | null)[]): Promise<string> {
127
- const eslint = new ESLint(this.baseOptions);
128
+ const eslint = new ESLint(this.baseESLintOptions);
128
129
  const formatterName = this.config.formatterName ?? DEFAULT_BASE_CONFIG.formatterName;
129
130
 
130
131
  // When eslint-interactive is installed globally, eslint-formatter-codeframe will also be installed globally.
@@ -173,6 +174,20 @@ export class Core {
173
174
  return await this.fix(results, ruleIds, { name: 'disablePerFile', args: { description } });
174
175
  }
175
176
 
177
+ /**
178
+ * Convert error to warning per file.
179
+ * @param results The lint results of the project to convert
180
+ * @param ruleIds The rule ids to convert
181
+ * @param description The comment explaining the reason for converting
182
+ */
183
+ async convertErrorToWarningPerFile(
184
+ results: ESLint.LintResult[],
185
+ ruleIds: string[],
186
+ description?: string,
187
+ ): Promise<Undo> {
188
+ return await this.fix(results, ruleIds, { name: 'convertErrorToWarningPerFile', args: { description } });
189
+ }
190
+
176
191
  /**
177
192
  * Apply suggestions.
178
193
  * @param results The lint results of the project to apply suggestions
@@ -201,13 +216,13 @@ export class Core {
201
216
  // NOTE: Extract only necessary results and files for performance
202
217
  const filteredResultsOfLint = filterResultsByRuleId(resultsOfLint, ruleIds);
203
218
  const targetFilePaths = filteredResultsOfLint.map((result) => result.filePath);
204
- const usedRuleIds = await getUsedRuleIds(targetFilePaths, this.baseOptions);
219
+ const usedRuleIds = await getUsedRuleIds(targetFilePaths, this.baseESLintOptions);
205
220
 
206
221
  // TODO: refactor
207
222
  let results = filteredResultsOfLint;
208
223
  for (let i = 0; i < MAX_AUTOFIX_PASSES; i++) {
209
224
  const eslint = new ESLint({
210
- ...this.baseOptions,
225
+ ...this.baseESLintOptions,
211
226
  // This is super hack to load ESM plugin/rule.
212
227
  // ref: https://github.com/eslint/eslint/issues/15453#issuecomment-1001200953
213
228
  plugins: {
@@ -1,7 +1,6 @@
1
1
  import chalk from 'chalk';
2
2
  import { ESLint } from 'eslint';
3
- // eslint-disable-next-line @typescript-eslint/no-require-imports
4
- import table = require('table');
3
+ import table from 'table';
5
4
  import terminalLink from 'terminal-link';
6
5
  import { ERROR_COLOR } from './colors.js';
7
6
  import { takeRuleStatistics } from './take-rule-statistics.js';
package/src/index.ts CHANGED
File without changes
@@ -0,0 +1,45 @@
1
+ import { Rule, Linter } from 'eslint';
2
+ import { unique } from '../../util/array.js';
3
+ import { findShebang, toInlineConfigCommentText } from '../../util/eslint.js';
4
+ import { notEmpty } from '../../util/type-check.js';
5
+ import { FixContext } from '../index.js';
6
+
7
+ export type FixToConvertErrorToWarningPerFileArgs = {
8
+ description?: string;
9
+ };
10
+
11
+ function generateFix(context: FixContext, description?: string): Rule.Fix | null {
12
+ const ruleIdsToConverting = unique(
13
+ context.messages
14
+ // Ignore warnings
15
+ .filter((message) => message.severity === 2)
16
+ .map((message) => message.ruleId)
17
+ .filter(notEmpty),
18
+ );
19
+ if (ruleIdsToConverting.length === 0) return null;
20
+
21
+ const rulesRecordToConverting: Partial<Linter.RulesRecord> = Object.fromEntries(
22
+ ruleIdsToConverting.map((ruleId) => [ruleId, 1]),
23
+ );
24
+
25
+ // Insert the inline config comment at the top of the file.
26
+ // NOTE: Merging settings into an existing inline config comment is intentionally avoided
27
+ // because of the complexity of the implementation.
28
+
29
+ const text = toInlineConfigCommentText({ rulesRecord: rulesRecordToConverting, description }) + '\n';
30
+
31
+ const shebang = findShebang(context.sourceCode.text);
32
+ // if shebang exists, insert comment after shebang
33
+ return context.fixer.insertTextAfterRange(shebang?.range ?? [0, 0], text);
34
+ }
35
+
36
+ /**
37
+ * Create fix to convert error to warning per file.
38
+ */
39
+ export function createFixToConvertErrorToWarningPerFile(
40
+ context: FixContext,
41
+ args: FixToConvertErrorToWarningPerFileArgs,
42
+ ): Rule.Fix[] {
43
+ const fix = generateFix(context, args.description);
44
+ return fix ? [fix] : [];
45
+ }
@@ -40,13 +40,24 @@ function generateFixPerLine(
40
40
  const headNode = context.sourceCode.getNodeByRangeIndex(headNodeIndex);
41
41
  if (headNode === null) return null; // For some reason, it seems to be null sometimes.
42
42
 
43
+ // Extract the same indent as the line we want to fix
44
+ const indent = context.sourceCode.text.slice(
45
+ headNodeIndex,
46
+ headNodeIndex +
47
+ context.sourceCode.text
48
+ .slice(headNodeIndex)
49
+ // ref: https://tc39.es/ecma262/#sec-white-space
50
+ // eslint-disable-next-line no-control-regex
51
+ .search(/[^\u{0009}\u{000B}\u{000C}\u{FEFF}\p{gc=Space_Separator}]/u),
52
+ );
53
+
43
54
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
55
  if ((headNode.type as any) === 'JSXText') {
45
56
  const commentText = toCommentText({ type: 'Block', scope: 'next-line', ruleIds: ruleIdsToDisable, description });
46
- return context.fixer.insertTextBeforeRange([headNodeIndex, headNodeIndex], '{' + commentText + '}\n');
57
+ return context.fixer.insertTextBeforeRange([headNodeIndex, headNodeIndex], indent + '{' + commentText + '}\n');
47
58
  } else {
48
59
  const commentText = toCommentText({ type: 'Line', scope: 'next-line', ruleIds: ruleIdsToDisable, description });
49
- return context.fixer.insertTextBeforeRange([headNodeIndex, headNodeIndex], commentText + '\n');
60
+ return context.fixer.insertTextBeforeRange([headNodeIndex, headNodeIndex], indent + commentText + '\n');
50
61
  }
51
62
  }
52
63
  }
@@ -6,6 +6,10 @@ export {
6
6
  export { type FixToApplyAutoFixesArgs, createFixToApplyAutoFixes } from './apply-auto-fixes.js';
7
7
  export { type FixToDisablePerFileArgs, createFixToDisablePerFile } from './disable-per-file.js';
8
8
  export { type FixToDisablePerLineArgs, createFixToDisablePerLine } from './disable-per-line.js';
9
+ export {
10
+ type FixToConvertErrorToWarningPerFileArgs,
11
+ createFixToConvertErrorToWarningPerFile,
12
+ } from './convert-error-to-warning-per-file.js';
9
13
  export {
10
14
  type FixableMaker,
11
15
  type FixToMakeFixableAndFixArgs,
@@ -2,6 +2,7 @@ import { ESLint, Rule } from 'eslint';
2
2
  import {
3
3
  createFixToApplyAutoFixes,
4
4
  createFixToApplySuggestions,
5
+ createFixToConvertErrorToWarningPerFile,
5
6
  createFixToDisablePerFile,
6
7
  createFixToDisablePerLine,
7
8
  createFixToMakeFixableAndFix,
@@ -53,6 +54,8 @@ function createFixes(context: Rule.RuleContext, ruleOption: FixRuleOption, fixer
53
54
  fixes = createFixToDisablePerLine(fixContext, fix.args);
54
55
  } else if (fix.name === 'disablePerFile') {
55
56
  fixes = createFixToDisablePerFile(fixContext, fix.args);
57
+ } else if (fix.name === 'convertErrorToWarningPerFile') {
58
+ fixes = createFixToConvertErrorToWarningPerFile(fixContext, fix.args);
56
59
  } else if (fix.name === 'applySuggestions') {
57
60
  fixes = createFixToApplySuggestions(fixContext, fix.args);
58
61
  } else if (fix.name === 'makeFixableAndFix') {
@@ -8,6 +8,7 @@ import {
8
8
  type FixToDisablePerLineArgs,
9
9
  type FixToMakeFixableAndFixArgs,
10
10
  type FixToApplyAutoFixesArgs,
11
+ FixToConvertErrorToWarningPerFileArgs,
11
12
  } from './fix/index.js';
12
13
  import { preferAdditionShorthandRule } from './prefer-addition-shorthand-rule.js';
13
14
 
@@ -30,11 +31,18 @@ export type Fix =
30
31
  | { name: 'applyAutoFixes'; args: FixArg<'applyAutoFixes'> }
31
32
  | { name: 'disablePerLine'; args: FixArg<'disablePerLine'> }
32
33
  | { name: 'disablePerFile'; args: FixArg<'disablePerFile'> }
34
+ | { name: 'convertErrorToWarningPerFile'; args: FixArg<'convertErrorToWarningPerFile'> }
33
35
  | { name: 'applySuggestions'; args: FixArg<'applySuggestions'> }
34
36
  | { name: 'makeFixableAndFix'; args: FixArg<'makeFixableAndFix'> };
35
37
 
36
38
  /** For test */
37
- export type FixName = 'applyAutoFixes' | 'disablePerLine' | 'disablePerFile' | 'applySuggestions' | 'makeFixableAndFix';
39
+ export type FixName =
40
+ | 'applyAutoFixes'
41
+ | 'disablePerLine'
42
+ | 'disablePerFile'
43
+ | 'convertErrorToWarningPerFile'
44
+ | 'applySuggestions'
45
+ | 'makeFixableAndFix';
38
46
 
39
47
  /** For test */
40
48
  export type FixArg<T extends FixName> = T extends 'applyAutoFixes'
@@ -43,6 +51,8 @@ export type FixArg<T extends FixName> = T extends 'applyAutoFixes'
43
51
  ? FixToDisablePerLineArgs
44
52
  : T extends 'disablePerFile'
45
53
  ? FixToDisablePerFileArgs
54
+ : T extends 'convertErrorToWarningPerFile'
55
+ ? FixToConvertErrorToWarningPerFileArgs
46
56
  : T extends 'applySuggestions'
47
57
  ? FixToApplySuggestionsArgs
48
58
  : T extends 'makeFixableAndFix'
@@ -2,6 +2,7 @@ import { Remote } from 'comlink';
2
2
  import { ESLint } from 'eslint';
3
3
  import {
4
4
  doApplySuggestionsAction,
5
+ doConvertErrorToWarningPerFileAction,
5
6
  doDisablePerFileAction,
6
7
  doDisablePerLineAction,
7
8
  doFixAction,
@@ -58,6 +59,9 @@ export async function selectAction(
58
59
  } else if (selectedAction === 'disablePerFile') {
59
60
  const undo = await doDisablePerFileAction(core, results, selectedRuleIds);
60
61
  return createCheckResultsScene(undo);
62
+ } else if (selectedAction === 'convertErrorToWarningPerFile') {
63
+ const undo = await doConvertErrorToWarningPerFileAction(core, results, selectedRuleIds);
64
+ return createCheckResultsScene(undo);
61
65
  } else if (selectedAction === 'applySuggestions') {
62
66
  const undo = await doApplySuggestionsAction(core, results, selectedRuleIds);
63
67
  return createCheckResultsScene(undo);
@@ -1,5 +1,6 @@
1
1
  declare module 'cachedir' {
2
2
  // eslint-disable-next-line import/no-default-export
3
3
  function cachedir(name: string): string;
4
- export = cachedir;
4
+ // eslint-disable-next-line import/no-default-export
5
+ export default cachedir;
5
6
  }
package/src/util/cache.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { join } from 'path';
2
- // eslint-disable-next-line @typescript-eslint/no-require-imports
3
- import cachedir = require('cachedir');
2
+ import cachedir from 'cachedir';
4
3
  import { VERSION } from '../cli/package.js';
5
4
 
6
5
  /**
@@ -1,4 +1,4 @@
1
- import { AST, ESLint } from 'eslint';
1
+ import { AST, ESLint, Linter } from 'eslint';
2
2
  import type { Comment } from 'estree';
3
3
  import { unique } from './array.js';
4
4
  import { notEmpty } from './type-check.js';
@@ -97,6 +97,30 @@ export function toCommentText({ type, scope, ruleIds, description }: Omit<Disabl
97
97
  }
98
98
  }
99
99
 
100
+ export type InlineConfigComment = {
101
+ description?: string;
102
+ rulesRecord: Partial<Linter.RulesRecord>;
103
+ range: [number, number];
104
+ };
105
+
106
+ /**
107
+ * Convert `InlineConfigComment` to comment text.
108
+ */
109
+ export function toInlineConfigCommentText({ rulesRecord, description }: Omit<InlineConfigComment, 'range'>): string {
110
+ const header = 'eslint';
111
+ const rulesRecordText = Object.entries(rulesRecord)
112
+ .map(([ruleId, ruleEntry]) => {
113
+ // TODO: Inherit options of the rule set by the user in eslintrc if the option exists.
114
+ return `${ruleId}: ${JSON.stringify(ruleEntry)}`;
115
+ })
116
+ .join(', ');
117
+ if (description === undefined) {
118
+ return `/* ${header} ${rulesRecordText} */`;
119
+ } else {
120
+ return `/* ${header} ${rulesRecordText} -- ${description} */`;
121
+ }
122
+ }
123
+
100
124
  /**
101
125
  * Create the results with only messages with the specified rule ids.
102
126
  * @param results The lint results.