oas-schema-walker review
oas-schema-walker 1.1.5 is a two-function CommonJS utility for traversing one OpenAPI 3.0 Schema Object. `walkSchema` calls a callback on the root and recognized children under `items`, properties, pattern properties, additional schemas, `allOf`, `anyOf`, `oneOf`, and `not`; `getDefaultState` supplies depth, cycle tracking, and two behavior flags. It neither discovers schemas inside a full OpenAPI document nor resolves references, validates keywords, or builds JSON Pointers. The current release changed JSDoc comments only, so its runtime behavior is effectively the March 2020 line plus that documentation publication.
oas-schema-walker 1.1.5 installed in 0.9 seconds and its browser build was 0.9 KB gzipped in our sandbox, but it ships no types and its latest release only adjusted JSDoc. Keep it for OAS-Kit compatibility or a known OpenAPI 3.0 subset; new 3.1 tooling should install a walker that understands the current JSON Schema vocabulary and reference graph.
We installed it
| Install | ✓ · 0.9s | 1 package on disk · 1 MB |
| Import | ✓ | ESM import works · require() works · CommonJS package |
| Browser | 0.9 KB | gzipped (2.1 KB minified), bundled with esbuild |
| Types | — | no TypeScript types found |
| Known vulns | 0 | 0 critical · 0 high · 0 moderate · 0 low (npm audit) |
Answers from our run
Does oas-schema-walker install cleanly?
Yes. In a fresh container with an empty cache, npm install oas-schema-walker finished in 0.9s, leaving 1 package and 1 MB on disk. npm audit reported no known vulnerabilities.
How much does oas-schema-walker add to a browser bundle?
0.9 KB gzipped (2.1 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.
Does oas-schema-walker work with both ESM and CommonJS?
Yes. Both import 'oas-schema-walker' and require('oas-schema-walker') worked in Node 22 in our run. The package is published as CommonJS.
Does oas-schema-walker include TypeScript types?
No type declarations were found in our install, so TypeScript users need their own declarations.
oas-schema-walker or json-schema-traverse: which should you use?
json-schema-traverse: Choose it for JSON Schema traversal with explicit pointers and a callback API built around more schema keywords. oas-schema-walker 1.1.5 installed in 0.9 seconds and its browser build was 0.9 KB gzipped in our sandbox, but it ships no types and its latest release only adjusted JSDoc.
When should you not use oas-schema-walker?
The job starts with a whole OpenAPI file. This walker knows no paths, operations, parameters, responses, component lookup, parsing, or YAML.
Use it if
- Existing OAS-Kit code needs the exact traversal behavior used by its resolver, validator, or converter packages.
- A controlled OpenAPI 3.0 schema needs a synchronous pre-order callback with zero dependencies.
- In-place inspection or mutation is acceptable and the caller can select each starting Schema Object.
- Repeated JavaScript object references may occur and a WeakMap-based descent guard is enough.
- The job starts with a whole OpenAPI file. This walker knows no paths, operations, parameters, responses, component lookup, parsing, or YAML.
- OpenAPI 3.1 or JSON Schema 2020-12 coverage matters. It does not descend through `prefixItems`, `contains`, conditionals, `dependentSchemas`, `propertyNames`, or unevaluated keywords.
- Referenced schemas must be visited. A `$ref` produces a small temporary callback object and stops; the target and most sibling keywords are ignored.
- TypeScript consumers require maintained declarations. The 24 KB package includes no types and publishes no ESM-specific entry or exports map.
- Your policy requires tested, recent releases. Version 1.1.5 was published in July 2020, its package test script exits with `Error: no test specified`, and the monorepo last moved in October 2023.
Setup reality
We installed oas-schema-walker 1.1.5 in a clean Node 22 sandbox in 0.9 seconds. npm left one package and 1 MB on disk; the package is 24 KB unpacked with zero direct dependencies and zero peers. It uses the BSD-3-Clause license, includes no TypeScript declarations, and produced zero npm audit findings. Both require() and ESM import worked despite the CommonJS-only package metadata. Our browser build measured 2.1 KB minified and 0.9 KB gzipped.
Call walkSchema(schema, {}, getDefaultState(), callback). The generated README omits the first parameter from its displayed signature, while the source clearly takes schema, parent, state, then callback. There is no file parser or configuration layer; extract each components.schemas value yourself. Passing a state without depth replaces it with defaults, so set combine or allowRefSiblings on a real default state.
One mutable state object is shared for the walk. depth rises and falls, top becomes false after the root and never returns to true, and property holds only the latest relative edge such as properties/name. Copy values during the callback and build your own path stack if location matters. The callback fires before the seen-object check, so a repeated reference is reported again even though its children are not revisited.
A $ref callback receives a new object containing the reference, plus description only when allowRefSiblings is true. Mutating that temporary object does not rewrite the original. combine creates a flattened callback view for single-entry composition arrays, but local reassignment does not reliably replace the parent's child. Ordinary nodes are original objects and can be mutated, so clone input first when callers still need an untouched schema.
Patterns
Walk every supported child schema visit-schema-nodes
const {getDefaultState, walkSchema} = require('oas-schema-walker');
walkSchema(schema, {}, getDefaultState(), (node, parent, state) => {
console.log(state.depth, node.type);
});The actual order is schema, parent, state, callback. The README's generated signature leaves out the first argument.
Start from each OpenAPI component schema walk-component-schemas
for (const [name, schema] of Object.entries(api.components?.schemas ?? {})) {
walkSchema(schema, {}, getDefaultState(), (node) => {
console.log(name, node.type);
});
}The package does not find schemas inside an OpenAPI document. Select each root before calling it.
Record property edges during traversal copy-relative-edges
const edges = [];
walkSchema(schema, {}, getDefaultState(), (node, _parent, state) => {
if (state.property?.startsWith('properties/')) {
edges.push({name: state.property.slice(11), node});
}
});`state.property` is a relative edge, not a full path, and later callbacks overwrite it. Copy the string immediately.
Count callback invocations count-callbacks
let callbacks = 0;
walkSchema(schema, {}, getDefaultState(), () => { callbacks += 1; });
console.log(callbacks);A repeated object triggers another callback before the WeakMap check stops descent, so this may exceed the number of unique objects.
Read required names from object schemas find-required-properties
const requiredByNode = [];
walkSchema(schema, {}, getDefaultState(), (node, _parent, state) => {
if (Array.isArray(node.required)) {
requiredByNode.push({depth: state.depth, names: [...node.required]});
}
});Depth alone is not a durable address. Maintain a path stack if required lists from different objects must be mapped back exactly.
Add a description to typed nodes mutate-ordinary-nodes
walkSchema(schema, {}, getDefaultState(), (node) => {
if (node.type && !node.description) {
node.description = `A ${node.type} value`;
}
});Ordinary callback nodes are the original objects, so this mutation persists. Clone the schema before destructive transformations.
Find reference strings without resolving them collect-ref-values
const refs = [];
walkSchema(schema, {}, getDefaultState(), (node) => {
if (node.$ref) refs.push(node.$ref);
});Traversal ends at every `$ref`. The callback object is a temporary copy and does not expose the target.
Expose descriptions next to references retain-ref-description
const state = getDefaultState();
state.allowRefSiblings = true;
walkSchema(schema, {}, state, (node) => {
if (node.$ref) console.log(node.$ref, node.description);
});Only `description` is copied beside `$ref`; all other sibling keys are absent from the callback view.
Flatten a one-branch composition for callbacks inspect-single-composition
const state = getDefaultState();
state.combine = true;
walkSchema(schema, {}, state, (node) => {
console.log(node.type, node.allOf);
});This is best treated as an inspection view. The combined local object may not replace the original child held by its parent.
Handle only the first two levels filter-shallow-callback-work
walkSchema(schema, {}, getDefaultState(), (node, _parent, state) => {
if (state.depth <= 2) inspect(node);
});The callback cannot prune traversal. Deeper supported children are still visited even when the callback returns early.
Flag OpenAPI 3.1 schema branches warn-on-unsupported-keywords
const newer = ['prefixItems', 'contains', 'if', 'then', 'else', 'dependentSchemas'];
walkSchema(schema, {}, getDefaultState(), (node) => {
for (const keyword of newer) {
if (keyword in node) console.warn(`Manual walk needed: ${keyword}`);
}
});The warning sees the current node but this package will not descend through those JSON Schema 2020-12 child keywords.
Import the CommonJS package from ESM load-from-esm
import walker from 'oas-schema-walker';
const {getDefaultState, walkSchema} = walker;
walkSchema(schema, {}, getDefaultState(), visit);Our Node 22 ESM import worked through CommonJS interop. There is no exports map or native ESM build.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| json-schema-traverse | npm | Choose it for JSON Schema traversal with explicit pointers and a callback API built around more schema keywords. |
| @apidevtools/swagger-parser | npm | Use it when the input is a complete Swagger or OpenAPI document that needs parsing, validation, bundling, or dereferencing. |
| @redocly/openapi-core | npm | Choose it for maintained OpenAPI document walking, rules, resolution, and linting rather than one isolated schema callback. |
More utils guides
lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

