agentsclimarketplace

Linting

Skill 14BryanEspinoza/agent-stack/skills/linting

Reglas de ESLint y Prettier - formato consistente, flat config, integración con husky/lint-staged, CI/CDFrom its SKILL.md

Install
npx -y skills add 14BryanEspinoza/agent-stack --skill linting

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

12.7 KB, ~3.7k tokens by cl100k_base, as published. Nobody here has run it

Linting — ESLint & Prettier


1. Filosofía

  1. Consistencia sobre preferencias — El linter y formatter eliminan discusiones de estilo. Lo importante es que el código sea uniforme, no qué estilo se elija.
  2. Formato automatizado — Prettier formatea solo, sin configuración por equipo. ESLint se enfoca en calidad de código, no en estilo.
  3. Flat config (ESLint 9+) — Desde ESLint v9, el formato legacy (.eslintrc) está deprecado. Usar eslint.config.js con flat config.
  4. Pre-commit hookslint-staged + husky garantizan que solo pase código linted y formateado. Sin atajos.
  5. CI como cortafuegos — El CI también corre lint. Si pasa local pero falla en CI, hay un desajuste de configuración.

2. Versiones Mínimas

TecnologíaVersión Mínima
Node.js22+
ESLint9+
Prettier3+
@eslint/js9+
typescript-eslint8+
husky9+
lint-staged15+

3. Instalación

# ESLint + Prettier + integración
pnpm add -D eslint prettier eslint-config-prettier

# Husky + lint-staged (pre-commit hooks)
pnpm add -D husky lint-staged

# TypeScript (opcional)
pnpm add -D typescript-eslint @eslint/js typescript

Inicializar Husky

pnpm exec husky init
# Crea .husky/pre-commit — luego agregar: pnpm exec lint-staged

4. ESLint — Flat Config (eslint.config.js)

ESLint 9+ usa flat config por defecto. No crear .eslintrc.*.

Configuración básica (JavaScript/ESM)

// eslint.config.js
import js from "@eslint/js";

export default [
  js.configs.recommended,

  {
    rules: {
      "no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
      "no-console": ["warn", { allow: ["warn", "error"] }],
      "no-debugger": "error",
      "no-duplicate-imports": "error",
      "prefer-const": "error",
      "no-var": "error",
      eqeqeq: ["error", "always"],
      curly: ["error", "all"],
      "no-throw-literal": "error",
      "prefer-template": "warn",
    },
  },

  {
    ignores: [
      "dist/",
      "build/",
      "node_modules/",
      ".git/",
      "coverage/",
      "*.config.*",
    ],
  },
];

TypeScript

// eslint.config.js
import js from "@eslint/js";
import tseslint from "typescript-eslint";

export default tseslint.config(
  js.configs.recommended,
  ...tseslint.configs.recommended,
  ...tseslint.configs.stylistic,

  {
    rules: {
      "@typescript-eslint/no-unused-vars": [
        "warn",
        { argsIgnorePattern: "^_" },
      ],
      "@typescript-eslint/explicit-function-return-type": "off",
      "@typescript-eslint/no-explicit-any": "warn",
      "@typescript-eslint/consistent-type-imports": [
        "error",
        { prefer: "type-imports" },
      ],
    },
  },

  {
    ignores: [
      "dist/",
      "build/",
      "node_modules/",
      ".git/",
      "coverage/",
      "*.config.*",
      "*.d.ts",
    ],
  },
);

React + JSX

// eslint.config.js
import js from "@eslint/js";
import reactPlugin from "eslint-plugin-react";
import reactHooksPlugin from "eslint-plugin-react-hooks";

export default [
  js.configs.recommended,

  {
    plugins: {
      react: reactPlugin,
      "react-hooks": reactHooksPlugin,
    },
    settings: {
      react: { version: "detect" },
    },
    rules: {
      ...reactPlugin.configs.recommended.rules,
      ...reactHooksPlugin.configs.recommended.rules,

      "react/react-in-jsx-scope": "off",
      "react/jsx-uses-react": "off",
      "react/prop-types": "off",
      "react/jsx-no-target-blank": "error",
      "react/self-closing-comp": "error",
    },
  },

  {
    ignores: ["dist/", "build/", "node_modules/", ".git/", "coverage/"],
  },
];

