oas-linter
oas-linter is the default style-rule plugin used by the oas-validator package while walking an OpenAPI document. It loads YAML or JSON rule files, checks named OpenAPI object types such as operation, parameter, and response, and accumulates warnings for missing fields, naming patterns, mutually exclusive properties, length limits, ordering, and embedded JSON Schema checks. Despite the name, this npm package is not a standalone command-line program and does not parse an API document by itself.
Keep oas-linter when maintaining an OAS-Kit stack that already depends on its rule DSL. For a new linting workflow, install Spectral, Redocly CLI, or another actual executable instead of wiring this stateful plugin by hand.
Use it if
- You already use oas-validator and want to keep its built-in lint rules or replace them with a compatible local rule file
- You need a small YAML rules DSL for checks tied to oas-validator object names such as operation, parameter, reference, and securityScheme
- You maintain an existing OAS-Kit integration that calls loadRules, lint, and getResults directly
- You need to chain a base rules file and override individual rules by their unique name
- You expect an oas-linter executable: package 3.2.2 publishes no bin entry, so it cannot lint a file from a shell on its own
- You want current OpenAPI governance tooling: the npm release is from May 2021 and the monorepo was last pushed in October 2023, while Spectral and Redocly CLI have broader current ruleset ecosystems
- You need arbitrary JSONPath selection or custom JavaScript rule functions: this DSL targets the object names supplied by oas-validator and only implements its fixed set of rule operators
- You run validations concurrently with different rule sets in one process: the source stores rules and results in module-level mutable arrays, and loading rules or starting another rule application resets shared state
- You want one dependency that parses, resolves, validates, and reports OpenAPI files: this is only a plugin, its README tells users to pair it with oas-validator, and direct use requires you to reproduce the validator's traversal context
Setup reality
Installing npm install oas-linter succeeds without native compilation, credentials, environment variables, or peer-dependency warnings, but that does not give you a runnable linter. There is no bin field. In normal use you install oas-validator and pass { lint: true }; the validator loads this package's default rules, walks the already parsed OpenAPI object, and copies getResults() into options.warnings. Direct use is much more manual: call loadDefaultRules() or loadRules(path) first, then call lint(objectName, object, key, options) for every relevant object in the same order the validator does. The options object must contain metadata with a count object, context, lintSkip, and a numeric verbose value or the implementation can fail on assumptions that its host normally satisfies. Custom rule files are read synchronously from disk and parsed as YAML with the core schema. A top-level require can chain another rules file; extensionless paths inherit the parent file's extension, and relative paths resolve beside the parent. Rules with the same name merge, disabled rules are removed, and applyRules resets accumulated results. State is global to the loaded module, not scoped to a validator instance, so concurrent jobs with distinct rules can overwrite one another. There are no bundled TypeScript declarations. The dependencies include should, yaml 1.x, and a release-candidate range of @exodus/schemasafe. In CI, wrap oas-validator rather than this package, pin versions, load rules once per isolated process, and turn warning results into an explicit nonzero exit policy yourself.
Patterns
Run the default linter through oas-validatorvalidate-with-defaults
const validator = require('oas-validator')
const options = { lint: true }
try {
await validator.validate(openapiDocument, options)
} catch (error) {
console.error(error.message)
console.error(options.warnings || [])
}This is the supported integration path. oas-validator loads default rules, supplies traversal context, and gathers linter results into options.warnings.
Define truthy and pattern rules in YAMLwrite-rules-file
# api-rules.yaml
url: https://docs.example.com/api-rules
rules:
- name: operation-id-required
object: operation
description: operations need an operationId
truthy: operationId
- name: operation-id-style
object: operation
pattern:
property: operationId
value: '^[a-z][A-Za-z0-9]+$'object names are supplied by oas-validator, not discovered from JSONPath. A rule with an unknown object name will never be visited.
Load a custom rules fileload-custom-rules
const linter = require('oas-linter')
linter.loadRules(require.resolve('./api-rules.yaml'))
console.log(linter.getRules().rules.map((rule) => rule.name))loadRules reads synchronously and changes module-level state. Load once before validation and do not swap rule files between concurrent requests.
Pass custom-loaded rules to oas-validatorinject-custom-linter
const validator = require('oas-validator')
const linter = require('oas-linter')
linter.loadRules(require.resolve('./api-rules.yaml'))
const options = {
lint: true,
linter: linter.lint,
linterResults: linter.getResults,
}
await validator.validate(openapiDocument, options)Supplying linter prevents oas-validator from calling loadDefaultRules. Pair it with linterResults or the host cannot collect the warnings.
Extend a base rules filechain-rule-files
# team-rules.yaml
require: ./base-rules
rules:
- name: operation-tags
description: every operation needs at least one tag
object: operation
truthy: tagsAn extensionless require inherits .yaml from the parent, and relative paths resolve from the parent rules file rather than process.cwd().
Disable a rule inherited by namedisable-default-rule
require: ./base-rules.yaml
rules:
- name: info-contact
disabled: trueRules are merged by name, then entries with disabled: true are filtered out. The older enabled property is deprecated and ignored.
Require one of several propertiesrequire-one-property
rules:
- name: operation-summary-or-description
object: operation
description: add summary or description
or:
- summary
- descriptionor checks whether at least one named property is defined. It does not require the selected value to be non-empty; use truthy when emptiness must fail.
Require exactly one of two fieldsrequire-exclusive-property
rules:
- name: example-source-exclusive
object: example
description: choose inline or external example data
xor:
- value
- externalValuexor reports when neither property exists and when more than one exists. It tests definedness, not whether values are non-empty.
Limit a string fieldenforce-max-length
rules:
- name: operation-summary-length
object: operation
maxLength:
property: summary
value: 80maxLength only runs when the target property exists and is a string. Combine it with truthy if the field is also mandatory.
Validate an object with an embedded JSON Schemaembed-json-schema
rules:
- name: contact-shape
object: contact
schema:
type: object
required: [email]
properties:
email:
type: string
pattern: '^[^@]+@[^@]+$'Schemas are compiled lazily with @exodus/schemasafe and cached on the in-memory rule object as $schema. Use supported JSON Schema keywords for that dependency version.
Skip selected rules for one validationskip-named-rules
const options = {
lint: true,
lintSkip: ['info-contact', 'license-url'],
}
await validator.validate(openapiDocument, options)lintSkip matches exact rule names. It is useful for a temporary exception but can silently preserve policy drift if the list is never reviewed.
Read warning details after validationinspect-results
for (const warning of options.warnings || []) {
console.error({
rule: warning.ruleName,
pointer: warning.pointer,
message: warning.message,
docs: warning.rule && warning.rule.url,
})
}Warnings come from shared accumulated results. Consume them immediately after one validation and isolate parallel jobs in separate processes if rule sets differ.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| @stoplight/spectral-cli | npm | Use for a standalone OpenAPI and AsyncAPI linter with JSONPath-based rules, shareable rulesets, formats, and direct CI commands |
| @redocly/cli | npm | Use when linting should sit beside OpenAPI bundling, preview, documentation, and configurable organization rules |
| ibm-openapi-validator | npm | Use for an installable OpenAPI validator and linter with its own CLI and configurable rules rather than an internal traversal plugin |