@redocly/openapi-core
Version:
See https://github.com/Redocly/redocly-cli
69 lines (58 loc) • 2 kB
text/typescript
import { buildSubjectVisitor, buildVisitorObject } from './utils';
import { isString } from '../../../utils';
import type { asserts, AssertionFn } from './asserts';
import type {
Arazzo1Visitor,
Async2Visitor,
Async3Visitor,
Oas2Visitor,
Oas3Visitor,
Overlay1Visitor,
} from '../../../visitors';
import type { RuleSeverity } from '../../../config';
export type AssertionLocators = {
filterInParentKeys?: (string | number)[];
filterOutParentKeys?: (string | number)[];
matchParentKeys?: string;
};
export type AssertionDefinition = {
subject: {
type: string;
property?: string | string[];
} & AssertionLocators;
assertions: { [name in keyof typeof asserts]?: AssertionFn };
};
export type RawAssertion = AssertionDefinition & {
where?: AssertionDefinition[];
message?: string;
suggest?: string[];
severity?: RuleSeverity;
};
export type Assertion = RawAssertion & { assertionId: string };
export const Assertions = (opts: Record<string, Assertion>) => {
const visitors: (
| Oas2Visitor
| Oas3Visitor
| Async2Visitor
| Async3Visitor
| Arazzo1Visitor
| Overlay1Visitor
)[] = [];
// As 'Assertions' has an array of asserts,
// that array spreads into an 'opts' object on init rules phase here
// https://github.com/Redocly/redocly-cli/blob/main/packages/core/src/config/config.ts#L311
// that is why we need to iterate through 'opts' values;
// before - filter only object 'opts' values
const assertions: Assertion[] = Object.values(opts).filter(
(opt: unknown) => typeof opt === 'object' && opt !== null
);
for (const [_, assertion] of assertions.entries()) {
if (!isString(assertion.subject.type)) {
throw new Error(`${assertion.assertionId}: 'type' (String) is required`);
}
const subjectVisitor = buildSubjectVisitor(assertion.assertionId, assertion);
const visitorObject = buildVisitorObject(assertion, subjectVisitor);
visitors.push(visitorObject);
}
return visitors;
};