@sushichan044/eslint-todo 0.0.1

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.
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ // @ts-check
3
+ import { run } from "../dist/cli.mjs";
4
+
5
+ run(process.argv).catch((error) => {
6
+ console.error(error);
7
+ process.exit(1);
8
+ });
package/dist/cli.d.mts ADDED
@@ -0,0 +1,3 @@
1
+ declare const run: (argv: string[]) => Promise<void>;
2
+
3
+ export { run };
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ declare const run: (argv: string[]) => Promise<void>;
2
+
3
+ export { run };
package/dist/cli.mjs ADDED
@@ -0,0 +1,45 @@
1
+ import { defineCommand, runMain } from 'citty';
2
+ import { generateESLintTodo } from './index.mjs';
3
+ import 'eslint';
4
+ import 'node:fs';
5
+ import 'node:fs/promises';
6
+ import 'node:path';
7
+ import 'magicast';
8
+ import './shared/eslint-todo.DYn5wjQX.mjs';
9
+ import 'defu';
10
+ import 'node:process';
11
+ import 'jiti';
12
+
13
+ const cli = defineCommand({
14
+ args: {
15
+ cwd: {
16
+ description: "Current working directory",
17
+ required: false,
18
+ type: "string",
19
+ valueHint: "path"
20
+ },
21
+ "todo-file": {
22
+ description: "ESLint todo file name",
23
+ required: false,
24
+ type: "string",
25
+ valueHint: "filename"
26
+ }
27
+ },
28
+ meta: {
29
+ description: "Generate ESLint todo file and temporally suppress ESLint errors!",
30
+ name: "@sushichan044/eslint-todo/cli",
31
+ version: "0.0.1"
32
+ },
33
+ async run({ args }) {
34
+ const options = {
35
+ cwd: args.cwd,
36
+ todoFile: args["todo-file"]
37
+ };
38
+ await generateESLintTodo(options);
39
+ }
40
+ });
41
+ const run = async (argv) => {
42
+ await runMain(cli, { rawArgs: argv });
43
+ };
44
+
45
+ export { run };
@@ -0,0 +1,6 @@
1
+ import { Linter } from 'eslint';
2
+ import { U as UserOptions } from './shared/eslint-todo.BijUMnSZ.mjs';
3
+
4
+ declare const eslintConfigTodo: (userOptions?: UserOptions) => Promise<Linter.Config[]>;
5
+
6
+ export { eslintConfigTodo };
@@ -0,0 +1,6 @@
1
+ import { Linter } from 'eslint';
2
+ import { U as UserOptions } from './shared/eslint-todo.BijUMnSZ.js';
3
+
4
+ declare const eslintConfigTodo: (userOptions?: UserOptions) => Promise<Linter.Config[]>;
5
+
6
+ export { eslintConfigTodo };
@@ -0,0 +1,44 @@
1
+ import { existsSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { o as optionsWithDefault, a as importDefault, e as escapeGlobCharacters } from './shared/eslint-todo.DYn5wjQX.mjs';
4
+ import 'defu';
5
+ import 'node:process';
6
+ import 'jiti';
7
+
8
+ const eslintConfigTodo = async (userOptions = {}) => {
9
+ const resolvedOptions = optionsWithDefault(userOptions);
10
+ const todoPath = path.resolve(resolvedOptions.cwd, resolvedOptions.todoFile);
11
+ if (!existsSync(todoPath)) {
12
+ return [];
13
+ }
14
+ const todoModule = await importDefault(todoPath);
15
+ const config = buildESLintFlatConfig({
16
+ todo: todoModule,
17
+ ...resolvedOptions
18
+ });
19
+ return config;
20
+ };
21
+ const buildESLintFlatConfig = (options) => {
22
+ const { cwd, todo, todoFile } = options;
23
+ const configs = [];
24
+ const relativeTodoFilePath = path.relative(cwd, path.resolve(cwd, todoFile));
25
+ configs.push({
26
+ files: [relativeTodoFilePath],
27
+ linterOptions: {
28
+ reportUnusedDisableDirectives: false
29
+ },
30
+ name: "@sushichan044/eslint-todo/setup"
31
+ });
32
+ Object.entries(todo).forEach(([ruleId, entry]) => {
33
+ configs.push({
34
+ files: entry.files.map((f) => escapeGlobCharacters(f)),
35
+ name: `@sushichan044/eslint-todo/todo/${ruleId}`,
36
+ rules: {
37
+ [ruleId]: "off"
38
+ }
39
+ });
40
+ });
41
+ return configs;
42
+ };
43
+
44
+ export { eslintConfigTodo };
@@ -0,0 +1,5 @@
1
+ import { U as UserOptions } from './shared/eslint-todo.BijUMnSZ.mjs';
2
+
3
+ declare const generateESLintTodo: (userOptions: UserOptions) => Promise<void>;
4
+
5
+ export { generateESLintTodo };
@@ -0,0 +1,5 @@
1
+ import { U as UserOptions } from './shared/eslint-todo.BijUMnSZ.js';
2
+
3
+ declare const generateESLintTodo: (userOptions: UserOptions) => Promise<void>;
4
+
5
+ export { generateESLintTodo };
package/dist/index.mjs ADDED
@@ -0,0 +1,68 @@
1
+ import { ESLint } from 'eslint';
2
+ import { existsSync } from 'node:fs';
3
+ import { writeFile } from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import { parseModule, generateCode } from 'magicast';
6
+ import { o as optionsWithDefault, i as isNonEmptyString } from './shared/eslint-todo.DYn5wjQX.mjs';
7
+ import 'defu';
8
+ import 'node:process';
9
+ import 'jiti';
10
+
11
+ const generateESLintTodoModule = (eslintTodo) => {
12
+ const js = `/* eslint-disable */
13
+ /**
14
+ * Auto generated file by eslint-todo. DO NOT EDIT MANUALLY.
15
+ */
16
+
17
+ export default {};
18
+ `;
19
+ const mod = parseModule(js);
20
+ mod.exports["default"] = eslintTodo;
21
+ const { code: jsCode } = generateCode(mod, {
22
+ format: { objectCurlySpacing: true, tabWidth: 2 }
23
+ });
24
+ return `${jsCode}
25
+ `;
26
+ };
27
+
28
+ const resetTodoFile = async (todoFilePath) => {
29
+ if (!existsSync(todoFilePath)) {
30
+ return;
31
+ }
32
+ await writeFile(todoFilePath, generateESLintTodoModule({}));
33
+ };
34
+ const runESLintLinting = async (eslint, options) => eslint.lintFiles(path.resolve(options.cwd, "**/*"));
35
+ const aggregateESLintTodoByRuleId = (results, options) => {
36
+ return results.reduce((acc, lintResult) => {
37
+ for (const message of lintResult.messages) {
38
+ if (!isNonEmptyString(message.ruleId)) {
39
+ continue;
40
+ }
41
+ acc[message.ruleId] ??= {
42
+ autoFix: false,
43
+ files: []
44
+ };
45
+ if (Object.prototype.hasOwnProperty.call(acc, message.ruleId)) {
46
+ acc[message.ruleId].files.push(
47
+ path.relative(options.cwd, lintResult.filePath)
48
+ );
49
+ acc[message.ruleId].autoFix = message.fix != null;
50
+ }
51
+ }
52
+ return acc;
53
+ }, {});
54
+ };
55
+ const generateESLintTodo = async (userOptions) => {
56
+ const resolvedOptions = optionsWithDefault(userOptions);
57
+ const resolvedTodoPath = path.resolve(
58
+ resolvedOptions.cwd,
59
+ resolvedOptions.todoFile
60
+ );
61
+ await resetTodoFile(resolvedTodoPath);
62
+ const eslint = new ESLint();
63
+ const results = await runESLintLinting(eslint, resolvedOptions);
64
+ const todoByRuleId = aggregateESLintTodoByRuleId(results, resolvedOptions);
65
+ await writeFile(resolvedTodoPath, generateESLintTodoModule(todoByRuleId));
66
+ };
67
+
68
+ export { generateESLintTodo };
@@ -0,0 +1,16 @@
1
+ type Options = {
2
+ /**
3
+ * The file path to read and write the ESLint todo list.
4
+ * @default ".eslint-todo.js"
5
+ */
6
+ todoFile: string;
7
+ /**
8
+ * The current working directory.
9
+ *
10
+ * @default process.cwd()
11
+ */
12
+ cwd: string;
13
+ };
14
+ type UserOptions = Partial<Options>;
15
+
16
+ export type { UserOptions as U };
@@ -0,0 +1,16 @@
1
+ type Options = {
2
+ /**
3
+ * The file path to read and write the ESLint todo list.
4
+ * @default ".eslint-todo.js"
5
+ */
6
+ todoFile: string;
7
+ /**
8
+ * The current working directory.
9
+ *
10
+ * @default process.cwd()
11
+ */
12
+ cwd: string;
13
+ };
14
+ type UserOptions = Partial<Options>;
15
+
16
+ export type { UserOptions as U };
@@ -0,0 +1,24 @@
1
+ import { defu } from 'defu';
2
+ import { cwd } from 'node:process';
3
+ import { createJiti } from 'jiti';
4
+
5
+ const optionsWithDefault = (options = {}) => {
6
+ return defu(options, defaultOptions);
7
+ };
8
+ const defaultOptions = {
9
+ cwd: cwd(),
10
+ todoFile: ".eslint-todo.js"
11
+ };
12
+
13
+ const jiti = createJiti(import.meta.url);
14
+ const importDefault = async (url) => {
15
+ return await jiti.import(url, { default: true });
16
+ };
17
+ const escapeGlobCharacters = (glob) => {
18
+ return glob.replace(/\\/g, "\\\\").replace(/\*/g, "\\*").replace(/\?/g, "\\?").replace(/\[/g, "\\[").replace(/\]/g, "\\]").replace(/\{/g, "\\{").replace(/\}/g, "\\}").replace(/\)/g, "\\)").replace(/\(/g, "\\(").replace(/\!/g, "\\!");
19
+ };
20
+ const isNonEmptyString = (maybeString) => {
21
+ return maybeString != null && maybeString !== "";
22
+ };
23
+
24
+ export { importDefault as a, escapeGlobCharacters as e, isNonEmptyString as i, optionsWithDefault as o };
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@sushichan044/eslint-todo",
3
+ "repository": {
4
+ "type": "git",
5
+ "url": "https://github.com/sushichan044/eslint-todo.git"
6
+ },
7
+ "version": "0.0.1",
8
+ "type": "module",
9
+ "bin": {
10
+ "eslint-todo": "bin/eslint-todo.mjs"
11
+ },
12
+ "module": "./dist/index.mjs",
13
+ "exports": {
14
+ ".": {
15
+ "import": "./dist/index.mjs",
16
+ "types": "./dist/index.d.ts"
17
+ },
18
+ "./cli": {
19
+ "import": "./dist/cli.mjs",
20
+ "types": "./dist/cli.d.ts"
21
+ },
22
+ "./eslint": {
23
+ "import": "./dist/eslint.mjs",
24
+ "types": "./dist/eslint.d.ts"
25
+ }
26
+ },
27
+ "files": [
28
+ "dist"
29
+ ],
30
+ "peerDependencies": {
31
+ "eslint": "^8.57.0 || ^9.0.0"
32
+ },
33
+ "dependencies": {
34
+ "citty": "0.1.6",
35
+ "defu": "6.1.4",
36
+ "jiti": "2.4.2",
37
+ "magicast": "0.3.5"
38
+ },
39
+ "devDependencies": {
40
+ "@types/node": "22.13.0",
41
+ "@virtual-live-lab/eslint-config": "2.2.16",
42
+ "@virtual-live-lab/prettier-config": "2.0.15",
43
+ "@virtual-live-lab/tsconfig": "2.1.16",
44
+ "eslint": "9.19.0",
45
+ "prettier": "3.4.2",
46
+ "typescript": "5.7.3",
47
+ "typescript-eslint": "8.23.0",
48
+ "unbuild": "3.3.1",
49
+ "vitest": "3.0.4"
50
+ },
51
+ "engines": {
52
+ "node": "^20.0.0 || ^22.0.0 || ^23.0.0"
53
+ },
54
+ "scripts": {
55
+ "build": "unbuild",
56
+ "test": "vitest",
57
+ "eslint:inspect": "eslint --inspect-config"
58
+ }
59
+ }