Implementieren einer Redocly CLI Lint-Regel
Verwandeln Sie eine Prüfung in natürlicher Sprache („jedes Array-Schema muss items deklarieren“) in eine funktionierende und getestete Redocly-Lint-Regel.
Die Leiter. Redocly bietet drei Möglichkeiten, eine Prüfung durchzuführen. Die erste ist am günstigsten zu warten.
- Integrierte Regel — eine der integrierten Regeln führt die Prüfung durch.
- Konfigurierbare Regel — ein oder mehrere
rule/*-Einträge inredocly.yamlführen die Prüfung mit Assertions durch. - Benutzerdefiniertes Plugin — JavaScript-Code, der Ihre eigene Regel mit dem Visitor-Muster implementiert. Verwenden Sie diese Stufe zuletzt.
Führen Sie die Prüfungen einzeln durch. Beginnen Sie jede Prüfung auf Stufe 1. Gehen Sie nur eine Stufe tiefer, wenn die aktuelle Stufe die Prüfung nicht durchführen kann. Übernehmen Sie alle Syntax aus der offiziellen Dokumentation oder dem Cookbook. Vertrauen Sie der Dokumentation, nicht Ihrem Gedächtnis. Verwenden Sie moderne Syntax, wie ESM statt CommonJS. Wenn das Projekt einen eigenen Stil hat, folgen Sie diesem.
1. Triage
Notieren Sie für jede Prüfung drei Dinge: den Knoten, den sie betrachtet, was wahr sein muss und wie ein Verstoß aussieht. Führen Sie die Triage für jede Prüfung separat durch. Unterschiedliche Prüfungen können auf unterschiedlichen Stufen landen.
Ermitteln Sie Knotennamen mit dem Befehl inspect-node-types, nicht aus dem Gedächtnis.
Der Typenbaum ist in jeder Spezifikation und jeder Version unterschiedlich.
Die Namen, die er ausgibt, sind der subject.type einer konfigurierbaren Regel und die Visitor-Keys eines Plugins.
| um zu lernen | ausführen |
|---|---|
| den Typ an einer Stelle | --pointer='#/paths/~1orders' |
| jeden Knoten oder jeden Knoten eines Typs | kein Flag, oder --type=Schema |
| welche Typen die Beschreibung verwendet | --summary |
| wo ein Typ sitzen kann | --type=<Type> --parents |
| die Vorfahren eines Knotens | --pointer=<pointer> --parents |
Die letzten beiden Zeilen geben einer Regel ihren Gültigkeitsbereich.
Wenn ein Typ unter mehr als einem Elternteil sitzt, benötigt die Regel eine where-Begrenzung.
Ohne diese Begrenzung meldet die Regel auch die Zweige, die Sie nicht wollen.
Der Befehl zeigt die Beschreibung vor Ihnen an. Er zeigt nicht alles, was die Spezifikation erlaubt.
Wenn der Befehl keinen Zweig ausgibt, ist dieser Zweig nicht nachgewiesen. Er ist nicht abwesend.
Der Befehl verkürzt Schritt 3 nicht. Er gibt Ihnen Typnamen. Er sagt Ihnen nicht, ob Ihre Assertions die Prüfung ausdrücken.
Gehen Sie die Leiter für jede Prüfung durch:
- Durchsuchen Sie die Liste der integrierten Regeln nach dem Konzept.
Ein abschließender Schrägstrich in einem Pfad ergibt
no-path-trailing-slash. Wenn die Konfiguration bereits ein Regelset erweitert, das die integrierte Regel aktiviert, teilen Sie dies dem Benutzer mit. Fügen Sie die Regel nicht erneut hinzu. Verwenden Sie die integrierte Regel, wenn ihre Beschreibung mit der Prüfung übereinstimmt, selbst wenn sie mehr meldet als die Regel, die Sie ersetzen. Eine integrierte Regel ist normalerweise eine bessere Version derselben Idee, daher sind ihre zusätzlichen Funde die korrekt durchgeführte Prüfung. Wenn Sie das engere Verhalten von Hand schreiben, tauschen Sie eine gewartete Regel gegen Code ein, den Sie warten müssen. Gehen Sie nur eine Stufe tiefer, wenn die integrierte Regel etwas anderes prüft. Melden Sie, welche integrierte Regel Sie genommen haben und was sie hinzufügt. - Stellen Sie sicher, dass die integrierte Regel die Spezifikationsversionen unterstützt, die das Projekt lintet.
Einige integrierte Regeln unterstützen nur eine Version.
no-invalid-media-type-examplesunterstützt OpenAPI 3.x, sodass eine Swagger 2.0-Prüfung nicht erzwungen wird. Redocly gibtUnused rules found in redocly.yamlaus, wenn eine aktivierte Regel nicht auf ein Dokument angewendet werden kann. Korrigieren Sie diese Zeile. Es ist kein Rauschen. - Versuchen Sie es mit Assertions und einer
where-Begrenzung. Siehe „Konfigurierbare Regeln“ unten. Eine Prüfung kann mehrererule/*-Einträge benötigen, einen für jeden Fall oder Ort. Das ist immer noch besser als ein Plugin. - Schreiben Sie ein Plugin nur, wenn konfigurierbare Regeln die Prüfung nicht ausdrücken können, auch in Kombination. Arbeiten Sie zuerst die drei Stellschrauben unten durch. Ein Plugin kann jede Prüfung durchführen, aber es ist Code. Es fügt Komplexität, Wartungsaufwand und eigene Fehler hinzu.
- Fordern Sie den Benutzer auf, ein Issue zu melden, nur wenn keine konfigurierbare Regel eine echte Lücke schließen kann.
Die Triage ist abgeschlossen, wenn jede Prüfung eine Stufe hat. Geben Sie eine Lösung für jede Prüfung: die höchste Stufe, die funktioniert. Melden Sie nur, worauf der Benutzer reagieren muss: eine Diskrepanz zwischen einer Beschreibung und einer Implementierung, eine nicht nachgewiesene Regel oder eine Entscheidung, die auch anders getroffen werden könnte. Melden Sie im Chat. Schreiben Sie niemals eine Zusammenfassungsdatei. Die Konfiguration dokumentiert den Rest, daher erzählen Sie nicht die Stufe jeder Prüfung.
Migration von einem anderen Linter
- Migrieren Sie die effektive Regelsammlung, nicht nur die in der Datei geschriebenen Regeln.
Ein
extendsoder eine geerbte Basis aktiviert weitere Regeln mit ihren Standard-Schweregraden. Jede dieser Regeln ist ebenfalls eine Prüfung. Lösen Sie diese Basis auf und zählen Sie die Regeln, bevor Sie beginnen. Dann kennen Sie die wahre Größe der Aufgabe. - Übernehmen Sie jede Prüfung aus zwei Quellen: der Beschreibung der Regel und ihrer Implementierung. Übernehmen Sie sie niemals aus Ihrer Erinnerung an den Regelnamen. Wenn die beiden nicht übereinstimmen, verwenden Sie die Beschreibung. Die Beschreibung sagt, was der Autor wollte, und die Implementierung kann einen Fehler enthalten. Teilen Sie dem Benutzer den Unterschied mit.
- Überspringen Sie eine Regel mit dem Schweregrad
off. Migrieren Sie sie nicht, nicht einmal als deaktivierten Eintrag. Wenn die aktivierten Regeln erledigt sind, listen Sie jede übersprungene Regel in einer Zeile auf. Dann kann der Benutzer entscheiden. - Lesen Sie für Spectral zuerst die Zuordnungstabelle im Migrationsleitfaden. Viele Spectral-Kernregeln sind auf eine integrierte Regel abgebildet. Eine leere Zelle bedeutet, dass Sie die Leiter hinuntergehen.
- Wenn Sie eine Funktion aus der Quelle kopieren, kopieren Sie auch ihre Fehler in einen strengeren Host.
Redocly stoppt das gesamte Dokument, wenn eine Regel einen Fehler auslöst, aber der Quell-Linter kann nur eine Regel stoppen.
Ein ungeschützter Match, wie
v.match(/…/)[0]auf einen Wert, der nicht matchen kann, entfernt jeden Fund in dieser Datei. Fügen Sie dem kopierten Code eine Absicherung hinzu. Linten Sie dann ein Dokument, das die schwierige Form enthält.
2. Konfigurieren
Schreiben Sie in die redocly.yaml des Benutzers. Verwenden Sie genau diesen Namen, ohne führenden Punkt.
Wenn die Datei existiert, lesen Sie sie zuerst und behalten Sie die vorhandenen extends und Regeln bei.
Setzen Sie jede Regel auf error, es sei denn, der Benutzer fragt nach einer anderen Stufe.
Wenn Sie migrieren, behalten Sie den Quell-Schweregrad bei und wählen Sie die nächstgelegene Redocly-Stufe.
Es gibt nur error (schlägt den Lauf fehl), warn und off, daher werden info und hint zu warn.
Referenzieren Sie jede Datei, die Sie aus der Konfiguration erstellen, und führen Sie sie im Lint-Lauf aus. Hinterlassen Sie keine toten Dateien.
Eine Konfiguration ohne extends erbt nichts – nicht recommended und nicht einmal struct.
Die Standard-Basis wird nur angewendet, wenn keine Konfigurationsdatei existiert.
Daher führt eine redocly.yaml genau die Regeln aus, die sie benennt.
Die integrierte Stufe existiert nur, wenn extends ein Regelset benennt oder wenn die Konfiguration jede integrierte Regel selbst auflistet.
Ohne beides lintet ein Dokument, das die Spezifikation dreimal verletzt, sauber.
Verdrahten Sie jede Regel.
Ein Plugin in plugins: tut nichts, wenn seine Regeln in rules: fehlen, und Redocly gibt keine Warnung aus.
Nachdem Sie die Konfiguration geschrieben haben, listen Sie die Regel-IDs auf, die aktiv sein müssen.
Bestätigen Sie, dass jede ID in rules: oder in einem spezifikationsbezogenen Block ist.
Wenn alle Regeln enthalten sind, vergleichen Sie Ihre Liste mit den vordefinierten Regelsets: minimal, recommended, recommended-strict und spec.
- Wenn Ihre Regeln einem Regelset nahe kommen, erweitern Sie es. Behalten Sie nur die Unterschiede als Überschreibungen: andere Schweregrade, auszuschaltende Regeln und Prüfungen, die das Regelset nicht enthält.
- Ein Regelset aktiviert auch Regeln, nach denen der Benutzer nicht gefragt hat.
Lesen Sie, was es hinzufügt, und überschreiben Sie jede Regel, die einer von Ihnen geschriebenen Regel widerspricht oder sie wiederholt.
Ein Regelset, das eine Prüfung aktiviert, die die Quelle auf
offsetzt, ist ein zu korrigierender Fehler, kein Vorteil. - Wenn die Überschreibungen so zahlreich sind wie die Regeln oder mehr, behalten Sie die einfache Liste und kein
extends.
3. Verifizieren
Eine Regel ist nicht nachgewiesen, bis ein Live-Lauf sie meldet.
Weisen Sie jede Regel mit npx redocly lint <api-datei> in zwei Richtungen nach:
- eine verletzende Fixture: die Regel meldet, an der richtigen Stelle;
- eine konforme Fixture: der Lauf bleibt still.
Ein falsch positives Ergebnis ist der häufige Fehler, daher ist eine Regel, die nur die verletzende Fixture bestanden hat, nicht nachgewiesen. Schreiben Sie die verletzende Fixture so, dass diese Regel von der Regel daneben getrennt ist: der Regel, die Sie ersetzen, oder ihrem Nachbarn in der Konfiguration. Zwei Fehler benötigen diese Trennung:
- Setzen Sie einen falschen Wert in die verletzende Fixture.
Eine Regel, die eine leere
descriptionablehnen muss, mussdescription: ''melden. Wenn Sie''nur in die konforme Fixture setzen, beweisen Sie nichts, weil eine Anwesenheits-Assertion es akzeptiert. Die Regel sieht dann korrekt aus und die Lücke bleibt. - Eine integrierte Regel, die zwei Quellprüfungen ersetzt, benötigt eine Fixture, die nur die zweite Prüfung verletzt.
no-unsafe-markdownmeldet<script>, aber niemalseval(. Eine Fixture, die beide enthält, gibt der integrierten Regel Anerkennung für eine Prüfung, die sie nicht durchführt.
Um die Ausgabe sauber zu halten, übergeben Sie eine kleine temporäre Konfiguration mit --config.
Löschen Sie diese Konfiguration und die Fixtures, wenn Sie fertig sind.
Jedes von Ihnen gelieferte Snippet muss wie geschrieben korrekt sein: es wird als YAML geparst und verhält sich wie behauptet.
Sie sind fertig, wenn jede Prüfung eine verletzende Fixture benennt, die gemeldet hat, und eine konforme Fixture, die still geblieben ist.
Nennen Sie diese Fixtures in Ihrem Bericht.
Eine Anzahl ist kein Nachweis.
Ein sauberer Lauf auf den eigenen Dateien des Projekts ist ebenfalls kein Nachweis: er zeigt nur, dass dort nichts gemeldet wird, und das gilt sowohl für eine korrekte Regel als auch für eine tote Regel.
Wenn Sie die riskanten Regeln verifizieren und die anderen annehmen, ist die Auslieferung nicht nachgewiesen. Sagen Sie dies und nennen Sie jede nicht nachgewiesene Regel.
Eine konforme Fixture beweist nur die darin enthaltenen Formen.
Eine Spezifikationsversion, die Sie nicht versucht haben, oder ein Ort, den --parents gezeigt hat und den Sie nicht getestet haben, bleibt ungetestet. Melden Sie dies.
Wenn ein Live-Lauf unmöglich ist, markieren Sie die Regel als nicht verifiziert. Behaupten Sie nicht, dass sie funktioniert.
Sie sind auch fertig, wenn jede angeforderte Prüfung in der Konfiguration oder auf der Übersprungsliste ist und das Projekt nur die Konfigurations- und Plugindateien enthält, die Sie erstellt haben.
Konfigurierbare Regeln
Dokumentation: Konfigurierbare Regeln. Ausgearbeitete Beispiele: Cookbook/configurable-rules.
Eine Regel ist ein Eintrag unter rules: mit einem Namen, der mit rule/ beginnt:
rules:
rule/my-check:
subject:
type: Schema # ein Knotentyp aus der Typliste der Dokumentation
property: title # optional
assertions:
defined: true
where: [] # optionaler Gate
message: Custom problem text.
severity: error
Einfache rules gelten für jedes Dokument, das das Projekt lintet. Behalten Sie Regeln standardmäßig dort.
Verschieben Sie eine Regel nur unter einen spezifikationsbezogenen Schlüssel, wenn die Prüfung etwas benötigt, das nur in einer Spezifikationsversion existiert, wie nullable in OAS 3.0, oder wenn der Benutzer nach der Bereichsabgrenzung fragt.
Die Schlüssel sind oas2Rules, oas3_0Rules, oas3_1Rules, oas3_2Rules, async2Rules, async3Rules, arazzo1Rules und overlay1Rules.
Eine Regel innerhalb eines Schlüssels wird für die anderen Versionen nicht ausgeführt, daher benötigt eine Prüfung, die das Projekt für zwei Versionen benötigt, einen Eintrag, den beide Versionen erreichen.
Begrenzen Sie stattdessen eine Plugin-Regel innerhalb des Plugins in seiner rules-Map.
Was eine Assertion testet
Zwei Tatsachen verursachen die meisten falsch positiven Ergebnisse und die meisten stillen Fehlschläge.
Ein fehlender Wert besteht.
Nahezu jede Assertion gilt, wenn der von ihr geprüfte Wert fehlt.
const: array auf property: type passt auf ein Schema mit dem Typ array und auch auf jedes Schema ohne type.
Wenn also ein where-Eintrag einen Eigenschaftswert testet, fügen Sie defined: true neben die Wert-Assertion, wenn die Eigenschaft fehlen kann.
Anwesenheit ist nicht Wert.
defined, required, requireAny, disallowed und mutuallyExclusive testen, ob ein Schlüssel existiert.
Sie sagen nichts über den Inhalt aus, daher besteht defined: true für description für description: ''.
Bestätigen Sie stattdessen den Wert: nonEmpty: true lehnt einen leeren String ab, und const, enum und pattern testen den Inhalt.
Dies ist der häufigste Mangel in der Praxis.
Er sieht in der Überprüfung korrekt aus, und nur eine verletzende Fixture, die '' enthält, zeigt ihn.
Zwei Ergebnisse dieser Tatsachen:
const: <value>ist auch die Art zu sagen „dieses Feld muss falsch sein“, da die Assertion für diesen Wert und für ein fehlendes Feld gilt.requireAnyzählt nur Schlüssel. „Mindestens eines dieser Felder und nicht leer“ hat keine Assertionsform. Diese Prüfung ist ein echter Plugin-Fall.
Was die Assertion inspiziert
property: name— der Wert dieses Feldes auf dem Subjektknoten.property: [name, url, email]— jedes aufgeführte Feld einzeln. Jedes Feld, das fehlschlägt, wird zu einem eigenen Problem mit eigenem JSON-Pointer, wie#/info/contact/name.propertyfehlt — die Schlüssel des Subjektknotens. Zum Beispielsubject: { type: Paths }mitassertions: { notPattern: /.+\/$/ }läuft auf den Pfad-Strings selbst.
Zielen Sie auf das Subjekt, dann begrenzen Sie es
Drei Stellschrauben zielen auf eine Regel. Lösen Sie sie in dieser Reihenfolge.
1. Subjekt: der Knoten, der besitzt, was Sie bestätigen.
- Eine Prüfung der Schlüssel, die eine Map enthält, zielt auf den Map-Typ selbst.
Die Maps von Responses, Headern, Schema-Eigenschaften und Pfaden sind jeweils ihr eigener Typ.
Daher ist „diese Map muss diesen Schlüssel enthalten“ ein
requiredauf einem Subjekt. Suchen Sie nicht im Elternknoten. - Eine Prüfung eines Werts zielt auf den Knoten, der das Feld enthält, plus
property. type: anymit einempropertyprüft diese Eigenschaft überall, wo sie vorkommt.- Bestätigen Sie den Typnamen mit
inspect-node-typesauf einem Dokument der Spezifikationsversion, die die Regel anvisiert. Ein benannter Typ kann in einer Version existieren und in einer anderen nicht.HeadersMapist ein Typ in OpenAPI 3. In OpenAPI 2 ist dieheaders-Map anonym und hat keinen Typnamen, daher meldet einHeadersMap-Subjekt unteroas2Rulesniemals. Redocly warnt vor einer ungelösten Regel-ID, aber nicht vor einem ungelöstensubject.type, daher ergibt ein falscher Typ eine Regel, die niemals meldet.
2. Eine where-Gate (Liste von Bedingungen)
Eine where-Bedingung schränkt ein, wann die Assertion läuft.
Jedes Element in der Liste ist ein Objekt mit subject, property und assertions.
Alle Bedingungen müssen wahr sein, damit die Regel auf den Subjektknoten angewendet wird.
where:
- subject:
type: Paths
assertions:
defined: true # the subject node must have this field
3. Assertion: was Sie testen
Siehe die Assertions-Referenz.
Plugin-Regeln
Dokumentation: Benutzerdefinierte Plugins.
Ein Plugin ist eine JavaScript-Datei, die ein Objekt exportiert:
export default {
id: 'my-plugin',
rules: {
'my-rule': {
Schema() { /* … */ },
},
},
};
Registrieren Sie das Plugin in redocly.yaml und aktivieren Sie die Regel:
plugins:
- './plugins/my-plugin.js'
rules:
my-plugin/my-rule: error
Das Visitor-Muster
Ein Visitor ist eine Methode auf dem Regelobjekt, benannt nach einem Knotentyp. Redocly ruft sie für jeden Knoten dieses Typs im Dokument auf. Der Methode wird der Knotenwert und ein Kontextobjekt übergeben.
export default {
id: 'example',
rules: {
'no-empty-description': {
Schema(schema, { location, report }) {
if (schema.description === '') {
report({
message: 'Schema description must not be empty.',
location: location.child('description'),
});
}
},
},
},
};
Fehlerbehandlung
- Verwenden Sie
try/catchfür Operationen, die Fehler auslösen können (z. B. Regex). - Ein Fehler in einer Plugin-Regel stoppt die gesamte Linting-Sitzung. Stellen Sie sicher, dass Ihr Code robust ist.
- Testen Sie mit Edge Cases:
null,undefined, leere Strings, unerwartete Typen.
Wann ein Plugin notwendig ist
- Wenn die Assertions von konfigurierbaren Regeln die Prüfung nicht ausdrücken können (z. B. „mindestens eines dieser Felder und nicht leer“).
- Wenn Sie auf externe Datenquellen zugreifen müssen.
- Wenn Sie komplexe Validierungen mit mehreren Bedingungen oder Kontext benötigen.
Fehlerbehebung
Die Regel meldet nie
- Subjekttyp ist falsch. Verwenden Sie
inspect-node-typesmit dem richtigen Pointer und der richtigen Spezifikationsversion. where-Gate blockiert. Kommentieren Sie denwhere-Block aus, um zu sehen, ob die Regel ohne ihn meldet.- Regel ist nicht verdrahtet. Stellen Sie sicher, dass die Regel-ID in
rules:oder im spezifikationsbezogenen Block ist. - Falsche Spezifikationsversion. Ein
oas2Rules-Block wird für OpenAPI 3 nicht ausgeführt.
Falsch positive Ergebnisse
- Fehlender
defined-Test. Eine Assertion aufproperty: descriptionschlägt fürdescription: ''nicht fehl, abernonEmpty: trueschon. - Keine
where-Begrenzung. Die Regel gilt für alle Vorkommen des Subjekttyps, nicht nur für die gewünschten. - Falsche Annahme über Knotenstruktur. Verwenden Sie
--parents, um zu bestätigen, wo ein Knoten sitzen kann.
Fehlerhafte Ausgabe
- Stille Fehlschläge (falsch negativ): Die Regel sollte melden, tut es aber nicht. Überprüfen Sie den Subjekttyp und die Spezifikationsversion.
- Mehrere Meldungen am selben Ort: Der Visitor kann pro Knoten mehr als einmal aufgerufen werden. Verwenden Sie
locationsorgfältig.
Migration von Spectral
- Lesen Sie die Migrations-Dokumentation.
- Lösen Sie die effektive Regelsammlung auf:
spectral:runsoderextends. - Jede Spectral-Regel prüft einen Knotentyp und eine Bedingung. Schreiben Sie diese als Prüfung auf.
- Gehen Sie die Leiter für jede Prüfung durch.
- Setzen Sie den Schweregrad entsprechend:
error→error,warn→warn,info/hint→warn. - Testen Sie jede Regel mit verletzenden und konformen Fixtures.
Checkliste für die Fertigstellung
- Jede Prüfung hat eine Stufe (integriert, konfigurierbar, Plugin).
- Die Konfiguration ist geschrieben und referenziert alle erstellten Dateien.
- Jede Regel ist verdrahtet (in
rules:oder einem spezifikationsbezogenen Block). - Jede Regel ist verifiziert: verletzende Fixture meldet, konforme Fixture bleibt still.
- Migrierte Regeln sind dokumentiert (welche ersetzt, welche hinzugefügt).
- Der Bericht listet nicht nachgewiesene oder nicht migrierte Regeln auf.