@sushichan044/eslint-todo 0.2.5 → 0.3.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 (39) hide show
  1. package/README.md +1 -28
  2. package/config-schema.json +4 -7
  3. package/dist/action/delete-rule.mjs +1 -2
  4. package/dist/action/gen.mjs +1 -2
  5. package/dist/action/index.mjs +1 -2
  6. package/dist/cli/commands/common-arguments.mjs +5 -12
  7. package/dist/cli/commands/correct.mjs +1 -2
  8. package/dist/cli/commands/generate.mjs +1 -2
  9. package/dist/cli/commands/index.mjs +5 -12
  10. package/dist/cli/handlers/correct.mjs +6 -10
  11. package/dist/cli/handlers/generate.mjs +4 -7
  12. package/dist/config/validation.mjs +11 -16
  13. package/dist/eslint/index.mjs +2 -5
  14. package/dist/index.mjs +1 -2
  15. package/dist/node_modules/.pnpm/{typia@9.6.0_typescript@5.8.3 → typia@11.0.0_typescript@5.9.3}/node_modules/typia/lib/internal/_accessExpressionAsString.mjs +2 -2
  16. package/dist/node_modules/.pnpm/{typia@9.6.0_typescript@5.8.3 → typia@11.0.0_typescript@5.9.3}/node_modules/typia/lib/internal/_createStandardSchema.mjs +7 -7
  17. package/dist/node_modules/.pnpm/{typia@9.6.0_typescript@5.8.3 → typia@11.0.0_typescript@5.9.3}/node_modules/typia/lib/internal/_validateReport.mjs +2 -2
  18. package/dist/operation/select-rule.mjs +11 -17
  19. package/dist/package.mjs +1 -1
  20. package/dist/path.d.mts +0 -3
  21. package/dist/path.mjs +1 -2
  22. package/dist/serializer.mjs +2 -3
  23. package/dist/todofile/index.d.mts +0 -8
  24. package/dist/todofile/v1.mjs +5 -6
  25. package/dist/todofile/v2.d.mts +2 -0
  26. package/dist/todofile/v2.mjs +7 -10
  27. package/dist/utils/glob.mjs +1 -2
  28. package/dist/worker/core/client.mjs +2 -5
  29. package/package.json +54 -73
  30. package/dist/cli/commands/mcp.mjs +0 -22
  31. package/dist/cli/handlers/mcp.mjs +0 -22
  32. package/dist/lib/eslint.d.mts +0 -11
  33. package/dist/mcp/index.d.mts +0 -8
  34. package/dist/mcp/index.mjs +0 -12
  35. package/dist/mcp/setup.d.mts +0 -11
  36. package/dist/mcp/setup.mjs +0 -108
  37. package/dist/mcp/stdio.mjs +0 -7
  38. package/dist/mcp/transport/stdio.mjs +0 -10
  39. package/dist/mcp/types.d.mts +0 -14
package/README.md CHANGED
@@ -22,7 +22,7 @@ Requires:
22
22
  - **Flat Config Required**
23
23
  - If you are using legacy config, you must migrate into flat config first.