Reglas recomendadas por categoría

Posibles errores

{
  rules: {
    "no-console": ["warn", { allow: ["warn", "error"] }],
    "no-debugger": "error",
    "no-duplicate-imports": "error",
    "no-constant-binary-expression": "error",
    "no-promise-executor-return": "error",
    "no-self-compare": "error",
    "no-template-curly-in-string": "error",
    "no-unmodified-loop-condition": "error",
    "no-unreachable-loop": "error",
    "require-atomic-updates": "error",
  },
}

Buenas prácticas

{
  rules: {
    "array-callback-return": "error",
    "block-scoped-var": "error",
    curly: ["error", "all"],
    "default-case-last": "error",
    eqeqeq: ["error", "always"],
    "no-eval": "error",
    "no-extend-native": "error",
    "no-implied-eval": "error",
    "no-iterator": "error",
    "no-lone-blocks": "error",
    "no-new-wrappers": "error",
    "no-proto": "error",
    "no-return-assign": "error",
    "no-script-url": "error",
    "no-throw-literal": "error",
    "no-unused-expressions": "error",
    "no-useless-concat": "error",
    "prefer-regex-literals": "error",
    "require-await": "warn",
    yoda: "error",
  },
}

Estilo

{
  rules: {
    "consistent-return": "error",
    "no-lonely-if": "error",
    "no-multi-assign": "error",
    "no-nested-ternary": "error",
    "no-unneeded-ternary": "error",
    "one-var": ["error", "never"],
    "prefer-const": "error",
    "prefer-destructuring": "warn",
    "prefer-object-spread": "error",
    "prefer-template": "warn",
    "sort-imports": ["warn", { ignoreDeclarationSort: true }],
  },
}

5. Prettier

.prettierrc

{
  "semi": true,
  "singleQuote": false,
  "tabWidth": 2,
  "trailingComma": "all",
  "printWidth": 80,
  "bracketSpacing": true,
  "arrowParens": "always",
  "endOfLine": "lf",
  "quoteProps": "as-needed"
}

Alternativa en eslint.config.js

import prettierConfig from "eslint-config-prettier";

export default [
  // ... otras configs
  prettierConfig, // Siempre al final para desactivar reglas conflictivas
];

Ignorar archivos (.prettierignore)

# .prettierignore
dist/
build/
node_modules/
.git/
coverage/
*.min.js
*.map
*.lock
*.svg
*.png
*.jpg
*.ico
CHANGELOG.md

Scripts en package.json

{
  "scripts": {
    "lint": "eslint .",
    "lint:fix": "eslint . --fix",
    "format": "prettier --write .",
    "format:check": "prettier --check ."
  }
}

6. Integración ESLint + Prettier

eslint-config-prettier (recomendado)

Desactiva todas las reglas de ESLint que entran en conflicto con Prettier. Se coloca al final del array en flat config.

// eslint.config.js
import js from "@eslint/js";
import prettierConfig from "eslint-config-prettier";

export default [
  js.configs.recommended,
  // ... otros plugins y reglas
  prettierConfig, // último — desactiva reglas de estilo conflictivas
];

eslint-plugin-prettier (no recomendado)

Ejecuta Prettier como regla de ESLint. Tiene problemas de rendimiento y puede duplicar errores. Preferir eslint-config-prettier + ejecutar Prettier por separado.

// ❌ No recomendado
import eslintPluginPrettier from "eslint-plugin-prettier";

export default [
  {
    plugins: { prettier: eslintPluginPrettier },
    rules: {
      "prettier/prettier": "error",
    },
  },
];

Flujo recomendado

1. ESLint detecta errores de calidad (no estilo)
2. Prettier formatea automáticamente (estilo)
3. eslint-config-prettier evita conflictos entre ambos
4. lint-staged ejecuta ambos en pre-commit

7. Husky + lint-staged (Pre-commit Hooks)

Instalación

pnpm add -D husky lint-staged
pnpm exec husky init

Configurar pre-commit hook

# .husky/pre-commit
pnpm exec lint-staged

Configuración en package.json

{
  "lint-staged": {
    "*.{js,ts,tsx,mjs,cjs}": ["eslint --fix", "prettier --write"],
    "*.{json,md,css,html,yaml,yml}": ["prettier --write"]
  }
}

