CommunityProgramación y desarrollogithub.com

Redocly/redocly-lint-rules

Implementa una regla de lint de Redocly CLI en el archivo redocly.yaml o en un plugin personalizado para una descripción OpenAPI, AsyncAPI o Arazzo. Úsalo cuando el usuario quiera aplicar una convención, solicite una regla configurable o una regla de plugin, depure una regla que nunca reporta o da falsos positivos, o migre reglas desde otro linter como Spectral.

¿Qué es redocly-lint-rules?

Esta habilidad guía la implementación de reglas de lint personalizadas en Redocly CLI, utilizando un enfoque escalonado. Primero, se recomienda usar reglas integradas de Redocly, que son las más fáciles de mantener. Si no es posible, se pasa a reglas configurables en el archivo `redocly.yaml` usando aserciones. Como último recurso, se escribe un plugin personalizado en JavaScript. La habilidad enfatiza la verificación meticulosa: cada regla debe probarse con un fixture que la active (violación) y otro que no (conformidad) para evitar falsos positivos. También cubre la migración desde otros linters como Spectral, traduciendo la efectiva reglas configuradas y manteniendo la severidad correspondiente. Es compatible con OpenAPI, AsyncAPI y Arazzo, y está diseñada para desarrolladores que necesitan aplicar convenciones de API de manera programática y confiable.

Compatible con✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Redocly/redocly-cli/tree/HEAD/.claude/skills/redocly-lint-rules

Installed? Explore more Programación y desarrollo skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Implementando una regla de lint de Redocly CLI

Convierte una verificación escrita en lenguaje natural ("cada esquema de arreglo debe declarar items") en una regla de lint de Redocly que funcione y esté probada.