24
24
  - Utilities like [@eslint/compat](https://github.com/eslint/rewrite/tree/main/packages/compat) can help you.
25
- - Node.js: `>= 20.0.0`
25
+ - Node.js: `^20.12.0 || ^22.0.0 || >=24.0.0`
26
26
  - May work in Deno, but not tested.
27
27
 
28
28
  ## Getting Started
@@ -125,30 +125,3 @@ Sure!
125
125
  ```
126
126
 
127
127
  </details>
128
-
129
- ## Use as MCP server (Experimental)
130
-
131
- eslint-todo provides some useful tools to AI Agents via MCP.
132
-
133
- You mus specify `--mcp` and `--root <root path>`.
134
-
135
- ### Setup for VSCode
136
-
137
- update `.vscode/mcp.json` in your workspace:
138
-
139
- ```json
140
- {
141
- "servers": {
142
- "eslint-todo": {
143
- "type": "stdio",
144
- "command": "npx",
145
- "args": [
146
- "@sushichan044/eslint-todo",
147
- "--mcp",
148
- "--root",
149
- "${workspaceFolder}"
150
- ]
151
- }
152
- }
153
- }
154
- ```
@@ -61,13 +61,10 @@
61
61
  },
62
62
  "type": {
63
63
  "description": "Type of limit to apply.",
64
- "oneOf": [
65
- {
66
- "const": "file"
67
- },
68
- {
69
- "const": "violation"
70
- }
64
+ "type": "string",
65
+ "enum": [
66
+ "file",
67
+ "violation"
71
68
  ]
72
69
  }
73
70
  },
@@ -5,8 +5,7 @@ import { deleteRule } from "../operation/delete-rule.mjs";
5
5
  const deleteRuleAction = defineAction(async ({ core, hooks }, input) => {
6
6
  const currentModule = await core.readTodoModule();
7
7
  if (!TodoModuleV2Handler.isVersion(currentModule)) throw new Error("This action requires the latest version of the todo file.");
8
- const hasChanges = await core.todoModuleHasUncommittedChanges();
9
- if (hasChanges) {
8
+ if (await core.todoModuleHasUncommittedChanges()) {
10
9
  await hooks.callHook("warn:todo-module-is-dirty");
11
10
  return;
12
11
  }
@@ -1,8 +1,7 @@
1
1
  import { TodoModuleSerializer } from "../serializer.mjs";
2
2
  import { defineAction } from "./index.mjs";
3
3
  const genAction = defineAction(async ({ core, hooks }) => {
4
- const hasChanges = await core.todoModuleHasUncommittedChanges();
5
- if (hasChanges) {
4
+ if (await core.todoModuleHasUncommittedChanges()) {
6
5
  await hooks.callHook("warn:todo-module-is-dirty");
7
6
  return;
8
7
  }
@@ -16,8 +16,7 @@ function prepareAction(action, options) {
16
16
  hooks
17
17
  };
18
18
  try {
19
- const result = input === void 0 ? await action(actionApi) : await action(actionApi, input);
20
- return result;
19
+ return input === void 0 ? await action(actionApi) : await action(actionApi, input);
21
20
  } catch (error) {
22
21
  throw error;
23
22
  } finally {
@@ -18,18 +18,11 @@ const commonArguments = {
18
18
  type: "string"
19
19
  }
20
20
  };
21
- const modeArguments = {
22
- correct: {
23
- default: false,
24
- description: "Launch the correct mode (default: false)",
25
- type: "boolean"
26
- },
27
- mcp: {
28
- default: false,
29
- description: "Launch the MCP server. (default: false)",
30
- type: "boolean"
31
- }
32
- };
21
+ const modeArguments = { correct: {
22
+ default: false,
23
+ description: "Launch the correct mode (default: false)",
24
+ type: "boolean"
25
+ } };
33
26
  const correctModeArguments = {
34
27
  "correct.autoFixableOnly": {
35
28
  description: "Allow to select non auto-fixable rules.",
@@ -34,8 +34,7 @@ const correctCmd = define({
34
34
  todoFile: context.values.todoFile
35
35
  };
36
36
  const cliCwd = cwd();
37
- const userConfig = isDirty ? userCLIConfig : await resolveFileConfig(cliCwd);
38
- return await handleCorrect(cliCwd, userConfig);
37
+ return await handleCorrect(cliCwd, isDirty ? userCLIConfig : await resolveFileConfig(cliCwd));
39
38
  }
40
39
  });
41
40
  export { correctCmd };
@@ -15,8 +15,7 @@ const generateCmd = define({
15
15
  todoFile: context.values.todoFile
16
16
  };
17
17
  const cliCwd = cwd();
18
- const userConfig = isDirty ? userCLIConfig : await resolveFileConfig(cliCwd);
19
- return await handleGenerate(cliCwd, userConfig);
18
+ return await handleGenerate(cliCwd, isDirty ? userCLIConfig : await resolveFileConfig(cliCwd));
20
19
  }
21
20
  });
22
21
  export { generateCmd };
@@ -3,18 +3,16 @@ import { resolveFileConfig } from "../../config/resolve.mjs";
3
3
  import { logger } from "../logger.mjs";
4
4
  import { handleCorrect } from "../handlers/correct.mjs";
5
5
  import { handleGenerate } from "../handlers/generate.mjs";
6
- import { handleMCP } from "../handlers/mcp.mjs";
7
6
  import { commonArguments, correctModeArguments, modeArguments } from "./common-arguments.mjs";
8
7
  import { correctCmd } from "./correct.mjs";
9
8
  import { generateCmd } from "./generate.mjs";
10
- import { mcpCmd } from "./mcp.mjs";
11
9
  import { cwd } from "node:process";
12
10
  import { cli, define } from "gunshi";
13
11
  import { renderHeader } from "gunshi/renderer";
14
- const subCommands = /* @__PURE__ */ new Map();
15
- subCommands.set("generate", generateCmd);
16
- subCommands.set("correct", correctCmd);
17
- subCommands.set("mcp", mcpCmd);
12
+ const subCommands = {
13
+ correct: correctCmd,
14
+ generate: generateCmd
15
+ };
18
16
  const mainCmd = define({
19
17
  args: {
20
18
  ...commonArguments,
@@ -23,12 +21,11 @@ const mainCmd = define({
23
21
  },
24
22
  name: "root",
25
23
  run: async (context) => {
26
- const { correct: _explicitCorrect, mcp: _explicitMcp,...flagsExceptMode } = context.explicit;
24
+ const { correct: _explicitCorrect, ...flagsExceptMode } = context.explicit;
27
25
  const isDirty = Object.values(flagsExceptMode).includes(true);
28
26
  if (isDirty) logger.warn("Ignoring config file because config is passed via CLI flags.");
29
27
  const mode = (() => {
30
28
  if (context.values.correct) return "correct";
31
- if (context.values.mcp) return "mcp";
32
29
  return "generate";
33
30
  })();
34
31
  const userCLIConfig = {
@@ -53,10 +50,6 @@ const mainCmd = define({
53
50
  };
54
51
  const cliCwd = cwd();
55
52
  const userConfig = isDirty ? userCLIConfig : await resolveFileConfig(cliCwd);
56
- if (mode === "mcp") {
57
- logger.warn("The `--mcp` flag is deprecated and will be removed in v1. Use the `mcp` sub command instead.");
58
- return await handleMCP(cliCwd, userConfig);
59
- }
60
53
  if (mode === "correct") {
61
54
  logger.warn("The `--correct` flag is deprecated and will be removed in v1. Use the `correct` sub command instead.");
62
55
  return await handleCorrect(cliCwd, userConfig);
@@ -10,19 +10,17 @@ import { resolveFlatConfig } from "@sushichan044/eslint-config-array-resolver";
10
10
  import { colorize } from "consola/utils";
11
11
  const handleCorrect = async (cwd, userConfig) => {
12
12
  const config = configWithDefault(userConfig);
13
- const eslintConfig = await resolveFlatConfig(config.root);
14
- const eslintConfigSubset = createESLintConfigSubset(eslintConfig);
13
+ const eslintConfigSubset = createESLintConfigSubset(await resolveFlatConfig(config.root));
15
14
  const eslintTodoCore = new ESLintTodoCore(config);
16
15
  const todoFilePathFromCLI = relative(cwd, eslintTodoCore.getTodoModulePath().absolute);
17
- const todoModuleHasChanges = await eslintTodoCore.todoModuleHasUncommittedChanges();
18
- if (todoModuleHasChanges) {
16
+ if (await eslintTodoCore.todoModuleHasUncommittedChanges()) {
19
17
  logger.warn(`Attempting to run \`eslint-todo --correct\` on ${todoFilePathFromCLI} which has uncommitted changes. Please commit or stash these changes and try again.
20
18
 
21
19
  This command makes ignored errors in ${todoFilePathFromCLI} detectable by ESLint again.
22
20
  If you want to fix ESLint errors, please use \`eslint --fix\` instead.`);
23
21
  return;
24
22
  }
25
- const selectRulesToFixExecutor = prepareAction(selectRulesToFixAction, {
23
+ const result = await prepareAction(selectRulesToFixAction, {
26
24
  config,
27
25
  eslintConfig: eslintConfigSubset,
28
26
  hooks: {
@@ -37,10 +35,9 @@ If you want to fix ESLint errors, please use \`eslint --fix\` instead.`);
37
35
  logger.success(`Selected ${result$1.selection.ruleId}.`);
38
36
  }
39
37
  }
40
- });
41
- const result = await selectRulesToFixExecutor();
38
+ })();
42
39
  if (!result.success) return;
43
- const deleteRuleExecutor = prepareAction(deleteRuleAction, {
40
+ await prepareAction(deleteRuleAction, {
44
41
  config,
45
42
  eslintConfig: eslintConfigSubset,
46
43
  hooks: { "after:delete-and-write": () => {
@@ -56,7 +53,6 @@ If you want to fix ESLint errors, please use \`eslint --fix\` instead.`);
56
53
  const _exhaustiveCheck = result.selection;
57
54
  throw new Error(`Unknown selection type: ${JSON.stringify(_exhaustiveCheck)}`);
58
55
  } }
59
- });
60
- await deleteRuleExecutor(result.selection);
56
+ })(result.selection);
61
57
  };
62
58
  export { handleCorrect };
@@ -8,11 +8,9 @@ import { relative } from "pathe";
8
8
  import { resolveFlatConfig } from "@sushichan044/eslint-config-array-resolver";