Sin husky (git hooks nativos)

# .git/hooks/pre-commit
#!/bin/sh
pnpm exec lint-staged

8. CI/CD

Pipeline básico

name: Lint & Format
on: [push, pull_request]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: "pnpm"

      - run: pnpm install --frozen-lockfile
      - run: pnpm lint
      - run: pnpm format:check

Con múltiples versiones de Node

jobs:
  lint:
    strategy:
      matrix:
        node-version: [20, 22]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: "pnpm"
      - run: pnpm install --frozen-lockfile
      - run: pnpm lint

9. ESLint en Editores

VS Code (settings.json)

{
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit"
  },
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  "eslint.validate": [
    "javascript",
    "typescript",
    "javascriptreact",
    "typescriptreact"
  ]
}

Neovim / Vim (lazy.nvim)

{
  "nvimtools/none-ls.nvim",
  dependencies = { "nvim-lua/plenary.nvim" },
  opts = function()
    local null_ls = require("null-ls")
    return {
      sources = {
        null_ls.builtins.formatting.prettier,
        null_ls.builtins.diagnostics.eslint,
        null_ls.builtins.code_actions.eslint,
      },
    }
  end,
}

10. Linting para Otros Archivos

Markdown

pnpm add -D eslint-plugin-markdown
// eslint.config.js
import markdownPlugin from "eslint-plugin-markdown";

export default [
  ...markdownPlugin.configs.recommended,
  {
    files: ["**/*.md"],
    processor: "markdown/markdown",
  },
];

JSON

pnpm add -D prettier-plugin-packagejson
{
  "plugins": ["prettier-plugin-packagejson"]
}

CSS / SCSS

pnpm add -D stylelint stylelint-config-standard
// stylelint.config.js
export default {
  extends: ["stylelint-config-standard"],
  rules: {
    "selector-class-pattern": null,
  },
};

11. Troubleshooting

ESLint no encuentra la config

# Verificar que eslint.config.js existe en la raíz
ls eslint.config.js

# Verificar que no hay .eslintrc.* (legacy)
ls .eslintrc* 2>/dev/null || echo "No legacy config"

# ESLint 9+ ignora .eslintrc si existe eslint.config.js
rm .eslintrc* 2>/dev/null; echo "Legacy configs removed"

Conflicto entre ESLint y Prettier

# eslint-config-prettier desactiva reglas conflictivas
# Asegúrate de que prettierConfig está AL FINAL del array flat config

lint-staged no ejecuta

# Verificar hook
cat .husky/pre-commit

# Asegurar que husky está instalado
pnpm exec husky

# Ejecutar manualmente
pnpm exec lint-staged --verbose

ESLint lento

# Ignorar node_modules y dist
# Usar --cache
pnpm lint --cache

# En flat config, los ignores en objeto tienen más prioridad

Error: "ESLint couldn't find the config"

# Asegurar que eslint.config.js exporta un array
node -e "import('./eslint.config.js').then(m => console.log(Array.isArray(m.default)))"

12. Prohibiciones

  • NO usar .eslintrc.* legacy en proyectos nuevos (usar flat config eslint.config.js)
  • NO desactivar reglas sin comentario explicativo (// eslint-disable-next-line reason)
  • NO committear console.log — usar no-console: warn y revisar antes de commit
  • NO usar eslint-plugin-prettier — preferir eslint-config-prettier + Prettier separado
  • NO ignorar warnings de lint en PRs (configurar max-warnings: 0 en CI)
  • NO saltar hooks de pre-commit (git commit --no-verify solo en emergencias)
  • NO mezclar flat config con legacy config en el mismo proyecto
  • NO usar // eslint-disable-next-line sin especificar la regla exacta
  • NO tener reglas de estilo en ESLint que Prettier ya maneja
  • NO poner archivos autogenerados en lint (ignorar dist/, build/, .next/)
  • NO usar @babel/eslint-parser si usas TypeScript (usar @typescript-eslint/parser)
  • NO instalar ESLint globalmente (usar la versión local del proyecto)

13. Referencias

Nota: Para CI/CD, ver Deploy Nota: Para scripts en package.json, ver Package Manager Nota: Para control de versiones y hooks, ver Git Nota: Para JavaScript/TypeScript, ver JavaScript

Última actualización: 2026-07

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.