Skip to content

Latest commit

 

History

History
80 lines (65 loc) · 2.72 KB

File metadata and controls

80 lines (65 loc) · 2.72 KB

Contributing to apilint

Thanks for your interest! apilint is built so that adding a rule is small, isolated, and testable.

Getting started

git clone https://github.com/didrod205/apilint.git
cd apilint
npm install
npm test            # vitest
npm run typecheck   # tsc --noEmit
npm run build       # tsup -> dist/
node dist/cli.js scan examples/petstore-bad.yaml

Project layout

src/
  parse/yaml.ts     # dependency-free YAML subset parser
  parse/index.ts    # JSON/YAML auto-detection -> OpenApiDoc
  model.ts          # safe accessors: eachOperation, resolveRef, collectRefs
  rules/            # structure / info / operations / parameters / naming /
                    #   schemas / security  (the interesting part) + registry
  score.ts          # per-category & overall score, A–F grade
  report/           # json | markdown | console renderers
  config.ts, types.ts, index.ts, loader.ts, cli.ts
tests/              # vitest specs (incl. YAML parser)
examples/           # petstore-good.yaml, petstore-bad.yaml, config + sample reports

Adding a rule

  1. Add the rule id to RuleId and RULE_LABELS in src/types.ts.

  2. Write the rule in the relevant src/rules/*.ts:

    import type { Issue } from "../types.js";
    import { eachOperation } from "../model.js";
    import { makeIssue, type Rule, type RuleContext } from "./context.js";
    
    export const myRule: Rule = {
      id: "my-rule",
      category: "operations",
      severity: "warning",
      run(ctx: RuleContext): Issue[] {
        const issues: Issue[] = [];
        for (const { path, method, op } of eachOperation(ctx.doc)) {
          // inspect op and push makeIssue(this, ctx, { message, location, fix })
        }
        return issues;
      },
    };
  3. Register it in src/rules/index.ts (order = report order).

  4. Add a test in tests/rules.test.ts proving it fires (and doesn't on a clean spec).

Principles

  • Deterministic. No randomness, no network, no time-dependent output. Same spec must always produce the same report.
  • Opinionated but tunable. Ship sensible defaults; let users disable/retune.
  • Static-only. Parse the document; don't execute or fetch anything.
  • Dependency-light. Only cac and picocolors at runtime — the YAML parser is intentionally hand-rolled.
  • Actionable. Every issue carries a location and a concrete fix.

Checklist before opening a PR

  • npm run typecheck passes
  • npm test passes (tests added for new behavior)
  • New rules have a stable id, a label, and a fix message
  • CHANGELOG.md updated for user-facing changes
  • Regenerated examples/sample-report.* if output changed

This project follows the Contributor Covenant.