9
9
  const handleGenerate = async (cwd, userConfig) => {
10
10
  const config = configWithDefault(userConfig);
11
- const eslintConfig = await resolveFlatConfig(config.root);
12
- const eslintConfigSubset = createESLintConfigSubset(eslintConfig);
13
- const eslintTodoCore = new ESLintTodoCore(config);
14
- const todoFilePathFromCLI = relative(cwd, eslintTodoCore.getTodoModulePath().absolute);
15
- const genActionExecutor = prepareAction(genAction, {
11
+ const eslintConfigSubset = createESLintConfigSubset(await resolveFlatConfig(config.root));
12
+ const todoFilePathFromCLI = relative(cwd, new ESLintTodoCore(config).getTodoModulePath().absolute);
13
+ await prepareAction(genAction, {
16
14
  config,
17
15
  eslintConfig: eslintConfigSubset,
18
16
  hooks: {
@@ -29,7 +27,6 @@ const handleGenerate = async (cwd, userConfig) => {
29
27
  logger.success(`ESLint todo file generated at ${todoFilePathFromCLI}!`);
30
28
  }
31
29
  }
32
- });
33
- await genActionExecutor();
30
+ })();
34
31
  };
35
32
  export { handleGenerate };
@@ -1,10 +1,10 @@
1
1
  import { __toESM } from "../_virtual/rolldown_runtime.mjs";
