@sushichan044/eslint-todo 0.0.2 → 0.0.3

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 CHANGED
@@ -1,33 +1,35 @@
1
1
  # @sushichan044/eslint-todo
2
2
 
3
- > [!WARNING]
3
+ Simple tool to temporarily disable existing ESLint violations like `.rubocop_todo.yml` in RuboCop.
4
+
5
+ It also has a utility that helps reducing ignored violations at your pace.
6
+
7
+ > [!NOTE]
4
8
  > This tool only supports ESLint Flat Config with ES Module.
5
9
  >
6
10
  > If you want to use this tool to supress ESLint errors when migrating to ESLint Flat Config,
7
11
  > you first need to create Flat Config and then use this tool. Maybe utilities like [@eslint/compat](https://github.com/eslint/rewrite/tree/main/packages/compat) can help you.
8
12
 
9
- Simple tool to temporarily disable existing ESLint violations like `.rubocop_todo.yml` in RuboCop.
10
-
11
- This allows existing offending files to be excluded from scanning on a rule-by-rule basis, which is useful when making destructive changes to ESLint settings.
12
-
13
- It also has a utility that reduces the number of ignored rules at a pace that works for your team.
14
-
15
- ## Features
16
-
17
- - Temporarily disable ESLint rules for specific files having existing violations with one command.
18
- - Assistive feature to gradually eliminate ignored errors.
19
-
20
13
  ## Installation
21
14
 
22
15
  ```bash
23
- pnpm install -D @sushichan044/eslint-todo
16
+ npm install --save-dev eslint @sushichan044/eslint-todo
24
17
  ```
25
18
 
19
+ Requires:
20
+
21
+ - **ES Module**
22
+ - ESLint: `^8.57.0 || ^9.0.0`
23
+ - **Flat Config**
24
+ - Node.js: `>= 20.0.0`
25
+ - May work in Deno, but not tested.
26
+
26
27
  ## Getting Started
27
28
 
28
- 1. Add `eslint-todo` config to your `eslint.config.js`.
29
+ 1. Add `eslint-todo` config **at the bottom of your configs**. Do not forget `await`.
29
30
 
30
31
  ``` diff
32
+ // example: eslint.config.js
31
33
  + import { eslintConfigTodo } from '@sushichan044/eslint-todo/eslint';
32
34
 
33
35
  export default [
@@ -36,16 +38,13 @@ pnpm install -D @sushichan044/eslint-todo
36
38
  ]
37
39
  ```
38
40
 
39
- 2. Run `eslint-todo` to generate ESLint Todo file. By default, it will generate `.eslint-todo.js` file.
40
-
41
- > [!NOTE]
42
- > Run this command at the directory where your `eslint.config.js` is located.
41
+ 2. Run `eslint-todo` to generate ESLint Todo file at the directory where `eslint.config.js` is placed.
43
42
 
44
43
  ```bash
45
- pnpm exec eslint-todo
44
+ npx eslint-todo
46
45
  ```
47
46
 
48
- 3. Ignore `.eslint-todo.js` with some tools like Prettier as it is auto-generated module.
47
+ 3. Ignore generated `.eslint-todo.js` in some tools if you needed.
49
48
 
50
49
  ```diff
51
50
  // example: .prettierignore
@@ -67,10 +66,10 @@ Add `--correct` flag to launch eslint-todo with error reduction mode.
67
66
  In this mode, eslint-todo searches the todo file with the limit from CLI and removes one matching rule from the todo file.
68
67
  This allows ESLint to detect that rule as a violation again. For safety, only auto-fixable rules are searched by default.
69
68
 
70
- You can use `--limit`, `--limit-type`, `--no-auto-fixable-only` options to control the behavior.
69
+ You can use `--limit`, `--limit-type`, `--auto-fixable-only` options to control the behavior.
71
70
 
72
71
  Default options are: <br>
73
- Select one rule that has a total of 100 or fewer violations from auto-fixable rules.
72
+ Select one rule that has a total of 100 or fewer violations from **auto-fixable** rules.
74
73
 
75
74
  ```bash
76
75
  eslint-todo --correct --limit 100 --limit-type violation
@@ -82,10 +81,10 @@ Select one rule that has a total of 10 or fewer files with violations from auto-
82
81
  eslint-todo --correct --limit 10 --limit-type file
83
82
  ```
84
83
 
85
- Select one rule that has a total of 100 or fewer violations from all rules including non-auto-fixable rules:
84
+ Select one rule that has a total of 100 or fewer violations from **all rules including non-auto-fixable** rules:
86
85
 
87
86
  ```bash
88
- eslint-todo --correct --limit 100 --limit-type violation --no-auto-fixable-only
87
+ eslint-todo --correct --limit 100 --limit-type violation --auto-fixable-only false
89
88
  ```
90
89
 
91
90
  ## Configuration (CLI)
@@ -2,7 +2,4 @@
2
2
  // @ts-check
3
3
  import { run } from "../dist/cli/index.mjs";
4
4
 
5
- run(process.argv).catch((error) => {
6
- console.error(error);
7
- process.exit(1);
8
- });
5
+ await run(process.argv);
@@ -1,9 +1,10 @@
1
1
  import { defineCommand, runMain } from 'citty';
2
2
  import { createConsola } from 'consola';
3
3
  import { colorize } from 'consola/utils';
4
- import { L as LATEST_MODULE_HANDLER, T as TodoModuleV1Handler, E as ESLintTodoCore } from '../shared/eslint-todo.BwJWAS7j.mjs';
4
+ import { L as LATEST_MODULE_HANDLER, i as isNonEmptyString, T as TodoModuleV1Handler, E as ESLintTodoCore } from '../shared/eslint-todo.BShlgWEx.mjs';
5
5
  import { launchRemoteESLintTodoCore } from '../remote/client.mjs';
6
6
  import { klona } from 'klona/json';
7
+ import defu from 'defu';
7
8
  import { relative } from 'pathe';
8
9
  import * as v from 'valibot';
9
10
  import 'eslint';
@@ -11,7 +12,6 @@ import 'node:fs';
11
12
  import 'node:fs/promises';
12
13
  import 'magicast';
13
14
  import 'es-toolkit/compat';
14
- import 'defu';
15
15
  import 'node:process';
16
16
  import 'jiti';
17
17
  import 'comlink';
@@ -19,7 +19,7 @@ import 'comlink/dist/esm/node-adapter.mjs';
19
19
  import 'node:url';
20
20
  import 'node:worker_threads';
21
21
 
22
- const version = "0.0.2";
22
+ const version = "0.0.3";
23
23
 
24
24
  const defineAction = (action) => action;
25
25
  const NO_INPUT = Symbol("NO_INPUT");
@@ -36,36 +36,53 @@ async function runAction(action, options, input = NO_INPUT) {
36
36
  return await action(actionApi);
37
37
  }
38
38
  return await action(actionApi, input);
39
- } catch (e) {
40
- consola.error(e);
41
- throw e;
39
+ } catch (error) {
40
+ consola.error(error);
41
+ throw error;
42
42
  } finally {
43
43
  await remoteService.terminate();
44
44
  }
45
45
  }
46
46
 
47
- const deleteRule = (currentModule, ruleId) => {
48
- const newModule = klona(currentModule);
49
- if (Object.hasOwn(newModule.todo, ruleId)) {
50
- delete newModule.todo[ruleId];
47
+ const deleteRule = (currentModule, ruleSelection) => {
48
+ if (!Object.hasOwn(currentModule.todo, ruleSelection.ruleId)) {
49
+ return currentModule;
51
50
  }
52
- return newModule;
51
+ if (ruleSelection.type === "full") {
52
+ const newModule = klona(currentModule);
53
+ delete newModule.todo[ruleSelection.ruleId];
54
+ return newModule;
55
+ }
56
+ if (ruleSelection.type === "partial") {
57
+ const newModule = klona(currentModule);
58
+ const entry = newModule.todo[ruleSelection.ruleId];
59
+ for (const [file, count] of Object.entries(ruleSelection.violations)) {
60
+ if (!Object.hasOwn(entry.violations, file)) {
61
+ continue;
62
+ }
63
+ if (entry.violations[file] == null || entry.violations[file] !== count) {
64
+ continue;
65
+ }
66
+ delete entry.violations[file];
67
+ }
68
+ return newModule;
69
+ }
70
+ const _exhaustiveCheck = ruleSelection;
71
+ throw new Error(
72
+ `Unknown rule selection type ${JSON.stringify(_exhaustiveCheck)}`
73
+ );
53
74
  };
54
75
 
55
- const deleteRuleAction = defineAction(
56
- async ({ core, logger }, input) => {
57
- const { ruleId } = input;
58
- const currentModule = await core.readTodoModule();
59
- if (!LATEST_MODULE_HANDLER.isVersion(currentModule)) {
60
- throw new Error(
61
- "This action requires the latest version of the todo file."
62
- );
63
- }
64
- logger.info(`Deleting rule ${ruleId} from the todo file ...`);
65
- const newModule = deleteRule(currentModule, ruleId);
66
- await core.writeTodoModule(newModule);
76
+ const deleteRuleAction = defineAction(async ({ core }, input) => {
77
+ const currentModule = await core.readTodoModule();
78
+ if (!LATEST_MODULE_HANDLER.isVersion(currentModule)) {
79
+ throw new Error(
80
+ "This action requires the latest version of the todo file."
81
+ );
67
82
  }
68
- );
83
+ const newModule = deleteRule(currentModule, input);
84
+ await core.writeTodoModule(newModule);
85
+ });
69
86
 
70
87
  const genAction = defineAction(async ({ core, logger }) => {
71
88
  await core.resetTodoModule();
@@ -77,63 +94,154 @@ const genAction = defineAction(async ({ core, logger }) => {
77
94
  await core.writeTodoModule(todo);
78
95
  });
79
96
 
97
+ const operationOptionsWithDefault = (options = {}) => {
98
+ return defu(options, getDefaultOperationOptions());
99
+ };
100
+ const getDefaultOperationOptions = () => ({
101
+ allowPartialSelection: false,
102
+ autoFixableOnly: true
103
+ });
104
+
80
105
  const selectRuleBasedOnLimit = (todoModule, limit, options = {}) => {
106
+ const resolvedOptions = operationOptionsWithDefault(options);
81
107
  switch (limit.type) {
82
- case "file":
83
- return selectRuleBasedOnFilesLimit(todoModule, limit, options);
84
- case "violation":
85
- return selectRuleBasedOnViolationsLimit(todoModule, limit, options);
86
- default:
108
+ case "file": {
109
+ return selectRuleBasedOnFilesLimit(todoModule, limit, resolvedOptions);
110
+ }
111
+ case "violation": {
112
+ return selectRuleBasedOnViolationsLimit(
113
+ todoModule,
114
+ limit,
115
+ resolvedOptions
116
+ );
117
+ }
118
+ default: {
87
119
  const l = limit;
88
120
  throw new Error(`Got unknown limit: ${JSON.stringify(l)}`);
121
+ }
89
122
  }
90
123
  };
91
- const selectRuleBasedOnFilesLimit = (todoModule, limit, options = {}) => {
124
+ const selectRuleBasedOnFilesLimit = (todoModule, limit, options) => {
92
125
  const { count: limitCount } = limit;
93
- const { autoFixableOnly = true } = options;
94
- let selectedRule = null;
95
- let maxFiles = 0;
126
+ const { allowPartialSelection, autoFixableOnly } = options;
127
+ if (limitCount <= 0) {
128
+ throw new Error("The file limit must be greater than 0.");
129
+ }
130
+ let fullSelectableRule = null;
131
+ let selectedTargetCount = 0;
132
+ let partialSelectableRule = null;
96
133
  for (const [ruleId, entry] of Object.entries(todoModule.todo)) {
97
134
  if (autoFixableOnly && !entry.autoFix) {
98
135
  continue;
99
136
  }
100
- const totalFiles = Object.keys(entry.violations).length;
101
- if (totalFiles > maxFiles && totalFiles <= limitCount) {
102
- maxFiles = totalFiles;
103
- selectedRule = ruleId;
137
+ const violatedFiles = Object.keys(entry.violations).length;
138
+ if (violatedFiles > limitCount) {
139
+ if (allowPartialSelection && partialSelectableRule == null) {
140
+ partialSelectableRule = ruleId;
141
+ }
142
+ continue;
143
+ }
144
+ if (violatedFiles > selectedTargetCount) {
145
+ fullSelectableRule = ruleId;
146
+ selectedTargetCount = violatedFiles;
104
147
  }
105
148
  }
106
- return selectedRule != null ? { ruleId: selectedRule, success: true } : { success: false };
149
+ if (fullSelectableRule != null) {
150
+ return {
151
+ selection: {
152
+ ruleId: fullSelectableRule,
153
+ type: "full"
154
+ },
155
+ success: true
156
+ };
157
+ }
158
+ if (allowPartialSelection && isKeyOfTodo(todoModule.todo, partialSelectableRule)) {
159
+ const rule = todoModule.todo[partialSelectableRule];
160
+ const selectedPaths = Object.keys(rule.violations).slice(0, limitCount);
161
+ const selectedViolations = {};
162
+ for (const file of selectedPaths) {
163
+ selectedViolations[file] = rule.violations[file];
164
+ }
165
+ return {
166
+ selection: {
167
+ ruleId: partialSelectableRule,
168
+ type: "partial",
169
+ violations: selectedViolations
170
+ },
171
+ success: true
172
+ };
173
+ }
174
+ return { success: false };
107
175
  };
108
- const selectRuleBasedOnViolationsLimit = (todoModule, limit, options = {}) => {
176
+ const selectRuleBasedOnViolationsLimit = (todoModule, limit, options) => {
109
177
  const { count: limitCount } = limit;
110
- const { autoFixableOnly = true } = options;
111
- let selectedRule = null;
112
- let maxViolations = 0;
178
+ const { allowPartialSelection, autoFixableOnly } = options;
179
+ if (limitCount <= 0) {
180
+ throw new Error("The violation limit must be greater than 0.");
181
+ }
182
+ let fullSelectableRule = null;
183
+ let selectedTargetCount = 0;
184
+ let partialSelectableRule = null;
113
185
  for (const [ruleId, entry] of Object.entries(todoModule.todo)) {
114
186
  if (autoFixableOnly && !entry.autoFix) {
115
187
  continue;
116
188
  }
117
- const totalViolations = Object.values(entry.violations).reduce(
189
+ const totalViolationCount = Object.values(entry.violations).reduce(
118
190
  (sum, count) => sum + count,
119
191
  0
120
192
  );
121
- if (totalViolations > maxViolations && totalViolations <= limitCount) {
122
- maxViolations = totalViolations;
123
- selectedRule = ruleId;
193
+ if (totalViolationCount > limitCount) {
194
+ if (allowPartialSelection && partialSelectableRule == null) {
195
+ partialSelectableRule = ruleId;
196
+ }
197
+ continue;
198
+ }
199
+ if (totalViolationCount > selectedTargetCount) {
200
+ fullSelectableRule = ruleId;
201
+ selectedTargetCount = totalViolationCount;
124
202
  }
125
203
  }
126
- return selectedRule != null ? { ruleId: selectedRule, success: true } : { success: false };
204
+ if (fullSelectableRule != null) {
205
+ return {
206
+ selection: {
207
+ ruleId: fullSelectableRule,
208
+ type: "full"
209
+ },
210
+ success: true
211
+ };
212
+ }
213
+ if (allowPartialSelection && isKeyOfTodo(todoModule.todo, partialSelectableRule)) {
214
+ const rule = todoModule.todo[partialSelectableRule];
215
+ let selectedCount = 0;
216
+ const selectedViolations = {};
217
+ for (const [file, count] of Object.entries(rule.violations)) {
218
+ if (selectedCount + count > limitCount) {
219
+ break;
220
+ }
221
+ selectedCount += count;
222
+ selectedViolations[file] = count;
223
+ }
224
+ if (Object.keys(selectedViolations).length === 0) {
225
+ return { success: false };
226
+ }
227
+ return {
228
+ selection: {
229
+ ruleId: partialSelectableRule,
230
+ type: "partial",
231
+ violations: selectedViolations
232
+ },
233
+ success: true
234
+ };
235
+ }
236
+ return { success: false };
237
+ };
238
+ const isKeyOfTodo = (todoModule, ruleId) => {
239
+ return isNonEmptyString(ruleId) && Object.hasOwn(todoModule, ruleId);
127
240
  };
128
241
 
129
242
  const selectRulesToFixAction = defineAction(
130
243
  async ({ core, logger }, input) => {
131
- const {
132
- limit,
133
- options = {
134
- autoFixableOnly: true
135
- }
136
- } = input;
244
+ const { limit, options } = input;
137
245
  const currentModule = await core.readTodoModule();
138
246
  if (!LATEST_MODULE_HANDLER.isVersion(currentModule)) {
139
247
  throw new Error(
@@ -192,6 +300,7 @@ const resolveCLIOperation = (input) => {
192
300
  return {
193
301
  limit,
194
302
  options: {
303
+ allowPartialSelection: input.allowPartialSelection,
195
304
  autoFixableOnly: input.autoFixableOnly
196
305
  }
197
306
  };
@@ -200,6 +309,13 @@ const resolveCLIOperation = (input) => {
200
309
  const consola = createConsola({ formatOptions: { date: false } });
201
310
  const cli = defineCommand({
202
311
  args: {
312
+ // IMPORTANT:
313
+ // do not set default values for boolean options!
314
+ // CLI flag name is unexpected behavior when default value is set.
315
+ //
316
+ // example: `auto-fixable-only` with `default: true` results in
317
+ // $ eslint-todo --no-auto-fixable-only
318
+ // because the default value is true, the flag is negated.
203
319
  // general options
204
320
  "cwd": {
205
321
  description: "Current working directory (default: .)",
@@ -222,8 +338,13 @@ const cli = defineCommand({
222
338
  type: "boolean"
223
339
  },
224
340
  // operation options
341
+ "allow-partial-selection": {
342
+ description: "Allow partial selection of violations. Only works with --correct. (default: false)",
343
+ required: false,
344
+ type: "boolean",
345
+ valueHint: "boolean"
346
+ },
225
347
  "auto-fixable-only": {
226
- default: true,
227
348
  description: "Only handle auto-fixable violations. (default: true)",
228
349
  required: false,
229
350
  type: "boolean",
@@ -272,12 +393,13 @@ const cli = defineCommand({
272
393
  todoFile: args["todo-file"]
273
394
  };
274
395
  const eslintTodoCore = new ESLintTodoCore(options);
275
- const ctx = resolveCLIContext({
396
+ const context = resolveCLIContext({
276
397
  cwd: cliCwd,
277
398
  mode: {
278
399
  correct: args.correct
279
400
  },
280
401
  operation: {
402
+ allowPartialSelection: args["allow-partial-selection"],
281
403
  autoFixableOnly: args["auto-fixable-only"],
282
404
  limit: args.limit,
283
405
  limitType: args["limit-type"]
@@ -285,43 +407,67 @@ const cli = defineCommand({
285
407
  todoFileAbsolutePath: eslintTodoCore.getTodoModulePath().absolute
286
408
  });
287
409
  await runAction(updateAction, { consola, options });
288
- if (ctx.mode === "generate") {
410
+ if (context.mode === "generate") {
289
411
  await runAction(genAction, { consola, options });
290
- consola.success(`ESLint todo file generated at ${ctx.todoFilePath}!`);
412
+ consola.success(`ESLint todo file generated at ${context.todoFilePath}!`);
291
413
  return;
292
414
  }
293
- if (ctx.mode === "correct") {
294
- const selection = await runAction(
415
+ if (context.mode === "correct") {
416
+ const result = await runAction(
295
417
  selectRulesToFixAction,
296
418
  { consola, options },
297
- ctx.operation
419
+ context.operation
298
420
  );
299
- if (!selection.success) {
421
+ if (!result.success) {
300
422
  consola.warn(
301
423
  "Couldn't find any rule to fix. Increase the limit and retry."
302
424
  );
303
425
  return;
304
426
  }
305
- await runAction(
306
- deleteRuleAction,
307
- { consola, options },
308
- { ruleId: selection.ruleId }
309
- );
310
- consola.success(
311
- `Rule ${colorize("magenta", selection.ruleId)} deleted from the todo file and now ESLint will detect the violations.`
427
+ await runAction(deleteRuleAction, { consola, options }, result.selection);
428
+ if (result.selection.type === "full") {
429
+ consola.success(
430
+ `All violations of rule ${colorize(
431
+ "magenta",
432
+ result.selection.ruleId
433
+ )} are deleted from the todo file and now ESLint will detect the violations.`
434
+ );
435
+ return;
436
+ }
437
+ if (result.selection.type === "partial") {
438
+ const violationCount = Object.entries(
439
+ result.selection.violations
440
+ ).reduce((sum, [, count]) => sum + count, 0);
441
+ consola.success(
442
+ `${violationCount} violations of rule ${colorize(
443
+ "magenta",
444
+ result.selection.ruleId
445
+ )} are deleted from the todo file and now ESLint will detect the violations.`
446
+ );
447
+ return;
448
+ }
449
+ const _exhaustiveCheck = result.selection;
450
+ throw new Error(
451
+ `Unknown selection type: ${JSON.stringify(_exhaustiveCheck)}`
312
452
  );
313
- return;
314
453
  }
315
- throw new Error(`Unknown mode: ${JSON.stringify(ctx.mode)}`);
454
+ throw new Error(`Unknown mode: ${JSON.stringify(context.mode)}`);
316
455
  },
317
456
  setup({ args }) {
318
457
  consola.info(`eslint-todo CLI ${version}`);
319
- if (args.debug === true) {
320
- consola.level = 4;
321
- } else if (args.trace === true) {
322
- consola.level = 5;
323
- } else if (args.verbose === true) {
324
- consola.level = 999;
458
+ switch (true) {
459
+ case args.debug: {
460
+ consola.level = 4;
461
+ break;
462
+ }
463
+ case args.trace: {
464
+ consola.level = 5;
465
+ break;
466
+ }
467
+ case args.verbose: {
468
+ consola.level = 999;
469
+ break;
470
+ }
325
471
  }
326
472
  }
327
473
  });
@@ -1,4 +1,4 @@
1
- import { E as ESLintTodoCore, T as TodoModuleV1Handler, a as TodoModuleV2Handler, b as buildESLintConfigForModule } from '../shared/eslint-todo.BwJWAS7j.mjs';
1
+ import { E as ESLintTodoCore, T as TodoModuleV1Handler, a as TodoModuleV2Handler, b as buildESLintConfigForModule } from '../shared/eslint-todo.BShlgWEx.mjs';
2
2
  import 'eslint';
3
3
  import 'node:fs';
4
4
  import 'node:fs/promises';
@@ -22,17 +22,17 @@ const eslintConfigTodo = async (userOptions = {}) => {
22
22
  })();
23
23
  const configs = [
24
24
  {
25
- files: [todoModulePath.relative],
26
- linterOptions: {
27
- reportUnusedDisableDirectives: false
28
- },
29
25
  name: "@sushichan044/eslint-todo/setup"
26
+ },
27
+ {
28
+ ignores: [todoModulePath.relative],
29
+ name: "@sushichan044/eslint-todo/ignore"
30
30
  }
31
31
  ];
32
32
  if (module == null || !TodoModuleV1Handler.isVersion(module) && !TodoModuleV2Handler.isVersion(module)) {
33
33
  configs.push({
34
34
  files: [todoModulePath.relative],
35
- name: "@sushichan044/eslint-todo/warning/YOU_ARE_USING_INVALID_TODO_FILE"
35
+ name: "@sushichan044/eslint-todo/warning/FILE_NOT_FOUND_OR_INVALID_TODO_FILE"
36
36
  });
37
37
  return configs;
38
38
  }
package/dist/index.d.mts CHANGED
@@ -1,3 +1,3 @@
1
1
  import 'eslint';
2
2
  import './shared/eslint-todo.BijUMnSZ.mjs';
3
- export { E as ESLintTodoCore } from './shared/eslint-todo.B_vRyhWL.mjs';
3
+ export { E as ESLintTodoCore } from './shared/eslint-todo.BR1uwV1v.mjs';
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  import 'eslint';
2
2
  import './shared/eslint-todo.BijUMnSZ.js';
3
- export { E as ESLintTodoCore } from './shared/eslint-todo.BD1wUnwb.js';
3
+ export { E as ESLintTodoCore } from './shared/eslint-todo.DyfNwDMO.js';
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@ import 'eslint';
2
2
  import 'node:fs';
3
3
  import 'node:fs/promises';
4
4
  import 'pathe';
5
- export { E as ESLintTodoCore } from './shared/eslint-todo.BwJWAS7j.mjs';
5
+ export { E as ESLintTodoCore } from './shared/eslint-todo.BShlgWEx.mjs';
6
6
  import 'magicast';
7
7
  import 'es-toolkit/compat';
8
8
  import 'valibot';
@@ -1,7 +1,7 @@
1
1
  import * as Comlink from 'comlink';
2
2
  import { RemoteESLintTodoCore } from './core.mjs';
3
3
  import '../shared/eslint-todo.BijUMnSZ.mjs';
4
- import '../shared/eslint-todo.B_vRyhWL.mjs';
4
+ import '../shared/eslint-todo.BR1uwV1v.mjs';
5
5
  import 'eslint';
6
6
 
7
7
  type RemoteCore = {
@@ -1,7 +1,7 @@
1
1
  import * as Comlink from 'comlink';
2
2
  import { RemoteESLintTodoCore } from './core.js';
3
3
  import '../shared/eslint-todo.BijUMnSZ.js';
4
- import '../shared/eslint-todo.BD1wUnwb.js';
4
+ import '../shared/eslint-todo.DyfNwDMO.js';
5
5
  import 'eslint';
6
6
 
7
7
  type RemoteCore = {
@@ -1,18 +1,18 @@
1
1
  import { U as UserOptions } from '../shared/eslint-todo.BijUMnSZ.mjs';
2
- import { I as IESLintTodoCoreLike, S as SupportedModules, R as RuleSeverity, E as ESLintTodoCore } from '../shared/eslint-todo.B_vRyhWL.mjs';
2
+ import { I as IESLintTodoCoreLike, S as SupportedModules, R as RuleSeverity, E as ESLintTodoCore } from '../shared/eslint-todo.BR1uwV1v.mjs';
3
3
  import 'eslint';
4
4
 
5
5
  declare class RemoteESLintTodoCore implements IESLintTodoCoreLike {
6
6
  #private;
7
7
  constructor(userOptions: UserOptions);
8
8
  buildESLintConfig(todoModule: SupportedModules, severity: RuleSeverity): ReturnType<ESLintTodoCore["buildESLintConfig"]>;
9
- buildTodoFromLintResults(...params: Parameters<ESLintTodoCore["buildTodoFromLintResults"]>): ReturnType<ESLintTodoCore["buildTodoFromLintResults"]>;
10
- getTodoModulePath(...params: Parameters<ESLintTodoCore["getTodoModulePath"]>): ReturnType<ESLintTodoCore["getTodoModulePath"]>;
11
- initializeESLint(...params: Parameters<ESLintTodoCore["initializeESLint"]>): ReturnType<ESLintTodoCore["initializeESLint"]>;
12
- lint(...params: Parameters<ESLintTodoCore["lint"]>): ReturnType<ESLintTodoCore["lint"]>;
13
- readTodoModule(...params: Parameters<ESLintTodoCore["_DO_NOT_USE_DIRECTLY_unsafeReadTodoModule"]>): ReturnType<ESLintTodoCore["_DO_NOT_USE_DIRECTLY_unsafeReadTodoModule"]>;
14
- resetTodoModule(...params: Parameters<ESLintTodoCore["resetTodoModule"]>): ReturnType<ESLintTodoCore["resetTodoModule"]>;
15
- writeTodoModule(...params: Parameters<ESLintTodoCore["writeTodoModule"]>): ReturnType<ESLintTodoCore["writeTodoModule"]>;
9
+ buildTodoFromLintResults(...parameters: Parameters<ESLintTodoCore["buildTodoFromLintResults"]>): ReturnType<ESLintTodoCore["buildTodoFromLintResults"]>;
10
+ getTodoModulePath(...parameters: Parameters<ESLintTodoCore["getTodoModulePath"]>): ReturnType<ESLintTodoCore["getTodoModulePath"]>;
11
+ initializeESLint(...parameters: Parameters<ESLintTodoCore["initializeESLint"]>): ReturnType<ESLintTodoCore["initializeESLint"]>;
12
+ lint(...parameters: Parameters<ESLintTodoCore["lint"]>): ReturnType<ESLintTodoCore["lint"]>;
13
+ readTodoModule(...parameters: Parameters<ESLintTodoCore["_DO_NOT_USE_DIRECTLY_unsafeReadTodoModule"]>): ReturnType<ESLintTodoCore["_DO_NOT_USE_DIRECTLY_unsafeReadTodoModule"]>;
14
+ resetTodoModule(...parameters: Parameters<ESLintTodoCore["resetTodoModule"]>): ReturnType<ESLintTodoCore["resetTodoModule"]>;
15
+ writeTodoModule(...parameters: Parameters<ESLintTodoCore["writeTodoModule"]>): ReturnType<ESLintTodoCore["writeTodoModule"]>;
16
16
  }
17
17
 
18
18
  export { RemoteESLintTodoCore };
@@ -1,18 +1,18 @@
1
1
  import { U as UserOptions } from '../shared/eslint-todo.BijUMnSZ.js';
2
- import { I as IESLintTodoCoreLike, S as SupportedModules, R as RuleSeverity, E as ESLintTodoCore } from '../shared/eslint-todo.BD1wUnwb.js';
2
+ import { I as IESLintTodoCoreLike, S as SupportedModules, R as RuleSeverity, E as ESLintTodoCore } from '../shared/eslint-todo.DyfNwDMO.js';
3
3
  import 'eslint';
4
4
 
5
5
  declare class RemoteESLintTodoCore implements IESLintTodoCoreLike {
6
6
  #private;
7
7
  constructor(userOptions: UserOptions);
8
8
  buildESLintConfig(todoModule: SupportedModules, severity: RuleSeverity): ReturnType<ESLintTodoCore["buildESLintConfig"]>;
9
- buildTodoFromLintResults(...params: Parameters<ESLintTodoCore["buildTodoFromLintResults"]>): ReturnType<ESLintTodoCore["buildTodoFromLintResults"]>;
10
- getTodoModulePath(...params: Parameters<ESLintTodoCore["getTodoModulePath"]>): ReturnType<ESLintTodoCore["getTodoModulePath"]>;
11
- initializeESLint(...params: Parameters<ESLintTodoCore["initializeESLint"]>): ReturnType<ESLintTodoCore["initializeESLint"]>;
12
- lint(...params: Parameters<ESLintTodoCore["lint"]>): ReturnType<ESLintTodoCore["lint"]>;
13
- readTodoModule(...params: Parameters<ESLintTodoCore["_DO_NOT_USE_DIRECTLY_unsafeReadTodoModule"]>): ReturnType<ESLintTodoCore["_DO_NOT_USE_DIRECTLY_unsafeReadTodoModule"]>;
14
- resetTodoModule(...params: Parameters<ESLintTodoCore["resetTodoModule"]>): ReturnType<ESLintTodoCore["resetTodoModule"]>;
15
- writeTodoModule(...params: Parameters<ESLintTodoCore["writeTodoModule"]>): ReturnType<ESLintTodoCore["writeTodoModule"]>;
9
+ buildTodoFromLintResults(...parameters: Parameters<ESLintTodoCore["buildTodoFromLintResults"]>): ReturnType<ESLintTodoCore["buildTodoFromLintResults"]>;
10
+ getTodoModulePath(...parameters: Parameters<ESLintTodoCore["getTodoModulePath"]>): ReturnType<ESLintTodoCore["getTodoModulePath"]>;
11
+ initializeESLint(...parameters: Parameters<ESLintTodoCore["initializeESLint"]>): ReturnType<ESLintTodoCore["initializeESLint"]>;
12
+ lint(...parameters: Parameters<ESLintTodoCore["lint"]>): ReturnType<ESLintTodoCore["lint"]>;
13
+ readTodoModule(...parameters: Parameters<ESLintTodoCore["_DO_NOT_USE_DIRECTLY_unsafeReadTodoModule"]>): ReturnType<ESLintTodoCore["_DO_NOT_USE_DIRECTLY_unsafeReadTodoModule"]>;
14
+ resetTodoModule(...parameters: Parameters<ESLintTodoCore["resetTodoModule"]>): ReturnType<ESLintTodoCore["resetTodoModule"]>;
15
+ writeTodoModule(...parameters: Parameters<ESLintTodoCore["writeTodoModule"]>): ReturnType<ESLintTodoCore["writeTodoModule"]>;
16
16
  }
17
17
 
18
18
  export { RemoteESLintTodoCore };
@@ -1,7 +1,7 @@
1
1
  import * as Comlink from 'comlink';
2
2
  import nodeEndPoint from 'comlink/dist/esm/node-adapter.mjs';
3
3
  import { parentPort } from 'node:worker_threads';
4
- import { E as ESLintTodoCore } from '../shared/eslint-todo.BwJWAS7j.mjs';
4
+ import { E as ESLintTodoCore } from '../shared/eslint-todo.BShlgWEx.mjs';
5
5
  import 'eslint';
6
6
  import 'node:fs';
7
7
  import 'node:fs/promises';
@@ -23,26 +23,28 @@ class RemoteESLintTodoCore {
23
23
  buildESLintConfig(todoModule, severity) {
24
24
  return this.#todoCore.buildESLintConfig(todoModule, severity);
25
25
  }
26
- buildTodoFromLintResults(...params) {
27
- return this.#todoCore.buildTodoFromLintResults(...params);
26
+ buildTodoFromLintResults(...parameters) {
27
+ return this.#todoCore.buildTodoFromLintResults(...parameters);
28
28
  }
29
- getTodoModulePath(...params) {
30
- return this.#todoCore.getTodoModulePath(...params);
29
+ getTodoModulePath(...parameters) {
30
+ return this.#todoCore.getTodoModulePath(...parameters);
31
31
  }
32
- initializeESLint(...params) {
33
- return this.#todoCore.initializeESLint(...params);
32
+ initializeESLint(...parameters) {
33
+ return this.#todoCore.initializeESLint(...parameters);
34
34
  }
35
- async lint(...params) {
36
- return this.#todoCore.lint(...params);
35
+ async lint(...parameters) {
36
+ return this.#todoCore.lint(...parameters);
37
37
  }
38
- async readTodoModule(...params) {
39
- return this.#todoCore._DO_NOT_USE_DIRECTLY_unsafeReadTodoModule(...params);
38
+ async readTodoModule(...parameters) {
39
+ return this.#todoCore._DO_NOT_USE_DIRECTLY_unsafeReadTodoModule(
40
+ ...parameters
41
+ );
40
42
  }
41
- async resetTodoModule(...params) {
42
- return this.#todoCore.resetTodoModule(...params);
43
+ async resetTodoModule(...parameters) {
44
+ return this.#todoCore.resetTodoModule(...parameters);
43
45
  }
44
- async writeTodoModule(...params) {
45
- return this.#todoCore.writeTodoModule(...params);
46
+ async writeTodoModule(...parameters) {
47
+ return this.#todoCore.writeTodoModule(...parameters);
46
48
  }
47
49
  }
48
50
  Comlink.expose(
@@ -82,7 +82,7 @@ type TodoFilePath = {
82
82
 
83
83
  type MaybePromise<T> = Promise<T> | T;
84
84
  type MaybePromisifyAllMethods<T> = {
85
- [K in keyof T]: T[K] extends (...args: infer A) => infer R ? R extends PromiseLike<unknown> ? (...args: A) => R : (...args: A) => MaybePromise<R> : T[K];
85
+ [K in keyof T]: T[K] extends (...arguments_: infer A) => infer R ? R extends PromiseLike<unknown> ? (...arguments_: A) => R : (...arguments_: A) => MaybePromise<R> : T[K];
86
86
  };
87
87
 
88
88
  type ESLintInitializeOptions = Pick<ESLint.Options, "overrideConfig">;
@@ -18,9 +18,9 @@ const generateTodoModuleCode = (eslintTodo) => {
18
18
  "",
19
19
  "export default {};"
20
20
  ].join("\n");
21
- const mod = parseModule(js);
22
- mod.exports.default = eslintTodo;
23
- const { code: jsCode } = generateCode(mod, {
21
+ const module_ = parseModule(js);
22
+ module_.exports.default = eslintTodo;
23
+ const { code: jsCode } = generateCode(module_, {
24
24
  format: { objectCurlySpacing: true, tabWidth: 2 }
25
25
  });
26
26
  return `${jsCode}
@@ -28,7 +28,7 @@ const generateTodoModuleCode = (eslintTodo) => {
28
28
  };
29
29
 
30
30
  const escapeGlobCharacters = (glob) => {
31
- return glob.replace(/\\/g, "\\\\").replace(/\*/g, "\\*").replace(/\?/g, "\\?").replace(/\[/g, "\\[").replace(/\]/g, "\\]").replace(/\{/g, "\\{").replace(/\}/g, "\\}").replace(/\)/g, "\\)").replace(/\(/g, "\\(").replace(/\!/g, "\\!");
31
+ return glob.replaceAll("\\", "\\\\").replaceAll("*", String.raw`\*`).replaceAll("?", String.raw`\?`).replaceAll("[", String.raw`\[`).replaceAll("]", String.raw`\]`).replaceAll("{", String.raw`\{`).replaceAll("}", String.raw`\}`).replaceAll(")", String.raw`\)`).replaceAll("(", String.raw`\(`).replaceAll("!", String.raw`\!`);
32
32
  };
33
33
  const isNonEmptyString = (maybeString) => {
34
34
  return typeof maybeString === "string" && maybeString !== "";
@@ -41,7 +41,7 @@ const TodoModuleV2Handler = {
41
41
  version: 2,
42
42
  buildConfigsForESLint: ({ todo }, severity) => {
43
43
  return Object.entries(todo).map(([ruleId, entry]) => ({
44
- files: Object.keys(entry.violations).map(escapeGlobCharacters),
44
+ files: Object.keys(entry.violations).map((f) => escapeGlobCharacters(f)),
45
45
  name: `@sushichan044/eslint-todo/${severity}/${ruleId}`,
46
46
  rules: {
47
47
  [ruleId]: severity
@@ -49,23 +49,23 @@ const TodoModuleV2Handler = {
49
49
  }));
50
50
  },
51
51
  buildTodoFromLintResults(lintResult, options) {
52
- return lintResult.reduce((todoMod, result) => {
52
+ return lintResult.reduce((todoModule, result) => {
53
53
  const relativeFilePath = relative(options.cwd, result.filePath);
54
54
  for (const message of result.messages) {
55
55
  if (!isNonEmptyString(message.ruleId)) {
56
56
  continue;
57
57
  }
58
- todoMod.todo[message.ruleId] ??= {
58
+ todoModule.todo[message.ruleId] ??= {
59
59
  autoFix: false,
60
60
  violations: {}
61
61
  };
62
- todoMod.todo[message.ruleId].violations[relativeFilePath] ??= 0;
63
- if (Object.hasOwn(todoMod.todo, message.ruleId)) {
64
- todoMod.todo[message.ruleId].violations[relativeFilePath]++;
65
- todoMod.todo[message.ruleId].autoFix = message.fix != null;
62
+ todoModule.todo[message.ruleId].violations[relativeFilePath] ??= 0;
63
+ if (Object.hasOwn(todoModule.todo, message.ruleId)) {
64
+ todoModule.todo[message.ruleId].violations[relativeFilePath]++;
65
+ todoModule.todo[message.ruleId].autoFix = message.fix != null;
66
66
  }
67
67
  }
68
- return todoMod;
68
+ return todoModule;
69
69
  }, TodoModuleV2Handler.getDefaultTodo());
70
70
  },
71
71
  getDefaultTodo() {
@@ -89,7 +89,7 @@ const TodoModuleV1Handler = {
89
89
  version: 1,
90
90
  buildConfigsForESLint: (todo, severity) => {
91
91
  return Object.entries(todo).map(([ruleId, entry]) => ({
92
- files: entry.files.map(escapeGlobCharacters),
92
+ files: entry.files.map((f) => escapeGlobCharacters(f)),
93
93
  name: `@sushichan044/eslint-todo/${severity}/${ruleId}`,
94
94
  rules: {
95
95
  [ruleId]: severity
@@ -97,22 +97,22 @@ const TodoModuleV1Handler = {
97
97
  }));
98
98
  },
99
99
  buildTodoFromLintResults(lintResult, options) {
100
- return lintResult.reduce((todoMod, result) => {
100
+ return lintResult.reduce((todoModule, result) => {
101
101
  const relativeFilePath = relative(options.cwd, result.filePath);
102
102
  for (const message of result.messages) {
103
103
  if (!isNonEmptyString(message.ruleId)) {
104
104
  continue;
105
105
  }
106
- todoMod[message.ruleId] ??= {
106
+ todoModule[message.ruleId] ??= {
107
107
  autoFix: false,
108
108
  files: []
109
109
  };
110
- if (Object.hasOwn(todoMod, message.ruleId)) {
111
- todoMod[message.ruleId].files.push(relativeFilePath);
112
- todoMod[message.ruleId].autoFix = message.fix != null;
110
+ if (Object.hasOwn(todoModule, message.ruleId)) {
111
+ todoModule[message.ruleId].files.push(relativeFilePath);
112
+ todoModule[message.ruleId].autoFix = message.fix != null;
113
113
  }
114
114
  }
115
- return todoMod;
115
+ return todoModule;
116
116
  }, TodoModuleV1Handler.getDefaultTodo());
117
117
  },
118
118
  getDefaultTodo() {
@@ -243,4 +243,4 @@ class ESLintTodoCore {
243
243
  }
244
244
  }
245
245
 
246
- export { ESLintTodoCore as E, LATEST_MODULE_HANDLER as L, TodoModuleV1Handler as T, TodoModuleV2Handler as a, buildESLintConfigForModule as b };
246
+ export { ESLintTodoCore as E, LATEST_MODULE_HANDLER as L, TodoModuleV1Handler as T, TodoModuleV2Handler as a, buildESLintConfigForModule as b, isNonEmptyString as i };
@@ -82,7 +82,7 @@ type TodoFilePath = {
82
82
 
83
83
  type MaybePromise<T> = Promise<T> | T;
84
84
  type MaybePromisifyAllMethods<T> = {
85
- [K in keyof T]: T[K] extends (...args: infer A) => infer R ? R extends PromiseLike<unknown> ? (...args: A) => R : (...args: A) => MaybePromise<R> : T[K];
85
+ [K in keyof T]: T[K] extends (...arguments_: infer A) => infer R ? R extends PromiseLike<unknown> ? (...arguments_: A) => R : (...arguments_: A) => MaybePromise<R> : T[K];
86
86
  };
87
87
 
88
88
  type ESLintInitializeOptions = Pick<ESLint.Options, "overrideConfig">;
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "type": "git",
5
5
  "url": "https://github.com/sushichan044/eslint-todo.git"
6
6
  },
7
- "version": "0.0.2",
7
+ "version": "0.0.3",
8
8
  "type": "module",
9
9
  "bin": {
10
10
  "eslint-todo": "bin/eslint-todo.mjs"
@@ -36,25 +36,29 @@
36
36
  "klona": "2.0.6",
37
37
  "magicast": "0.3.5",
38
38
  "pathe": "2.0.3",
39
- "valibot": "1.0.0-rc.1"
39
+ "valibot": "1.0.0-rc.3"
40
40
  },
41
41
  "devDependencies": {
42
- "@eslint/config-inspector": "1.0.0",
43
- "@types/node": "22.13.4",
42
+ "@eslint/config-inspector": "1.0.1",
43
+ "@types/node": "22.13.8",
44
44
  "@virtual-live-lab/eslint-config": "2.2.17",
45
45
  "@virtual-live-lab/prettier-config": "2.0.16",
46
46
  "@virtual-live-lab/tsconfig": "2.1.17",
47
- "@vitest/coverage-v8": "3.0.5",
48
- "@vitest/eslint-plugin": "1.1.31",
49
- "eslint": "9.20.1",
47
+ "@vitest/coverage-v8": "3.0.7",
48
+ "@vitest/eslint-plugin": "1.1.36",
49
+ "eslint": "9.21.0",
50
50
  "eslint-flat-config-utils": "2.0.1",
51
+ "eslint-plugin-import-access": "2.2.2",
52
+ "eslint-plugin-unicorn": "57.0.0",
51
53
  "eslint-typegen": "2.0.0",
52
- "pkg-pr-new": "0.0.39",
53
- "prettier": "3.5.1",
54
+ "globals": "16.0.0",
55
+ "pkg-pr-new": "0.0.40",
56
+ "pnpm": "10.5.2",
57
+ "prettier": "3.5.3",
54
58
  "typescript": "5.7.3",
55
- "typescript-eslint": "8.24.0",
56
- "unbuild": "3.3.1",
57
- "vitest": "3.0.5"
59
+ "typescript-eslint": "8.25.0",
60
+ "unbuild": "3.5.0",
61
+ "vitest": "3.0.7"
58
62
  },
59
63
  "engines": {
60
64
  "node": "^20.0.0 || ^22.0.0 || ^23.0.0"