La escalera. Redocly ofrece tres formas de realizar una verificación. La primera es la más barata de mantener.

  1. Regla integrada — una de las reglas integradas realiza la verificación.
  2. Regla configurable — una o más entradas rule/* en redocly.yaml realizan la verificación con aserciones.
  3. Plugin personalizado — código JavaScript que implementa tu propia regla con el patrón de visitante. Usa este escalón al final.

Realiza las verificaciones de una en una. Comienza cada verificación en el escalón 1. Baja un escalón solo cuando el escalón actual no pueda realizar la verificación. Toma toda la sintaxis de la documentación oficial o del recetario. Confía en la documentación, no en tu memoria. Usa sintaxis moderna, como ESM en lugar de CommonJS. Si el proyecto tiene su propio estilo, sigue el proyecto.

1. Triage

Para cada verificación, anota tres cosas: el nodo que examina, qué debe ser verdadero, y cómo se ve una violación. Haz el triaje de cada verificación por separado. Diferentes verificaciones pueden terminar en diferentes escalones.

Obtén los nombres de los nodos del comando inspect-node-types, no de la memoria. El árbol de tipos es diferente en cada especificación y cada versión. Los nombres que imprime son el subject.type de una regla configurable y las claves de visitante de un plugin.

para aprenderejecutar
el tipo en una ubicación--pointer='#/paths/~1orders'
cada nodo, o cada nodo de un tiposin bandera, o --type=Schema
qué tipos usa la descripción--summary
dónde puede estar un tipo--type=<Tipo> --parents
los ancestros de un nodo--pointer=<puntero> --parents

Las dos últimas filas dan a una regla su alcance. Cuando un tipo se encuentra debajo de más de un padre, la regla necesita una puerta where. Sin esa puerta, la regla también reporta las ramas que no deseas. El comando muestra la descripción frente a ti. No muestra todo lo que la especificación permite. Cuando el comando no imprime una rama, esa rama no está comprobada. No está ausente. El comando no acorta el paso 3. Te da nombres de tipos. No te dice si tus aserciones expresan la verificación.

Sube la escalera para cada verificación:

  • Busca en la lista de reglas integradas el concepto. Una barra inclinada final en una ruta da no-path-trailing-slash. Cuando la configuración ya extiende un conjunto de reglas que activa la regla integrada, díselo al usuario. No agregues la regla de nuevo. Usa la regla integrada cuando su descripción coincida con la verificación, incluso si reporta más que la regla que reemplazas. Una regla integrada suele ser una versión mejorada de la misma idea, por lo que sus hallazgos adicionales son la verificación hecha correctamente. Cuando escribes el comportamiento más específico a mano, intercambias una regla mantenida por código que debes mantener. Baja un escalón solo cuando la regla integrada verifique algo diferente. Reporta qué regla integrada tomaste y qué añade.
  • Asegúrate de que la regla integrada soporte las versiones de especificación que el proyecto lint. Algunas reglas integradas solo soportan una versión. no-invalid-media-type-examples soporta OpenAPI 3.x, por lo que deja una verificación de Swagger 2.0 sin aplicar. Redocly imprime Unused rules found in redocly.yaml cuando una regla habilitada no puede aplicarse a un documento. Corrige esa línea. No es ruido.
  • Prueba aserciones y una puerta where. Consulta "Reglas configurables" más abajo. Una verificación puede necesitar varias entradas rule/*, una para cada caso o ubicación. Eso sigue siendo mejor que un plugin.
  • Escribe un plugin solo cuando las reglas configurables no puedan expresar la verificación, incluso en combinación. Primero trabaja con los tres diales a continuación. Un plugin puede hacer cualquier verificación, pero es código. Añade complejidad, mantenimiento y sus propios errores.
  • Dile al usuario que abra un issue solo cuando ninguna regla configurable pueda cerrar una brecha real.

El triaje está completo cuando cada verificación tiene un escalón. Da una solución para cada verificación: el escalón más alto que funcione. Reporta solo aquello sobre lo que el usuario debe actuar: un desajuste entre una descripción y una implementación, una regla no comprobada, o una decisión que podría ir en otra dirección. Reporta en el chat. Nunca escribas un archivo de resumen. La configuración registra el resto, así que no narres el escalón de cada verificación.

Migrar desde otro linter

  • Migra el conjunto de reglas efectivo, no solo las reglas escritas en el archivo. Un extends, o una base heredada, activa más reglas con sus severidades predeterminadas. Cada una de esas reglas también es una verificación. Resuelve esa base y cuenta las reglas antes de empezar. Así sabrás el tamaño real del trabajo.
  • Toma cada verificación de dos lugares: la descripción de la regla y su implementación. Nunca la tomes de tu memoria del nombre de la regla. Cuando los dos discrepen, usa la descripción. La descripción dice lo que el autor quería, y la implementación puede tener un error. Dile al usuario sobre la diferencia.
  • Omite una regla con severidad off. No la migres, ni siquiera como entrada deshabilitada. Cuando las reglas habilitadas estén listas, lista cada regla omitida en una línea. Entonces el usuario puede decidir.
  • Para Spectral, lee primero la tabla de mapeo en la guía de migración. Muchas reglas principales de Spectral se asignan a una regla integrada. Una celda vacía significa que bajas en la escalera.
  • Cuando copies una función de la fuente, también copias sus errores en un host más estricto. Redocly detiene todo el documento cuando una regla lanza una excepción, pero el linter fuente puede detener solo una regla. Una coincidencia sin protección, como v.match(/…/)[0] en un valor que puede no coincidir, elimina todos los hallazgos en ese archivo. Añade una protección al código que copies. Luego haz lint de un documento que tenga la forma difícil.

2. Configurar

Escribe en el archivo redocly.yaml del usuario. Usa ese nombre exacto, sin punto inicial. Cuando el archivo exista, léelo primero y conserva el extends y las reglas existentes. Establece cada regla en error, a menos que el usuario pida otro nivel. Cuando migres, conserva la severidad de origen y elige el nivel de Redocly más cercano. Solo existen error, que falla la ejecución, warn y off, por lo que info y hint se convierten en warn. Referencia cada archivo que crees desde la configuración, y ejercítalo en la ejecución de lint. No dejes archivos muertos.

Una configuración sin extends no hereda nada — ni recommended, ni siquiera struct. La base predeterminada se aplica solo cuando no existe ningún archivo de configuración. Por lo tanto, un redocly.yaml ejecuta exactamente las reglas que nombra. El escalón de regla integrada existe solo cuando extends nombra un conjunto de reglas, o cuando la configuración lista cada regla integrada por sí misma. Con ninguna de las dos, un documento que infringe la especificación tres veces pasa el lint sin problemas.

Conecta cada regla. Un plugin en plugins: no hace nada cuando sus reglas están ausentes de rules:, y Redocly no da ninguna advertencia. Después de escribir la configuración, lista los IDs de regla que deben estar activos. Confirma que cada ID esté en rules: o en un bloque con alcance de especificación.

Cuando todas las reglas estén incluidas, compara tu lista con los conjuntos de reglas predefinidos: minimal, recommended, recommended-strict y spec.

  • Cuando tus reglas se acerquen a un conjunto de reglas, extiéndelo. Conserva solo las diferencias como anulaciones: otras severidades, reglas para desactivar, y verificaciones que el conjunto de reglas no contiene.
  • Un conjunto de reglas también activa reglas que el usuario no solicitó. Lee lo que añade y anula cada regla que contradiga o repita una regla que escribiste. Un conjunto de reglas que activa una verificación que la fuente establece en off es un error a corregir, no un beneficio.
  • Cuando las anulaciones sean tantas como las reglas, o más, conserva la lista simple y sin extends.

3. Verificar

Una regla no está comprobada hasta que una ejecución en vivo la haga reportar. Comprueba cada regla con npx redocly lint <archivo-api> en dos direcciones:

  • un fixture violador: la regla reporta, en la ubicación correcta;
  • un fixture conforme: la ejecución permanece silenciosa.

Un falso positivo es el fallo común, por lo que una regla que solo pasó el fixture violador no está comprobada. Escribe el fixture violador para separar esta regla de la regla que la acompaña: la regla que reemplazas o su vecina en la configuración. Dos errores necesitan esa separación:

  • Pon un valor falso en el fixture violador. Una regla que debe rechazar un description vacío debe reportar en description: ''. Cuando pones '' solo en el fixture conforme, no pruebas nada, porque una aserción de presencia lo acepta. La regla entonces parece correcta y la brecha permanece.
  • Una regla integrada que reemplaza dos verificaciones fuente necesita un fixture que rompa solo la segunda verificación. no-unsafe-markdown reporta <script>, pero nunca eval(. Un fixture que contiene ambas da crédito a la regla integrada por una verificación que no realiza.

Para mantener la salida limpia, pasa una configuración temporal pequeña con --config. Elimina esa configuración y los fixtures cuando termines. Cada fragmento que entregues debe ser correcto tal como está escrito: analiza como YAML y se comporta como afirmas.

Has terminado cuando cada verificación nombre un fixture violador que reportó y un fixture conforme que permaneció silencioso. Nombra esos fixtures en tu informe. Un conteo no es evidencia. Una ejecución limpia en los propios archivos del proyecto tampoco es evidencia: solo muestra que nada reporta allí, y eso es cierto tanto para una regla correcta como para una regla muerta. Cuando verifiques las reglas riesgosas y asumas las demás, la entrega no está comprobada. Dilo, y nombra cada regla no comprobada. Un fixture conforme solo prueba las formas que contiene. Una versión de especificación que no probaste, o una ubicación que --parents mostró y no ejercitaste, permanece sin probar. Repórtalo. Cuando una ejecución en vivo sea imposible, marca la regla como no verificada. No afirmes que funciona.

También has terminado cuando cada verificación solicitada esté en la configuración o en la lista omitida, y el proyecto contenga solo los archivos de configuración y plugin que creaste.

Reglas configurables

Documentación: reglas configurables. Ejemplos prácticos: recetario/reglas-configurables.

Una regla es una entrada bajo rules: con un nombre que comienza con rule/:

rules:
  rule/mi-verificacion:
    subject:
      type: Schema # un tipo de nodo de la lista de tipos de la documentación
      property: title # opcional
    assertions:
      defined: true
    where: [] # puerta opcional
    message: Texto de problema personalizado.
    severity: error

rules simple se aplica a cada documento que el proyecto lint. Mantén las reglas allí por defecto. Mueve una regla bajo una clave con alcance de especificación solo cuando la verificación necesite algo que exista en una versión de especificación, como nullable en OAS 3.0, o cuando el usuario lo solicite. Las claves son oas2Rules, oas3_0Rules, oas3_1Rules, oas3_2Rules, async2Rules, async3Rules, arazzo1Rules y overlay1Rules. Una regla dentro de una clave no se ejecuta para las otras versiones, por lo que una verificación que el proyecto necesita en dos versiones necesita una entrada que ambas versiones alcancen. En su lugar, delimita una regla de plugin dentro del plugin, en su mapa rules.

Qué prueba una aserción

Dos hechos causan la mayoría de los falsos positivos y la mayoría de las omisiones silenciosas.

Un valor ausente pasa. Casi todas las aserciones se cumplen cuando el valor que verifican está ausente. const: array en property: type coincide con un esquema tipado array, y también con cada esquema sin type. Por lo tanto, cuando una entrada where prueba un valor de propiedad, añade defined: true junto a la aserción de valor si la propiedad puede estar ausente.

Presencia no es valor. defined, required, requireAny, disallowed y mutuallyExclusive prueban si existe una clave. No dicen nada sobre el contenido, por lo que defined: true en description pasa para description: ''. Afirma el valor en su lugar: nonEmpty: true rechaza una cadena vacía, y const, enum y pattern prueban el contenido. Este es el defecto más frecuente en la práctica. Se ve correcto en la revisión, y solo un fixture violador que contenga '' lo muestra.

Dos consecuencias de estos hechos:

  • const: <valor> es también la forma de decir "este campo debe ser falso", porque la aserción se cumple para ese valor y para un campo ausente.
  • requireAny cuenta solo claves. "Al menos uno de estos campos, y no vacío" no tiene forma de aserción. Esa verificación es un caso real de plugin.

Qué inspecciona la aserción

  • property: nombre — el valor de ese campo en el nodo sujeto.
  • property: [nombre, url, email] — cada campo listado por separado. Cada campo que falla se convierte en su propio problema con su propio puntero JSON, como #/info/contact/nombre.
  • property ausente — las claves del nodo sujeto. Por ejemplo, subject: { type: Paths } con assertions: { notPattern: /.+\/$/ } se ejecuta en las cadenas de ruta mismas.

Apunta al sujeto, luego ponle una puerta

Tres diales apuntan una regla. Resuélvelos en este orden.

1. Sujeto: el nodo que posee lo que afirmas.

  • Una verificación sobre las claves que contiene un mapa apunta al tipo del mapa mismo. Los mapas de respuestas, encabezados, propiedades de esquema y rutas son cada uno su propio tipo. Por lo tanto, "este mapa debe contener esa clave" es un required en un sujeto. No busques en el padre.
  • Una verificación sobre un valor apunta al nodo que contiene el campo, más property.
  • type: any con un property verifica esa propiedad en todas partes donde aparezca.
  • Confirma el nombre del tipo con inspect-node-types, en un documento de la versión de especificación a la que apunta la regla. Un tipo con nombre puede existir en una versión y no en otra. HeadersMap es un tipo en OpenAPI 3. En OpenAPI 2, el mapa headers de la respuesta es anónimo y no tiene nombre de tipo, por lo que un sujeto HeadersMap bajo oas2Rules nunca reporta. Redocly advierte sobre un ID de regla no resuelto, pero no sobre un subject.type no resuelto, por lo que un tipo incorrecto te da una regla que nunca reporta.

...

[truncado para traducción]

2. Puerta: la condición que activa la regla.

Ninguna puerta significa que la regla se aplica a cada ocurrencia del tipo del sujeto. Una puerta con una entrada restringe el alcance.

where:
  - subject:
      type: PathItem
    assertions:
      defined: [get, post]

Esta puerta dice: "solo se aplica a sujetos cuyo padre es un PathItem que tiene get o post".

3. Mensaje y severidad.

El mensaje debe explicar el problema y, si es posible, cómo solucionarlo.

Plugins

Documentación: plugins.

Cuando las reglas configurables no sean suficientes, escribe un plugin. Un plugin exporta un objeto con un mapa rules:

export default {
  id: 'mi-plugin',
  rules: {
    'mi-verificacion': {
      // implementación de la regla
    }
  }
};

Un plugin puede acceder al árbol de nodos completo y al contexto del linter, lo que permite verificaciones complejas.

Siempre prefiere reglas configurables sobre un plugin.

Resumen de la escalera

  1. Regla integrada — la más simple, sin configuración adicional.
  2. Regla configurable — aserciones en redocly.yaml, sin código.
  3. Plugin personalizado — código JavaScript, solo cuando sea estrictamente necesario.

Cada escalón es más costoso de mantener que el anterior. Sube la escalera de manera eficiente.

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

Skills relacionados