2
- import { require__accessExpressionAsString } from "../node_modules/.pnpm/typia@9.6.0_typescript@5.8.3/node_modules/typia/lib/internal/_accessExpressionAsString.mjs";
3
- import { require__validateReport } from "../node_modules/.pnpm/typia@9.6.0_typescript@5.8.3/node_modules/typia/lib/internal/_validateReport.mjs";
4
- import { require__createStandardSchema } from "../node_modules/.pnpm/typia@9.6.0_typescript@5.8.3/node_modules/typia/lib/internal/_createStandardSchema.mjs";
5
- var import__accessExpressionAsString = __toESM(require__accessExpressionAsString(), 1);
6
- var import__validateReport = __toESM(require__validateReport(), 1);
7
- var import__createStandardSchema = __toESM(require__createStandardSchema(), 1);
2
+ import { require__accessExpressionAsString } from "../node_modules/.pnpm/typia@11.0.0_typescript@5.9.3/node_modules/typia/lib/internal/_accessExpressionAsString.mjs";
3
+ import { require__validateReport } from "../node_modules/.pnpm/typia@11.0.0_typescript@5.9.3/node_modules/typia/lib/internal/_validateReport.mjs";
4
+ import { require__createStandardSchema } from "../node_modules/.pnpm/typia@11.0.0_typescript@5.9.3/node_modules/typia/lib/internal/_createStandardSchema.mjs";
5
+ var import__accessExpressionAsString = /* @__PURE__ */ __toESM(require__accessExpressionAsString());
6
+ var import__validateReport = /* @__PURE__ */ __toESM(require__validateReport());
7
+ var import__createStandardSchema = /* @__PURE__ */ __toESM(require__createStandardSchema());
8
8
  const UserConfigSchema = (() => {
9
9
  const _io0 = (input, _exceptionable = true) => (void 0 === input.correct || "object" === typeof input.correct && null !== input.correct && false === Array.isArray(input.correct) && _io1(input.correct, _exceptionable)) && (void 0 === input.root || "string" === typeof input.root) && (void 0 === input.todoFile || "string" === typeof input.todoFile) && (0 === Object.keys(input).length || Object.keys(input).every((key) => {
10
10
  if ([
@@ -12,8 +12,7 @@ const UserConfigSchema = (() => {
12
12
  "root",
13
13
  "todoFile"
14
14
  ].some((prop) => key === prop)) return true;
15
- const value = input[key];
16
- if (void 0 === value) return true;
15
+ if (void 0 === input[key]) return true;
17
16
  return false;
18
17
  }));
19
18
  const _io1 = (input, _exceptionable = true) => (void 0 === input.autoFixableOnly || "boolean" === typeof input.autoFixableOnly) && (void 0 === input.exclude || "object" === typeof input.exclude && null !== input.exclude && false === Array.isArray(input.exclude) && _io2(input.exclude, _exceptionable)) && (void 0 === input.include || "object" === typeof input.include && null !== input.include && false === Array.isArray(input.include) && _io3(input.include, _exceptionable)) && (void 0 === input.limit || "object" === typeof input.limit && null !== input.limit && false === Array.isArray(input.limit) && _io4(input.limit, _exceptionable)) && (void 0 === input.partialSelection || "boolean" === typeof input.partialSelection) && (0 === Object.keys(input).length || Object.keys(input).every((key) => {
@@ -24,26 +23,22 @@ const UserConfigSchema = (() => {
24
23
  "limit",
25
24
  "partialSelection"
26
25
  ].some((prop) => key === prop)) return true;
27
- const value = input[key];
28
- if (void 0 === value) return true;
26
+ if (void 0 === input[key]) return true;
29
27
  return false;
30
28
  }));
31
29
  const _io2 = (input, _exceptionable = true) => (void 0 === input.files || Array.isArray(input.files) && input.files.every((elem, _index1) => "string" === typeof elem)) && (void 0 === input.rules || Array.isArray(input.rules) && input.rules.every((elem, _index2) => "string" === typeof elem)) && (0 === Object.keys(input).length || Object.keys(input).every((key) => {
32
30
  if (["files", "rules"].some((prop) => key === prop)) return true;
33
- const value = input[key];
34
- if (void 0 === value) return true;
31
+ if (void 0 === input[key]) return true;
35
32
  return false;
36
33
  }));
37
34
  const _io3 = (input, _exceptionable = true) => (void 0 === input.files || Array.isArray(input.files) && input.files.every((elem, _index3) => "string" === typeof elem)) && (void 0 === input.rules || Array.isArray(input.rules) && input.rules.every((elem, _index4) => "string" === typeof elem)) && (0 === Object.keys(input).length || Object.keys(input).every((key) => {
38
35
  if (["files", "rules"].some((prop) => key === prop)) return true;
39
- const value = input[key];
40
- if (void 0 === value) return true;
36
+ if (void 0 === input[key]) return true;
41
37
  return false;
42
38
  }));
43
39
  const _io4 = (input, _exceptionable = true) => (void 0 === input.count || "number" === typeof input.count) && (void 0 === input.type || "file" === input.type || "violation" === input.type) && (0 === Object.keys(input).length || Object.keys(input).every((key) => {
44
40
  if (["count", "type"].some((prop) => key === prop)) return true;
45
- const value = input[key];
46
- if (void 0 === value) return true;
41
+ if (void 0 === input[key]) return true;
47
42
  return false;
48
43
  }));
49
44
  const _vo0 = (input, _path, _exceptionable = true) => [
@@ -8,13 +8,10 @@ import { cwd } from "node:process";
8
8
  const eslintConfigTodo = async (config) => {
9
9
  const root = config?.cwd;
10
10
  const todoFile = config?.todoFile;
11
- const cwdString = cwd();
12
- const configFromFile = await resolveFileConfig(cwdString);
13
- const resolvedConfig = mergeUserConfig(configFromFile, {
11
+ const core = new ESLintTodoCore(mergeUserConfig(await resolveFileConfig(cwd()), {
14
12
  root,
15
13
  todoFile
16
- });
17
- const core = new ESLintTodoCore(resolvedConfig);
14
+ }));
18
15
  const todoModulePath = core.getTodoModulePath();
19
16
  const module = await (async () => {
20
17
  try {
package/dist/index.mjs CHANGED
@@ -36,8 +36,7 @@ var ESLintTodoCore = class {
36
36
  });
37
37
  }
38
38
  async lint() {
39
- const result = await this.#eslint.lintFiles(resolve(this.#config.root, "**/*"));
40
- return result;
39
+ return await this.#eslint.lintFiles(resolve(this.#config.root, "**/*"));
41
40
  }
42
41
  async resetTodoModule() {
43
42
  if (!existsSync(this.#todoFilePath.absolute)) return;
@@ -1,5 +1,5 @@
1
1
  import { __commonJSMin } from "../../../../../../../_virtual/rolldown_runtime.mjs";
2
- var require__accessExpressionAsString = __commonJSMin((exports) => {
2
+ var require__accessExpressionAsString = /* @__PURE__ */ __commonJSMin(((exports) => {
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports._accessExpressionAsString = void 0;
5
5
  const _accessExpressionAsString = (str) => variable(str) ? `.${str}` : `[${JSON.stringify(str)}]`;
@@ -44,6 +44,6 @@ var require__accessExpressionAsString = __commonJSMin((exports) => {
44
44
  "while",
45
45
  "with"
46
46
  ]);
47
- });
47
+ }));
48
48
  export default require__accessExpressionAsString();
49
49
  export { require__accessExpressionAsString };
@@ -1,5 +1,5 @@
1
1
  import { __commonJSMin } from "../../../../../../../_virtual/rolldown_runtime.mjs";
2
- var require__createStandardSchema = __commonJSMin((exports) => {
2
+ var require__createStandardSchema = /* @__PURE__ */ __commonJSMin(((exports) => {
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports._createStandardSchema = void 0;
5
5
  const _createStandardSchema = (fn) => Object.assign(fn, { "~standard": {
@@ -16,11 +16,11 @@ var require__createStandardSchema = __commonJSMin((exports) => {
16
16
  } });
17
17
  exports._createStandardSchema = _createStandardSchema;
18
18
  var PathParserState;
19
- (function(PathParserState$1) {
20
- PathParserState$1[PathParserState$1["Start"] = 0] = "Start";
21
- PathParserState$1[PathParserState$1["Property"] = 1] = "Property";
22
- PathParserState$1[PathParserState$1["StringKey"] = 2] = "StringKey";
23
- PathParserState$1[PathParserState$1["NumberKey"] = 3] = "NumberKey";
19
+ (function(PathParserState) {
20
+ PathParserState[PathParserState["Start"] = 0] = "Start";
21
+ PathParserState[PathParserState["Property"] = 1] = "Property";
22
+ PathParserState[PathParserState["StringKey"] = 2] = "StringKey";
23
+ PathParserState[PathParserState["NumberKey"] = 3] = "NumberKey";
24
24
  })(PathParserState || (PathParserState = {}));
25
25
  const typiaPathToStandardSchemaPath = (path) => {
26
26
  if (!path.startsWith("$input")) throw new Error(`Invalid path: ${JSON.stringify(path)}`);
@@ -69,6 +69,6 @@ var require__createStandardSchema = __commonJSMin((exports) => {
69
69
  if (state !== PathParserState.Start) throw new Error(`Failed to parse path: ${JSON.stringify(path)}`);
70
70
  return segments;
71
71
  };
72
- });
72
+ }));
73
73
  export default require__createStandardSchema();
74
74
  export { require__createStandardSchema };
@@ -1,5 +1,5 @@
1
1
  import { __commonJSMin } from "../../../../../../../_virtual/rolldown_runtime.mjs";
2
- var require__validateReport = __commonJSMin((exports) => {
2
+ var require__validateReport = /* @__PURE__ */ __commonJSMin(((exports) => {
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports._validateReport = void 0;
5
5
  const _validateReport = (array) => {
@@ -22,6 +22,6 @@ var require__validateReport = __commonJSMin((exports) => {
22
22
  };
23
23
  };
24
24
  exports._validateReport = _validateReport;
25
- });
25
+ }));
26
26
  export default require__validateReport();
27
27
  export { require__validateReport };
@@ -7,8 +7,7 @@ const countRuleViolationsByLimit = (rule, limitType) => {
7
7
  };
8
8
  const categorizeRulesForSelection = (violationInfos, limitCount, limitType) => {
9
9
  return violationInfos.reduce((accumulator, rule) => {
10
- const totalCount = countRuleViolationsByLimit(rule, limitType);
11
- if (totalCount <= limitCount) accumulator.fullSelectable.push(rule);
10
+ if (countRuleViolationsByLimit(rule, limitType) <= limitCount) accumulator.fullSelectable.push(rule);
12
11
  else accumulator.partialSelectable.push(rule);
13
12
  return accumulator;
14
13
  }, {
@@ -47,16 +46,13 @@ function decideOptimalRule(violationInfos, config) {
47
46
  const { limit: { count: limitCount, type: limitType }, partialSelection: allowPartialSelection } = config;
48
47
  if (violationInfos.length === 0) return { success: false };
49
48
  const partitionedRules = categorizeRulesForSelection(violationInfos, limitCount, limitType);
50
- if (partitionedRules.fullSelectable.length > 0) {
51
- const bestRule = sortRulesByPriority(partitionedRules.fullSelectable, limitType)[0];
52
- return {
53
- selection: {
54
- ruleId: bestRule.ruleId,
55
- type: "full"
56
- },
57
- success: true
58
- };
59
- }
49
+ if (partitionedRules.fullSelectable.length > 0) return {
50
+ selection: {
51
+ ruleId: sortRulesByPriority(partitionedRules.fullSelectable, limitType)[0].ruleId,
52
+ type: "full"
53
+ },
54
+ success: true
55
+ };
60
56
  if (!allowPartialSelection) return { success: false };
61
57
  if (partitionedRules.partialSelectable.length === 0) return { success: false };
62
58
  const bestPartialSelectableRule = sortRulesByPriority(partitionedRules.partialSelectable, limitType)[0];
@@ -107,12 +103,10 @@ function selectRuleToCorrect(suppressions, eslintConfig, config) {
107
103
  throw new Error(`The ${limitTypeLabel} limit must be greater than 0.`);
108
104
  }
109
105
  const ruleBasedSuppression = toRuleBasedSuppression(suppressions);
110
- const violations = Object.entries(ruleBasedSuppression).map(([ruleId, violations$1]) => ({
106
+ return decideOptimalRule(filterViolations(Object.entries(ruleBasedSuppression).map(([ruleId, violations]) => ({
111
107
  isFixable: isRuleFixable(eslintConfig, ruleId),
112
108
  ruleId,
113
- violations: violations$1
114
- }));
115
- const filteredViolations = filterViolations(violations, config);
116
- return decideOptimalRule(filteredViolations, config);
109
+ violations
110
+ })), config), config);
117
111
  }
118
112
  export { selectRuleToCorrect };
package/dist/package.mjs CHANGED
@@ -1,4 +1,4 @@
1
1
  var name = "@sushichan044/eslint-todo";
2
- var version = "0.2.5";
2
+ var version = "0.3.0";
3
3
  var description = "A simple tool to gradually resolve a large number of ESLint violations.";
4
4
  export { description, name, version };
package/dist/path.d.mts CHANGED
@@ -9,8 +9,5 @@ type TodoFilePath = {
9
9
  */
10
10
  relative: string;
11
11
  };
12
- /**
13
- * Resolve the absolute and relative path of the todo file.
14
- */
15
12
  //#endregion
16
13
  export { TodoFilePath };
package/dist/path.mjs CHANGED
@@ -2,10 +2,9 @@ import { relative, resolve } from "pathe";
2
2
  const resolveTodoModulePath = (config) => {
3
3
  const { root, todoFile } = config;
4
4
  const absolutePath = resolve(root, todoFile);
5
- const relativePath = relative(root, absolutePath);
6
5
  return {
7
6
  absolute: absolutePath,
8
- relative: relativePath
7
+ relative: relative(root, absolutePath)
9
8
  };
10
9
  };
11
10
  export { resolveTodoModulePath };
@@ -11,7 +11,7 @@ const TodoModuleSerializer = {
11
11
  }
12
12
  };
13
13
  const serializeTodoModule = (eslintTodo) => {
14
- const js = [
14
+ const module_ = parseModule([
15
15
  "/* eslint-disable */",
16
16
  "/**",
17
17
  " * Auto generated file by eslint-todo. DO NOT EDIT MANUALLY.",
@@ -20,8 +20,7 @@ const serializeTodoModule = (eslintTodo) => {
20
20
  "/* prettier-ignore */",
21
21
  "// biome-ignore format: this is an auto-generated file",
22
22
  "export default {};"
23
- ].join("\n");
24
- const module_ = parseModule(js);
23
+ ].join("\n"));
25
24
  module_.exports.default = eslintTodo;
26
25
  const { code: jsCode } = generateCode(module_, { format: {
27
26
  objectCurlySpacing: true,
@@ -2,13 +2,5 @@ import { ESLint } from "eslint";
2
2
 
3
3
  //#region src/todofile/index.d.ts
4
4
  type TodoModuleLike = Record<string, unknown>;
5
- /**
6
- * Interface representing a handler for managing different versions of a todo module.
7
- *
8
- * @template CURRENT - The current version of the todo module.
9
- * @template NEXT - The next version of the todo module, defaults to `TodoModuleLike`.
10
- *
11
- * @package
12
- */
13
5
  //#endregion
14
6
  export { TodoModuleLike };
@@ -1,11 +1,11 @@
1
1
  import { __toESM } from "../_virtual/rolldown_runtime.mjs";
2
- import { require__accessExpressionAsString } from "../node_modules/.pnpm/typia@9.6.0_typescript@5.8.3/node_modules/typia/lib/internal/_accessExpressionAsString.mjs";
3
- import { require__validateReport } from "../node_modules/.pnpm/typia@9.6.0_typescript@5.8.3/node_modules/typia/lib/internal/_validateReport.mjs";
2
+ import { require__accessExpressionAsString } from "../node_modules/.pnpm/typia@11.0.0_typescript@5.9.3/node_modules/typia/lib/internal/_accessExpressionAsString.mjs";
3
+ import { require__validateReport } from "../node_modules/.pnpm/typia@11.0.0_typescript@5.9.3/node_modules/typia/lib/internal/_validateReport.mjs";
4
4
  import { isNonEmptyString } from "../utils/string.mjs";
5
5
  import { TodoModuleV2Handler } from "./v2.mjs";
6
6
  import { relative } from "pathe";
7
- var import__accessExpressionAsString = __toESM(require__accessExpressionAsString(), 1);
8
- var import__validateReport = __toESM(require__validateReport(), 1);
7
+ var import__accessExpressionAsString = /* @__PURE__ */ __toESM(require__accessExpressionAsString());
8
+ var import__validateReport = /* @__PURE__ */ __toESM(require__validateReport());
9
9
  const TodoModuleV1Handler = {
10
10
  version: 1,
11
11
  buildTodoFromLintResults(lintResult, config) {
@@ -38,8 +38,7 @@ const TodoModuleV1Handler = {
38
38
  });
39
39
  const _io1 = (input, _exceptionable = true) => "boolean" === typeof input.autoFix && Array.isArray(input.files) && input.files.every((elem, _index1) => "string" === typeof elem) && (2 === Object.keys(input).length || Object.keys(input).every((key) => {
40
40
  if (["autoFix", "files"].some((prop) => key === prop)) return true;
41
- const value = input[key];
42
- if (void 0 === value) return true;
41
+ if (void 0 === input[key]) return true;
43
42
  return false;
44
43
  }));
45
44
  const _vo0 = (input, _path, _exceptionable = true) => [false === _exceptionable || Object.keys(input).map((key) => {
@@ -1,3 +1,5 @@
1
+ import "./index.mjs";
2
+
1
3
  //#region src/todofile/v2.d.ts
2
4
  type ESLintTodoEntryV2 = {
3
5
  /**
@@ -1,10 +1,10 @@
1
1
  import { __toESM } from "../_virtual/rolldown_runtime.mjs";
2
- import { require__accessExpressionAsString } from "../node_modules/.pnpm/typia@9.6.0_typescript@5.8.3/node_modules/typia/lib/internal/_accessExpressionAsString.mjs";
3
- import { require__validateReport } from "../node_modules/.pnpm/typia@9.6.0_typescript@5.8.3/node_modules/typia/lib/internal/_validateReport.mjs";
2
+ import { require__accessExpressionAsString } from "../node_modules/.pnpm/typia@11.0.0_typescript@5.9.3/node_modules/typia/lib/internal/_accessExpressionAsString.mjs";
3
+ import { require__validateReport } from "../node_modules/.pnpm/typia@11.0.0_typescript@5.9.3/node_modules/typia/lib/internal/_validateReport.mjs";
4
4
  import { isNonEmptyString } from "../utils/string.mjs";
5
5
  import { relative } from "pathe";
6
- var import__accessExpressionAsString = __toESM(require__accessExpressionAsString(), 1);
7
- var import__validateReport = __toESM(require__validateReport(), 1);
6
+ var import__accessExpressionAsString = /* @__PURE__ */ __toESM(require__accessExpressionAsString());
7
+ var import__validateReport = /* @__PURE__ */ __toESM(require__validateReport());
8
8
  const TodoModuleV2Handler = {
9
9
  version: 2,
10
10
  buildTodoFromLintResults(lintResult, config) {
@@ -36,14 +36,12 @@ const TodoModuleV2Handler = {
36
36
  return (() => {
37
37
  const _io0 = (input, _exceptionable = true) => "object" === typeof input.meta && null !== input.meta && _io1(input.meta, _exceptionable) && "object" === typeof input.todo && null !== input.todo && false === Array.isArray(input.todo) && _io2(input.todo, _exceptionable) && (2 === Object.keys(input).length || Object.keys(input).every((key) => {
38
38
  if (["meta", "todo"].some((prop) => key === prop)) return true;
39
- const value = input[key];
40
- if (void 0 === value) return true;
39
+ if (void 0 === input[key]) return true;
41
40
  return false;
42
41
  }));
43
42
  const _io1 = (input, _exceptionable = true) => 2 === input.version && (1 === Object.keys(input).length || Object.keys(input).every((key) => {
44
43
  if (["version"].some((prop) => key === prop)) return true;
45
- const value = input[key];
46
- if (void 0 === value) return true;
44
+ if (void 0 === input[key]) return true;
47
45
  return false;
48
46
  }));
49
47
  const _io2 = (input, _exceptionable = true) => Object.keys(input).every((key) => {
@@ -53,8 +51,7 @@ const TodoModuleV2Handler = {
53
51
  });
54
52
  const _io3 = (input, _exceptionable = true) => "boolean" === typeof input.autoFix && "object" === typeof input.violations && null !== input.violations && false === Array.isArray(input.violations) && _io4(input.violations, _exceptionable) && (2 === Object.keys(input).length || Object.keys(input).every((key) => {
55
53
  if (["autoFix", "violations"].some((prop) => key === prop)) return true;
56
- const value = input[key];
57
- if (void 0 === value) return true;
54
+ if (void 0 === input[key]) return true;
58
55
  return false;
59
56
  }));
60
57
  const _io4 = (input, _exceptionable = true) => Object.keys(input).every((key) => {
@@ -6,7 +6,6 @@ const extractPathsByGlobs = (filePaths, patterns) => {
6
6
  };
7
7
  const pathMatchesGlobs = (filePath, patterns) => {
8
8
  if (patterns.length === 0) return true;
9
- const matchFunction = picomatch(patterns, { format: (input) => normalize(input) });
10
- return matchFunction(filePath);
9
+ return picomatch(patterns, { format: (input) => normalize(input) })(filePath);
11
10
  };
12
11
  export { extractPathsByGlobs };
@@ -1,13 +1,10 @@
1
- import { dirname, join } from "pathe";
2
1
  import * as Comlink from "comlink";
3
2
  import nodeEndPoint from "comlink/dist/esm/node-adapter.mjs";
4
- import { fileURLToPath } from "node:url";
5
3
  import { Worker } from "node:worker_threads";
6
4
  const launchRemoteESLintTodoCore = () => {
7
- const worker = new Worker(fileURLToPath(join(dirname(import.meta.url), "index.mjs")));
8
- const remoteCore = Comlink.wrap(nodeEndPoint(worker));
5
+ const worker = new Worker(new URL(import.meta.resolve("./index.mjs")));
9
6
  return {
10
- RemoteESLintTodoCore: remoteCore,
7
+ RemoteESLintTodoCore: Comlink.wrap(nodeEndPoint(worker)),
11
8
  terminate: async () => {
12
9
  await worker.terminate();
13
10
  }
package/package.json CHANGED
@@ -1,13 +1,20 @@
1
1
  {
2
2
  "name": "@sushichan044/eslint-todo",
3
- "version": "0.2.5",
3
+ "version": "0.3.0",
4
4
  "description": "A simple tool to gradually resolve a large number of ESLint violations.",
5
- "type": "module",
6
- "module": "./dist/index.mjs",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/sushichan044/eslint-todo.git"
8
+ },
9
+ "bin": {
10
+ "eslint-todo": "bin/eslint-todo.mjs"
11
+ },
7
12
  "files": [
8
- "dist",
9
- "config-schema.json"
13
+ "config-schema.json",
14
+ "dist"
10
15
  ],
16
+ "type": "module",
17
+ "module": "./dist/index.mjs",
11
18
  "exports": {
12
19
  ".": {
13
20
  "types": "./dist/index.d.mts",
@@ -21,102 +28,76 @@
21
28
  "types": "./dist/eslint/index.d.mts",
22
29
  "import": "./dist/eslint/index.mjs"
23
30
  },
24
- "./mcp": {
25
- "types": "./dist/mcp/index.d.mts",
26
- "import": "./dist/mcp/index.mjs"
27
- },
28
31
  "./package.json": "./package.json"
29
32
  },
30
- "bin": {
31
- "eslint-todo": "bin/eslint-todo.mjs"
32
- },
33
- "repository": {
34
- "type": "git",
35
- "url": "git+https://github.com/sushichan044/eslint-todo.git"
36
- },
37
33
  "publishConfig": {
38
34
  "access": "public",
39
35
  "registry": "https://registry.npmjs.org/"
40
36
  },
41
- "peerDependencies": {
42
- "eslint": "^8.57.0 || ^9.0.0"
43
- },
44
37
  "dependencies": {
45
- "@modelcontextprotocol/sdk": "1.17.0",
46
- "@sushichan044/eslint-config-array-resolver": "0.1.0",
47
- "@typescript-eslint/utils": "8.38.0",
48
- "bundle-require": "5.1.0",
38
+ "@sushichan044/eslint-config-array-resolver": "0.1.4",
49
39
  "comlink": "4.4.2",
50
40
  "consola": "3.4.2",
51
41
  "defu": "6.1.4",
52
- "empathic": "2.0.0",
53
- "gunshi": "0.27.0-alpha.10",
54
- "hookable": "5.5.3",
55
- "jiti": "2.5.1",
42
+ "gunshi": "0.27.5",
43
+ "hookable": "6.0.1",
44
+ "jiti": "2.6.1",
56
45
  "klona": "2.0.6",
57
- "magicast": "0.3.5",
58
- "mlly": "1.7.4",
46
+ "magicast": "0.5.1",
59
47
  "pathe": "2.0.3",
60
48
  "picomatch": "4.0.3",
61
- "tinyexec": "1.0.1",
62
- "zod": "3.25.76"
49
+ "tinyexec": "1.0.2"
63
50
  },
64
51
  "devDependencies": {
65
- "@arethetypeswrong/cli": "0.18.2",
66
- "@prettier/plugin-oxc": "0.0.4",
52
+ "@arethetypeswrong/core": "0.18.2",
67
53
  "@ryoppippi/unplugin-typia": "2.6.5",
68
54
  "@types/fs-extra": "11.0.4",
69
- "@types/node": "22.16.5",
70
- "@types/picomatch": "4.0.1",
71
- "@virtual-live-lab/eslint-config": "2.2.24",
72
- "@virtual-live-lab/prettier-config": "2.0.21",
55
+ "@types/node": "22.18.0",
56
+ "@types/picomatch": "4.0.2",
57
+ "@virtual-live-lab/eslint-config": "2.3.1",
58
+ "@virtual-live-lab/prettier-config": "2.0.22",
73
59
  "@virtual-live-lab/tsconfig": "2.1.21",
74
- "@vitest/coverage-v8": "3.2.4",
75
- "@vitest/eslint-plugin": "1.3.4",
76
- "eslint": "9.31.0",
77
- "eslint-flat-config-utils": "2.1.0",
78
- "eslint-plugin-import-access": "3.0.0",
79
- "eslint-plugin-unicorn": "60.0.0",
60
+ "@vitest/eslint-plugin": "1.6.4",
61
+ "eslint": "9.39.2",
62
+ "eslint-flat-config-utils": "2.1.4",
63
+ "eslint-plugin-import-access": "3.1.0",
64
+ "eslint-plugin-unicorn": "62.0.0",
80
65
  "eslint-typegen": "2.3.0",
81
- "fs-extra": "11.3.0",
82
- "fs-fixture": "2.8.1",
83
- "globals": "16.3.0",
84
- "pkg-pr-new": "0.0.54",
85
- "pnpm": "10.13.1",
86
- "prettier": "3.6.2",
87
- "publint": "0.3.12",
88
- "release-it": "19.0.4",
66
+ "fs-extra": "11.3.3",
67
+ "fs-fixture": "2.11.0",
68
+ "globals": "17.0.0",
69
+ "oxfmt": "0.21.0",
70
+ "pkg-pr-new": "0.0.62",
71
+ "pnpm": "10.27.0",
72
+ "publint": "0.3.16",
73
+ "release-it": "19.2.2",
89
74
  "release-it-pnpm": "4.6.6",
90
- "rolldown": "1.0.0-beta.29",
91
75
  "ts-patch": "3.3.0",
92
- "tsdown": "0.13.0",
93
- "typescript": "5.8.3",
94
- "typescript-eslint": "8.38.0",
95
- "typia": "9.6.0",
96
- "unplugin-unused": "0.5.1",
97
- "vite": "7.0.6",
98
- "vite-node": "3.2.4",
99
- "vitest": "3.2.4"
76
+ "tsdown": "0.18.4",
77
+ "typescript": "5.9.3",
78
+ "typescript-eslint": "8.51.0",
79
+ "typia": "11.0.0",
80
+ "unplugin-unused": "0.5.6",
81
+ "vite": "7.3.0",
82
+ "vite-node": "5.2.0",
83
+ "vitest": "4.0.16"
84
+ },
85
+ "peerDependencies": {
86
+ "eslint": "^8.57.0 || ^9.0.0"
100
87
  },
101
88
  "engines": {
102
- "node": "^20.0.0 || ^22.0.0 || ^23.0.0"
89
+ "node": "^20.12.0 || ^22.0.0 || >=24.0.0"
103
90
  },
104
91
  "scripts": {
105
- "build": "tsdown",
92
+ "build": "tsdown --config-loader unrun",
106
93
  "build:json-schema": "vite-node scripts/json-schema.ts",
107
- "dev": "unbuild --stub",
108
94
  "lint": "eslint --max-warnings 0 .",
109
- "format": "prettier --experimental-cli --write .",
110
- "format:ci": "prettier --experimental-cli --check .",
95
+ "format": "oxfmt",
96
+ "format:ci": "oxfmt --check",
97
+ "test": "vitest run",
111
98
  "typecheck": "tsc --noEmit",
112
- "test": "vitest",
113
- "test:run": "vitest run",
114
- "bench": "vitest bench",
115
- "bench:run": "vitest bench --run",
116
- "eslint:inspect": "eslint --inspect-config",
99
+ "eslint-config-inspector": "eslint --inspect-config",
117
100
  "pkg-pr-new": "pkg-pr-new publish --compact --comment=update --pnpm",
118
- "check": "pnpm run build && pnpm run lint && pnpm run format:ci && pnpm run typecheck && pnpm run test:run && pnpm run attw:check",
119
- "attw:check": "pnpm run build && pnpm pack && attw",
120
- "ai:prettier": "prettier --experimental-cli"
101
+ "check": "pnpm run build && pnpm run lint && pnpm run format:ci && pnpm run typecheck && pnpm run test"
121
102
  }
122
103
  }
@@ -1,22 +0,0 @@
1
- import { resolveFileConfig } from "../../config/resolve.mjs";
2
- import { logger } from "../logger.mjs";
3
- import { handleMCP } from "../handlers/mcp.mjs";
4
- import { commonArguments } from "./common-arguments.mjs";
5
- import { cwd } from "node:process";
6
- import { define } from "gunshi/definition";
7
- const mcpCmd = define({
8
- args: { ...commonArguments },
9
- name: "mcp",
10
- run: async (context) => {
11
- const isDirty = Object.values(context.explicit).includes(true);
12
- if (isDirty) logger.warn("Ignoring config file because config is passed via CLI flags.");
13
- const userCLIConfig = {
14
- root: context.values.root,
15
- todoFile: context.values.todoFile
16
- };
17
- const cliCwd = cwd();
18
- const userConfig = isDirty ? userCLIConfig : await resolveFileConfig(cliCwd);
19
- await handleMCP(cliCwd, userConfig);
20
- }
21
- });
22
- export { mcpCmd };
@@ -1,22 +0,0 @@
1
- import { configWithDefault } from "../../config/config.mjs";
2
- import { createESLintConfigSubset } from "../../lib/eslint.mjs";
3
- import { startMcpServerWithStdio } from "../../mcp/stdio.mjs";
4
- import { resolveFlatConfig } from "@sushichan044/eslint-config-array-resolver";
5
- const handleMCP = async (cwd, userConfig) => {
6
- const config = configWithDefault(userConfig);
7
- const eslintConfig = await resolveFlatConfig(config.root);
8
- const eslintConfigSubset = createESLintConfigSubset(eslintConfig);
9
- const stopMcpServer = await startMcpServerWithStdio({
10
- config,
11
- eslintConfig: eslintConfigSubset
12
- });
13
- process.on("SIGINT", () => {
14
- stopMcpServer().then(() => {
15
- process.exit(0);
16
- }).catch((error) => {
17
- console.error(error);
18
- process.exit(1);
19
- });
20
- });
21
- };
22
- export { handleMCP };
@@ -1,11 +0,0 @@
1
- import { Linter } from "eslint";
2
- import "@sushichan044/eslint-config-array-resolver";
3
-
4
- //#region src/lib/eslint.d.ts
5
- interface ESLintConfigSubset {
6
- rules: Record<string, {
7
- fixable: boolean;
8
- }>;
9
- }
10
- //#endregion
11
- export { ESLintConfigSubset };
@@ -1,8 +0,0 @@
1
- import { MCPServerContext } from "./types.mjs";
2
- import { SetupMcpServerOptions } from "./setup.mjs";
3
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
-
5
- //#region src/mcp/index.d.ts
6
- declare const ESLintTodoMcpServer: (context: MCPServerContext, options?: Partial<SetupMcpServerOptions>) => McpServer;
7
- //#endregion
8
- export { ESLintTodoMcpServer };
@@ -1,12 +0,0 @@
1
- import { name, version } from "../package.mjs";
2
- import { setupMcpServer } from "./setup.mjs";
3
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
- const ESLintTodoMcpServer = (context, options = {}) => {
5
- const server = new McpServer({
6
- name,
7
- version
8
- });
9
- setupMcpServer(server, context, options);
10
- return server;
11
- };
12
- export { ESLintTodoMcpServer };
@@ -1,11 +0,0 @@
1
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
-
3
- //#region src/mcp/setup.d.ts
4
- interface SetupMcpServerOptions {
5
- onError: (error: unknown) => void;
6
- }
7
- /**
8
- * @package
9
- */
10
- //#endregion
11
- export { SetupMcpServerOptions };
@@ -1,108 +0,0 @@
1
- import { ESLintTodoCore } from "../index.mjs";
2
- import { prepareAction } from "../action/index.mjs";
3
- import { deleteRuleAction } from "../action/delete-rule.mjs";
4
- import { selectRulesToFixAction } from "../action/select-rule.mjs";
5
- import { mergeConfig } from "../config/index.mjs";
6
- import { z } from "zod";
7
- const setupMcpServer = (server, context, { onError } = {}) => {
8
- onError ??= (error) => {
9
- console.error(error);
10
- };
11
- server.server.onerror = onError;
12
- server.tool("delete_suppression_with_limit", [
13
- "Delete suppression from ESLint suppressions json file with specific limit.",
14
- "",
15
- "Use this tool when you need to reduce ESLint suppressions while controlling the amount of diff reviewable.",
16
- "If you want to fix ESLint errors, please use `eslint --fix` instead.",
17
- "",
18
- "## Parameters",
19
- "You only specify the parameters you need for your work."
20
- ].join("\n"), {
21
- autoFixableOnly: z.boolean().optional().describe("Allow to select non auto-fixable rules"),
22
- excludedRules: z.array(z.string()).optional().default([]).describe("List of rules to exclude"),
23
- limitCount: z.number().optional().describe("Limit of suppression to delete"),
24
- limitType: z.enum(["file", "violation"]).optional().describe("Type of limit"),
25
- partialSelection: z.boolean().optional().describe("Allow to select partial suppressions of a rule")
26
- }, {
27
- destructiveHint: true,
28
- idempotentHint: false,
29
- openWorldHint: false,
30
- readOnlyHint: false,
31
- title: "Delete suppression with limit"
32
- }, async (parameters) => {
33
- try {
34
- const config = mergeConfig(context.config, { correct: {
35
- autoFixableOnly: parameters.autoFixableOnly,
36
- exclude: { rules: parameters.excludedRules },
37
- limit: {
38
- count: parameters.limitCount,
39
- type: parameters.limitType
40
- },
41
- partialSelection: parameters.partialSelection
42
- } });
43
- const core = new ESLintTodoCore(config);
44
- const todoModuleHasChanges = await core.todoModuleHasUncommittedChanges();
45
- if (todoModuleHasChanges) return {
46
- content: [{
47
- text: [
48
- "# Warning: The suppressions file has uncommitted changes",
49
- "You attempt to run this tool on a suppressions file that has uncommitted changes.",
50
- "This will cause unexpected diff, so we stopped the tool.",
51
- "",
52
- "## Suggested action",
53
- "1. Commit or stash these changes and try again. You should confirm with human reviewer.",
54
- "2. If you want to fix ESLint errors, please use `eslint --fix` instead."
55
- ].join("\n"),
56
- type: "text"
57
- }],
58
- isError: true
59
- };
60
- const selectRule = prepareAction(selectRulesToFixAction, {
61
- config,
62
- eslintConfig: context.eslintConfig
63
- });
64
- const selectionResult = await selectRule();
65
- if (!selectionResult.success) return { content: [{
66
- text: [
67
- "# No rules to fix",
68
- "Could not select rules to fix with given limit. Deletion from suppression json will not be performed.",
69
- "## Recommended action",
70
- "1. Check the eslint suppressions json file to ensure that the rule is suppressed.",
71
- "2. If the rule is suppressed, try a larger limit.",
72
- "3. If you can allow deleting partial suppressions of a rule, try to set `partialSelection` to `true`."
73
- ].join("\n"),
74
- type: "text"
75
- }] };
76
- const deleteRule = prepareAction(deleteRuleAction, {
77
- config: context.config,
78
- eslintConfig: context.eslintConfig
79
- });
80
- await deleteRule(selectionResult.selection);
81
- if (selectionResult.selection.type === "full") return { content: [{
82
- text: ["# Tool call succeed", `All suppressions of ${selectionResult.selection.ruleId} have been deleted.`].join("\n"),
83
- type: "text"
84
- }] };
85
- const deletedCount = Object.values(selectionResult.selection.violations).reduce((accumulator, current) => accumulator + current, 0);
86
- return { content: [{
87
- text: ["# Tool call succeed", `${deletedCount} suppressions of ${selectionResult.selection.ruleId} have been deleted.`].join("\n"),
88
- type: "text"
89
- }] };
90
- } catch (error) {
91
- console.error(error);
92
- return {
93
- content: [{
94
- text: [
95
- "# **Error Occurred**",
96
- "It looks like there was an error while communicating with the eslint-todo API.",
97
- "",
98
- "## Error Details",
99
- error instanceof Error ? error.message : String(error)
100
- ].join("\n"),
101
- type: "text"
102
- }],
103
- isError: true
104
- };
105
- }
106
- });
107
- };
108
- export { setupMcpServer };
@@ -1,7 +0,0 @@
1
- import { ESLintTodoMcpServer } from "./index.mjs";
2
- import { startStdioTransport } from "./transport/stdio.mjs";
3
- const startMcpServerWithStdio = async (context) => {
4
- const server = ESLintTodoMcpServer(context);
5
- return startStdioTransport(server);
6
- };
7
- export { startMcpServerWithStdio };
@@ -1,10 +0,0 @@
1
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
2
- const startStdioTransport = async (server) => {
3
- const transport = new StdioServerTransport();
4
- await server.connect(transport);
5
- return async () => {
6
- await server.close();
7
- await transport.close();
8
- };
9
- };
10
- export { startStdioTransport };
@@ -1,14 +0,0 @@
1
- import { Config } from "../config/config.mjs";
2
- import { ESLintConfigSubset } from "../lib/eslint.mjs";
3
-
4
- //#region src/mcp/types.d.ts
5
-
6
- /**
7
- * @package
8
- */
9
- interface MCPServerContext {
10
- config: Config;
11
- eslintConfig: ESLintConfigSubset;
12
- }
13
- //#endregion
14
- export { MCPServerContext };