eslint-config-efe13 1.1.4

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/CHANGELOG.md ADDED
@@ -0,0 +1,24 @@
1
+ # Changelog
2
+
3
+ Todas las notas de cambios para `eslint-config-efe13`.
4
+
5
+ ## [1.1.4] - 2026-09-09
6
+
7
+ - chore: Renombra el paquete a `eslint-config-efe13`.
8
+ - fix: Solicita confirmación antes de instalar dependencias cuando ya existe `eslint.config.mjs`.
9
+ - fix: Conserva el script `lint` existente en `package.json`.
10
+ - chore: Actualiza dependencias compatibles y corrige las vulnerabilidades reportadas por npm.
11
+ - test: Cubre la creación y conservación del script `lint`.
12
+
13
+ ## [1.1.0] - 2025-08-15
14
+
15
+ - feat: Agrega preset `backend-ts` (Node/TypeScript) con reglas: @typescript-eslint, import, n, promise, semistandard y Prettier integrados (Flat Config).
16
+ - chore: Añade `globals` como dependencia en presets `nextjs` y `vite` para alinear con `import globals from "globals"` en las plantillas.
17
+ - docs: Actualiza README para incluir `backend-ts` y nota sobre `tsconfig.json`.
18
+ - chore: Bump de versión a 1.1.0.
19
+
20
+ Crédito: reglas inspiradas en el trabajo de Goncy.
21
+
22
+ ---
23
+
24
+ Formato sugerido: Keep a Changelog (resumen breve por versión).
package/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # eslint-config-efe13
2
+
3
+ CLI para configurar rápidamente ESLint + Prettier (Flat Config) en proyectos Next.js, Vite o backend-ts (Node/TypeScript).
4
+
5
+ Reglas de configuración inspiradas en Goncy.
6
+
7
+
8
+
9
+ ## Uso rápido
10
+
11
+ Ejecuta el CLI en la raíz de tu proyecto con tu gestor preferido:
12
+
13
+ ```bash
14
+ npx eslint-config-efe13
15
+ # o
16
+ pnpm dlx eslint-config-efe13
17
+ # o
18
+ yarn dlx eslint-config-efe13
19
+ # o
20
+ bunx eslint-config-efe13
21
+ ```
22
+
23
+ El CLI intentará detectar el framework automáticamente. Si no puede detectarlo (o es ambiguo), te pedirá que selecciones uno (`nextjs` | `vite` | `backend-ts`) y hará la configuración automáticamente.
24
+
25
+ ### Nota para proyectos Vite
26
+
27
+ Si tu proyecto fue creado con Vite, elimina el archivo `eslint.config.js` que Vite genera por defecto. Este CLI creará `eslint.config.mjs` (Flat Config).
28
+
29
+ ### Nota para proyectos backend-ts
30
+
31
+ - Asegúrate de tener un `tsconfig.json` en la raíz del proyecto; el preset usa lint con información de tipos (`parserOptions.project`).
32
+ - El preset apunta a entornos Node.js y también habilita APIs de `serviceworker` (para soportar `fetch`, `Request`, `Response` en runtimes tipo Bun/Workers si fuese necesario).
33
+
34
+ ## Requisitos
35
+
36
+ - Node.js 18+.
37
+ - Un gestor de paquetes: npm, pnpm, yarn o bun.
38
+
39
+ ## ¿Qué hace?
40
+
41
+ - Detecta tu gestor de paquetes.
42
+ - Instala las dependencias necesarias.
43
+ - Genera `eslint.config.mjs` con configuración Flat + Prettier.
44
+ - Añade el script `"lint": "eslint ."` a `package.json` si existe y aún no define `lint`.
45
+
46
+ ## Lint
47
+
48
+ ```bash
49
+ npm run lint
50
+ ```
51
+ ## Licencia
52
+
53
+ ISC
54
+
package/bin/index.js ADDED
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env node
2
+ import chalk from "chalk";
3
+ import { execSync } from "child_process";
4
+ import fs from "fs";
5
+ import inquirer from "inquirer";
6
+ import ora from "ora";
7
+
8
+ import { depsByFramework } from "../src/deps.js";
9
+ import { detectFramework } from "../src/detect-framework.js";
10
+ import { detectPackageManager } from "../src/detect-package-manager.js";
11
+ import { ensureLintScript } from "../src/ensure-lint-script.js";
12
+ import { generateEslintConfig } from "../src/generate-config.js";
13
+
14
+ async function main() {
15
+ console.log(chalk.bold.blue("\n🚀 Configurador ESLint personalizado\n"));
16
+
17
+ const packageManager = detectPackageManager();
18
+ console.log(chalk.green(`Detectado gestor de paquetes: ${packageManager}`));
19
+
20
+ const detectedFramework = detectFramework();
21
+ let framework = detectedFramework;
22
+
23
+ if (framework) {
24
+ console.log(chalk.green(`Framework detectado: ${framework}`));
25
+ } else {
26
+ const response = await inquirer.prompt({
27
+ type: "list",
28
+ name: "framework",
29
+ message: "Selecciona el framework de tu proyecto",
30
+ choices: ["nextjs", { name: "react-ts + vite", value: "vite" }, "backend-ts"],
31
+ default: "nextjs",
32
+ });
33
+ framework = response.framework;
34
+ }
35
+
36
+ // Crear archivo eslint.config.mjs (con confirmación si ya existe)
37
+ const configPath = "eslint.config.mjs";
38
+ const configExists = fs.existsSync(configPath);
39
+
40
+ if (configExists) {
41
+ const { overwrite } = await inquirer.prompt({
42
+ type: "confirm",
43
+ name: "overwrite",
44
+ message: `Ya existe ${configPath}. ¿Sobreescribir?`,
45
+ default: false,
46
+ });
47
+
48
+ if (!overwrite) {
49
+ console.log(chalk.yellow(`Se mantuvo el ${configPath} existente.`));
50
+ return;
51
+ }
52
+ }
53
+
54
+ const spinner = ora("Instalando dependencias...").start();
55
+
56
+ try {
57
+ const deps = depsByFramework[framework];
58
+ const installCmd =
59
+ {
60
+ npm: "npm install -D",
61
+ pnpm: "pnpm add -D",
62
+ bun: "bun add -d",
63
+ yarn: "yarn add -D",
64
+ }[packageManager] || "npm install -D";
65
+
66
+ execSync(`${installCmd} ${deps.join(" ")}`, { stdio: "inherit" });
67
+ spinner.succeed("Dependencias instaladas correctamente");
68
+ } catch {
69
+ spinner.fail("Error instalando dependencias");
70
+ process.exit(1);
71
+ }
72
+
73
+ try {
74
+ fs.writeFileSync(configPath, generateEslintConfig(framework));
75
+ console.log(
76
+ chalk.green(`Archivo ${configPath} ${configExists ? "sobreescrito" : "creado"} con éxito`),
77
+ );
78
+ } catch {
79
+ console.error(chalk.red(`Error creando el archivo ${configPath}`));
80
+ process.exit(1);
81
+ }
82
+
83
+ // Añadir script lint a package.json
84
+ try {
85
+ const pkgPath = "package.json";
86
+ if (!fs.existsSync(pkgPath)) {
87
+ console.warn(chalk.yellow("No se encontró package.json, no se agregó script lint."));
88
+ } else {
89
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
90
+
91
+ if (ensureLintScript(pkg)) {
92
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
93
+ console.log(chalk.green("Script 'lint' agregado a package.json"));
94
+ } else {
95
+ console.log(chalk.yellow("Se mantuvo el script 'lint' existente."));
96
+ }
97
+ }
98
+ } catch {
99
+ console.warn(chalk.yellow("No se pudo modificar package.json para añadir el script lint."));
100
+ }
101
+
102
+ console.log(chalk.bold.blue("\n🎉 ¡Configuración completada con éxito!\n"));
103
+ }
104
+
105
+ main();
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "eslint-config-efe13",
3
+ "version": "1.1.4",
4
+ "type": "module",
5
+ "bin": {
6
+ "eslint-config-efe13": "bin/index.js"
7
+ },
8
+ "files": [
9
+ "bin/",
10
+ "src/",
11
+ "README.md",
12
+ "CHANGELOG.md"
13
+ ],
14
+ "scripts": {
15
+ "test": "vitest run",
16
+ "test:watch": "vitest"
17
+ },
18
+ "keywords": [
19
+ "eslint",
20
+ "prettier",
21
+ "nextjs",
22
+ "vite",
23
+ "backend",
24
+ "backend-ts",
25
+ "node",
26
+ "typescript",
27
+ "config",
28
+ "cli"
29
+ ],
30
+ "author": "efe13dev",
31
+ "license": "ISC",
32
+ "description": "Configuración de ESLint + Prettier inspirada en Goncy con un CLI para proyectos Next.js, Vite y backend-ts (Node/TypeScript).",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/efe13dev/eslint-config-efe.git"
36
+ },
37
+ "bugs": {
38
+ "url": "https://github.com/efe13dev/eslint-config-efe/issues"
39
+ },
40
+ "homepage": "https://github.com/efe13dev/eslint-config-efe#readme",
41
+ "dependencies": {
42
+ "chalk": "^5.6.2",
43
+ "inquirer": "^9.3.8",
44
+ "ora": "^6.3.1"
45
+ },
46
+ "engines": {
47
+ "node": ">=18"
48
+ },
49
+ "devDependencies": {
50
+ "vitest": "^4.1.11"
51
+ }
52
+ }
package/src/deps.js ADDED
@@ -0,0 +1,50 @@
1
+ export const depsByFramework = {
2
+ nextjs: [
3
+ "eslint",
4
+ "@eslint/compat",
5
+ "@next/eslint-plugin-next",
6
+ "eslint-config-next",
7
+ "eslint-config-prettier",
8
+ "eslint-plugin-import",
9
+ "eslint-plugin-jsx-a11y",
10
+ "eslint-plugin-prettier",
11
+ "eslint-plugin-react",
12
+ "eslint-plugin-react-compiler",
13
+ "eslint-plugin-react-hooks",
14
+ "prettier",
15
+ "prettier-plugin-tailwindcss",
16
+ "typescript",
17
+ "typescript-eslint",
18
+ "globals",
19
+ ],
20
+ vite: [
21
+ "eslint",
22
+ "@eslint/compat",
23
+ "eslint-config-prettier",
24
+ "eslint-plugin-import",
25
+ "eslint-plugin-jsx-a11y",
26
+ "eslint-plugin-prettier",
27
+ "eslint-plugin-react",
28
+ "eslint-plugin-react-hooks",
29
+ "prettier",
30
+ "prettier-plugin-tailwindcss",
31
+ "typescript",
32
+ "typescript-eslint",
33
+ "globals",
34
+ ],
35
+ "backend-ts": [
36
+ "eslint",
37
+ "@eslint/compat",
38
+ "@typescript-eslint/eslint-plugin",
39
+ "@typescript-eslint/parser",
40
+ "eslint-config-prettier",
41
+ "eslint-config-semistandard",
42
+ "eslint-plugin-import",
43
+ "eslint-plugin-n",
44
+ "eslint-plugin-prettier",
45
+ "eslint-plugin-promise",
46
+ "globals",
47
+ "prettier",
48
+ "typescript",
49
+ ],
50
+ };
@@ -0,0 +1,66 @@
1
+ import fs from "fs";
2
+
3
+ function readPackageJson(cwd = process.cwd()) {
4
+ const pkgPath = `${cwd}/package.json`;
5
+
6
+ if (!fs.existsSync(pkgPath)) return null;
7
+
8
+ try {
9
+ return JSON.parse(fs.readFileSync(pkgPath, "utf8"));
10
+ } catch {
11
+ return null;
12
+ }
13
+ }
14
+
15
+ /**
16
+ * Detecta el framework del proyecto a partir de dependencias y archivos de configuración.
17
+ * Retorna "nextjs" | "vite" | "backend-ts" | null.
18
+ */
19
+ export function detectFramework(cwd = process.cwd()) {
20
+ const pkg = readPackageJson(cwd);
21
+ const allDeps = {
22
+ ...(pkg?.dependencies || {}),
23
+ ...(pkg?.devDependencies || {}),
24
+ };
25
+
26
+ const hasDep = (name) => Boolean(allDeps[name]);
27
+
28
+ const hasNextConfig =
29
+ fs.existsSync(`${cwd}/next.config.js`) ||
30
+ fs.existsSync(`${cwd}/next.config.mjs`) ||
31
+ fs.existsSync(`${cwd}/next.config.ts`);
32
+
33
+ const hasViteConfig =
34
+ fs.existsSync(`${cwd}/vite.config.js`) ||
35
+ fs.existsSync(`${cwd}/vite.config.mjs`) ||
36
+ fs.existsSync(`${cwd}/vite.config.ts`);
37
+
38
+ const hasTsconfig = fs.existsSync(`${cwd}/tsconfig.json`);
39
+
40
+ const candidates = new Set();
41
+
42
+ if (hasDep("next") || hasNextConfig) candidates.add("nextjs");
43
+
44
+ if (
45
+ hasDep("vite") ||
46
+ hasViteConfig ||
47
+ hasDep("@vitejs/plugin-react") ||
48
+ hasDep("@vitejs/plugin-react-swc")
49
+ ) {
50
+ candidates.add("vite");
51
+ }
52
+
53
+ if (
54
+ hasTsconfig &&
55
+ (hasDep("typescript") || hasDep("@types/node") || hasDep("ts-node") || hasDep("tsx"))
56
+ ) {
57
+ candidates.add("backend-ts");
58
+ }
59
+
60
+ // Prioridad: nextjs > vite > backend-ts
61
+ if (candidates.has("nextjs")) return "nextjs";
62
+ if (candidates.has("vite")) return "vite";
63
+ if (candidates.has("backend-ts")) return "backend-ts";
64
+
65
+ return null;
66
+ }
@@ -0,0 +1,21 @@
1
+ import fs from "fs";
2
+
3
+ /**
4
+ * Detecta el gestor de paquetes del proyecto.
5
+ * Primero busca lockfiles en el directorio actual,
6
+ * luego recurre a npm_config_user_agent como fallback.
7
+ */
8
+ export function detectPackageManager(cwd = process.cwd()) {
9
+ if (fs.existsSync(`${cwd}/bun.lockb`) || fs.existsSync(`${cwd}/bun.lock`)) return "bun";
10
+ if (fs.existsSync(`${cwd}/pnpm-lock.yaml`)) return "pnpm";
11
+ if (fs.existsSync(`${cwd}/yarn.lock`)) return "yarn";
12
+ if (fs.existsSync(`${cwd}/package-lock.json`)) return "npm";
13
+
14
+ // Fallback: user-agent del proceso que invocó el CLI
15
+ const userAgent = process.env.npm_config_user_agent || "";
16
+ if (userAgent.startsWith("pnpm")) return "pnpm";
17
+ if (userAgent.startsWith("bun")) return "bun";
18
+ if (userAgent.startsWith("yarn")) return "yarn";
19
+
20
+ return "npm";
21
+ }
@@ -0,0 +1,7 @@
1
+ export function ensureLintScript(pkg) {
2
+ pkg.scripts ||= {};
3
+ if (Object.hasOwn(pkg.scripts, "lint")) return false;
4
+
5
+ pkg.scripts.lint = "eslint .";
6
+ return true;
7
+ }
@@ -0,0 +1,405 @@
1
+ function generateNextjsConfig() {
2
+ return `import globals from "globals";
3
+ import tseslint from "typescript-eslint";
4
+ import eslintPluginPrettier from "eslint-plugin-prettier/recommended";
5
+ import eslintPluginImport from "eslint-plugin-import";
6
+ import { fixupPluginRules } from "@eslint/compat";
7
+ import nextPlugin from "@next/eslint-plugin-next";
8
+
9
+ export default [
10
+ // Ignorar carpetas
11
+ {
12
+ ignores: ["node_modules", ".next", "out", "coverage", ".idea"],
13
+ },
14
+
15
+ // Base: Next.js + TypeScript
16
+ ...tseslint.configs.recommended,
17
+ // Next.js reglas recomendadas (flat config)
18
+ {
19
+ plugins: { "@next/next": nextPlugin },
20
+ rules: { ...nextPlugin.configs["core-web-vitals"].rules },
21
+ },
22
+
23
+ // Reglas generales
24
+ {
25
+ rules: {
26
+ "padding-line-between-statements": [
27
+ "warn",
28
+ { blankLine: "always", prev: "*", next: ["return", "export"] },
29
+ { blankLine: "always", prev: ["const", "let", "var"], next: "*" },
30
+ { blankLine: "any", prev: ["const", "let", "var"], next: ["const", "let", "var"] },
31
+ ],
32
+ "no-console": ["warn", { allow: ["error"] }],
33
+ },
34
+ },
35
+
36
+ // TypeScript: ajustes
37
+ {
38
+ rules: {
39
+ "@typescript-eslint/ban-ts-comment": "off",
40
+ "@typescript-eslint/no-empty-function": "off",
41
+ "@typescript-eslint/no-explicit-any": "off",
42
+ "@typescript-eslint/no-inferrable-types": "off",
43
+ "@typescript-eslint/no-namespace": "off",
44
+ "@typescript-eslint/no-non-null-assertion": "off",
45
+ "@typescript-eslint/explicit-function-return-type": "off",
46
+ "@typescript-eslint/no-unused-vars": [
47
+ "warn",
48
+ {
49
+ args: "after-used",
50
+ argsIgnorePattern: "^_.*?$",
51
+ caughtErrorsIgnorePattern: "^_.*?$",
52
+ },
53
+ ],
54
+ },
55
+ },
56
+
57
+ // Imports
58
+ {
59
+ plugins: {
60
+ import: fixupPluginRules(eslintPluginImport),
61
+ },
62
+ rules: {
63
+ "import/order": [
64
+ "warn",
65
+ {
66
+ groups: [
67
+ "type",
68
+ "builtin",
69
+ "object",
70
+ "external",
71
+ "internal",
72
+ "parent",
73
+ "sibling",
74
+ "index",
75
+ ],
76
+ pathGroups: [
77
+ {
78
+ pattern: "@/*",
79
+ group: "external",
80
+ position: "after",
81
+ },
82
+ ],
83
+ "newlines-between": "always",
84
+ },
85
+ ],
86
+ },
87
+ },
88
+
89
+ // Prettier + Tailwind
90
+ eslintPluginPrettier,
91
+ {
92
+ rules: {
93
+ "prettier/prettier": [
94
+ "warn",
95
+ {
96
+ printWidth: 100,
97
+ trailingComma: "all",
98
+ tabWidth: 2,
99
+ semi: true,
100
+ singleQuote: false,
101
+ bracketSpacing: true,
102
+ arrowParens: "always",
103
+ endOfLine: "auto",
104
+ plugins: ["prettier-plugin-tailwindcss"],
105
+ },
106
+ ],
107
+ },
108
+ },
109
+
110
+ // Configuración global de entorno
111
+ {
112
+ languageOptions: {
113
+ globals: {
114
+ ...globals.browser,
115
+ ...globals.serviceworker,
116
+ ...globals.node,
117
+ },
118
+ },
119
+ },
120
+ ];
121
+ `;
122
+ }
123
+
124
+ function generateViteConfig() {
125
+ return `import globals from "globals";
126
+ import tseslint from "typescript-eslint";
127
+ import eslintPluginPrettier from "eslint-plugin-prettier/recommended";
128
+ import eslintPluginImport from "eslint-plugin-import";
129
+ import { fixupPluginRules } from "@eslint/compat";
130
+
131
+ export default [
132
+ // Ignorar carpetas
133
+ {
134
+ ignores: ["node_modules", "dist", "coverage", ".idea"],
135
+ },
136
+
137
+ // Base: TypeScript recomendado
138
+ ...tseslint.configs.recommended,
139
+
140
+ // Reglas generales
141
+ {
142
+ rules: {
143
+ "padding-line-between-statements": [
144
+ "warn",
145
+ { blankLine: "always", prev: "*", next: ["return", "export"] },
146
+ { blankLine: "always", prev: ["const", "let", "var"], next: "*" },
147
+ { blankLine: "any", prev: ["const", "let", "var"], next: ["const", "let", "var"] },
148
+ ],
149
+ "no-console": ["warn", { allow: ["error"] }],
150
+ },
151
+ },
152
+
153
+ // TypeScript: ajustes
154
+ {
155
+ rules: {
156
+ "@typescript-eslint/ban-ts-comment": "off",
157
+ "@typescript-eslint/no-empty-function": "off",
158
+ "@typescript-eslint/no-explicit-any": "off",
159
+ "@typescript-eslint/no-inferrable-types": "off",
160
+ "@typescript-eslint/no-namespace": "off",
161
+ "@typescript-eslint/no-non-null-assertion": "off",
162
+ "@typescript-eslint/explicit-function-return-type": "off",
163
+ "@typescript-eslint/no-unused-vars": [
164
+ "warn",
165
+ {
166
+ args: "after-used",
167
+ argsIgnorePattern: "^_.*?$",
168
+ caughtErrorsIgnorePattern: "^_.*?$",
169
+ },
170
+ ],
171
+ },
172
+ },
173
+
174
+ // Imports
175
+ {
176
+ plugins: {
177
+ import: fixupPluginRules(eslintPluginImport),
178
+ },
179
+ rules: {
180
+ "import/order": [
181
+ "warn",
182
+ {
183
+ groups: [
184
+ "type",
185
+ "builtin",
186
+ "object",
187
+ "external",
188
+ "internal",
189
+ "parent",
190
+ "sibling",
191
+ "index",
192
+ ],
193
+ pathGroups: [
194
+ {
195
+ pattern: "@/*",
196
+ group: "external",
197
+ position: "after",
198
+ },
199
+ ],
200
+ "newlines-between": "always",
201
+ },
202
+ ],
203
+ },
204
+ },
205
+
206
+ // Prettier + Tailwind
207
+ eslintPluginPrettier,
208
+ {
209
+ rules: {
210
+ "prettier/prettier": [
211
+ "warn",
212
+ {
213
+ printWidth: 100,
214
+ trailingComma: "all",
215
+ tabWidth: 2,
216
+ semi: true,
217
+ singleQuote: false,
218
+ bracketSpacing: true,
219
+ arrowParens: "always",
220
+ endOfLine: "auto",
221
+ plugins: ["prettier-plugin-tailwindcss"],
222
+ },
223
+ ],
224
+ },
225
+ },
226
+
227
+ // Configuración global de entorno
228
+ {
229
+ languageOptions: {
230
+ globals: {
231
+ ...globals.browser,
232
+ ...globals.serviceworker,
233
+ ...globals.node,
234
+ },
235
+ },
236
+ },
237
+ ];
238
+ `;
239
+ }
240
+
241
+ function generateBackendTsConfig() {
242
+ return `import { fixupPluginRules } from "@eslint/compat";
243
+ import tseslint from "@typescript-eslint/eslint-plugin";
244
+ import tsparser from "@typescript-eslint/parser";
245
+ import eslintConfigPrettier from "eslint-config-prettier";
246
+ import semistandard from "eslint-config-semistandard";
247
+ import importPlugin from "eslint-plugin-import";
248
+ import nPlugin from "eslint-plugin-n";
249
+ import prettierRecommended from "eslint-plugin-prettier/recommended";
250
+ import promisePlugin from "eslint-plugin-promise";
251
+ import globals from "globals";
252
+
253
+ export default [
254
+ {
255
+ ignores: ["node_modules", "dist", "coverage", ".idea"],
256
+ },
257
+ {
258
+ files: ["**/*.ts"],
259
+ languageOptions: {
260
+ parser: tsparser,
261
+ parserOptions: {
262
+ ecmaVersion: "latest",
263
+ sourceType: "module",
264
+ // Lint con información de tipos
265
+ project: ["./tsconfig.json"],
266
+ tsconfigRootDir: process.cwd(),
267
+ },
268
+ globals: {
269
+ ...globals.node,
270
+ ...globals.es2021,
271
+ ...globals.serviceworker, // fetch, Request, Response
272
+ },
273
+ },
274
+ plugins: {
275
+ "@typescript-eslint": tseslint,
276
+ import: fixupPluginRules(importPlugin),
277
+ n: nPlugin,
278
+ promise: promisePlugin,
279
+ },
280
+ rules: {
281
+ ...semistandard.rules,
282
+
283
+ // Adaptaciones para TS
284
+ "@typescript-eslint/ban-ts-comment": "off",
285
+ "@typescript-eslint/no-empty-function": "off",
286
+ "@typescript-eslint/no-explicit-any": "off",
287
+ "@typescript-eslint/no-inferrable-types": "off",
288
+ "@typescript-eslint/no-namespace": "off",
289
+ "@typescript-eslint/no-non-null-assertion": "off",
290
+ "@typescript-eslint/explicit-function-return-type": "off",
291
+ "@typescript-eslint/no-unused-vars": [
292
+ "warn",
293
+ {
294
+ args: "after-used",
295
+ argsIgnorePattern: "^_.*?$",
296
+ caughtErrorsIgnorePattern: "^_.*?$",
297
+ },
298
+ ],
299
+ // TS adicional
300
+ "@typescript-eslint/consistent-type-imports": ["warn", { prefer: "type-imports" }],
301
+ "@typescript-eslint/no-floating-promises": "error",
302
+ "@typescript-eslint/no-misused-promises": ["error", { checksVoidReturn: false }],
303
+
304
+ // Desactivar reglas de ESLint que chocan con TS
305
+ "no-unused-vars": "off",
306
+ "no-undef": "off",
307
+
308
+ // Estilo: líneas en blanco entre declaraciones
309
+ "padding-line-between-statements": [
310
+ "warn",
311
+ { blankLine: "always", prev: "*", next: ["return", "export"] },
312
+ { blankLine: "always", prev: ["const", "let", "var"], next: "*" },
313
+ { blankLine: "any", prev: ["const", "let", "var"], next: ["const", "let", "var"] },
314
+ ],
315
+
316
+ // Console: permitir solo errores
317
+ "no-console": ["warn", { allow: ["error"] }],
318
+
319
+ // Orden de imports
320
+ "import/order": [
321
+ "warn",
322
+ {
323
+ groups: [
324
+ "type",
325
+ "builtin",
326
+ "object",
327
+ "external",
328
+ "internal",
329
+ "parent",
330
+ "sibling",
331
+ "index",
332
+ ],
333
+ pathGroups: [
334
+ {
335
+ pattern: "@/*",
336
+ group: "external",
337
+ position: "after",
338
+ },
339
+ ],
340
+ "newlines-between": "always",
341
+ },
342
+ ],
343
+ "import/no-duplicates": "warn",
344
+ "import/newline-after-import": ["warn", { count: 1 }],
345
+ "import/no-extraneous-dependencies": [
346
+ "error",
347
+ {
348
+ devDependencies: [
349
+ "**/*.test.ts",
350
+ "**/*.spec.ts",
351
+ "drizzle.config.ts",
352
+ "eslint.config.mjs",
353
+ "bunfig.toml",
354
+ ],
355
+ },
356
+ ],
357
+
358
+ // Promesas
359
+ "promise/no-return-wrap": "error",
360
+ "promise/param-names": "error",
361
+
362
+ // Node
363
+ "n/no-missing-import": "off", // TS resuelve imports
364
+ "n/no-process-exit": "warn",
365
+ "n/shebang": "off",
366
+ "n/no-unsupported-features/es-syntax": "off",
367
+ },
368
+ },
369
+ // Prettier recomendado (añade la regla prettier/prettier)
370
+ prettierRecommended,
371
+ // Ajustes de Prettier del proyecto
372
+ {
373
+ rules: {
374
+ // Configuración de Prettier centralizada en ESLint
375
+ "prettier/prettier": [
376
+ "warn",
377
+ {
378
+ printWidth: 100,
379
+ trailingComma: "all",
380
+ tabWidth: 2,
381
+ semi: true,
382
+ singleQuote: false,
383
+ bracketSpacing: true,
384
+ arrowParens: "always",
385
+ endOfLine: "auto",
386
+ },
387
+ ],
388
+ },
389
+ },
390
+ // Desactivar reglas en conflicto con Prettier
391
+ eslintConfigPrettier,
392
+ ];
393
+ `;
394
+ }
395
+
396
+ /**
397
+ * Genera el contenido del archivo eslint.config.mjs para el framework dado.
398
+ * @param {"nextjs"|"vite"|"backend-ts"} framework
399
+ * @returns {string}
400
+ */
401
+ export function generateEslintConfig(framework) {
402
+ if (framework === "nextjs") return generateNextjsConfig();
403
+ if (framework === "backend-ts") return generateBackendTsConfig();
404
+ return generateViteConfig();
405
+ }