@scalar/openapi-parser
Version:
modern OpenAPI parser written in TypeScript
109 lines (108 loc) • 3.66 kB
JavaScript
import Ajv04 from "ajv-draft-04";
import addFormats from "ajv-formats";
import Ajv2020 from "ajv/dist/2020.js";
import { ERRORS, OpenApiSpecifications, OpenApiVersions } from "../../configuration/index.js";
import { details as getOpenApiVersion } from "../../utils/details.js";
import { resolveReferences } from "../../utils/resolve-references.js";
import { transformErrors } from "../../utils/transform-errors.js";
const jsonSchemaVersions = {
"http://json-schema.org/draft-04/schema#": Ajv04,
"https://json-schema.org/draft/2020-12/schema": Ajv2020
};
class Validator {
version;
static supportedVersions = OpenApiVersions;
// Object with function *or* object { errors: string }
ajvValidators = {};
errors;
specificationVersion;
specificationType;
specification;
/**
* Checks whether a specification is valid and all references can be resolved.
*/
async validate(filesystem, options) {
const entrypoint = filesystem.find((file) => file.isEntrypoint);
const specification = entrypoint?.specification;
this.specification = specification;
if (this.specification?.info && !this.specification.info.version) {
this.specification.info.version = "0.0.1";
}
try {
if (specification === void 0 || specification === null) {
if (options?.throwOnError) {
throw new Error(ERRORS.EMPTY_OR_INVALID);
}
return {
valid: false,
errors: transformErrors(entrypoint, ERRORS.EMPTY_OR_INVALID)
};
}
const { version, specificationType, specificationVersion } = getOpenApiVersion(specification);
this.version = version;
this.specificationVersion = specificationVersion;
this.specificationType = specificationType;
if (!version) {
if (options?.throwOnError) {
throw new Error(ERRORS.OPENAPI_VERSION_NOT_SUPPORTED);
}
return {
valid: false,
errors: transformErrors(entrypoint, ERRORS.OPENAPI_VERSION_NOT_SUPPORTED)
};
}
const validateSchema = await this.getAjvValidator(version);
const schemaResult = validateSchema(specification);
if (validateSchema.errors) {
if (validateSchema.errors.length > 0) {
if (options?.throwOnError) {
throw new Error(validateSchema.errors[0]);
}
return {
valid: false,
errors: transformErrors(entrypoint, validateSchema.errors)
};
}
}
const resolvedReferences = resolveReferences(filesystem, options);
return {
valid: schemaResult && resolvedReferences.valid,
errors: [...schemaResult.errors ?? [], ...resolvedReferences.errors],
schema: resolvedReferences.schema
};
} catch (error) {
if (options?.throwOnError) {
throw error;
}
return {
valid: false,
errors: transformErrors(entrypoint, error.message ?? error)
};
}
}
/**
* Ajv JSON schema validator
*/
async getAjvValidator(version) {
if (this.ajvValidators[version]) {
return this.ajvValidators[version];
}
const schema = OpenApiSpecifications[version];
const AjvClass = jsonSchemaVersions[schema.$schema];
const ajv = new AjvClass({
// Ajv is a bit too strict in its strict validation of OpenAPI schemas.
// Switch strict mode off.
strict: false
});
addFormats(ajv);
if (version === "3.1") {
ajv.addFormat("media-range", true);
}
return this.ajvValidators[version] = ajv.compile(schema);
}
}
export {
Validator,
jsonSchemaVersions
};
//# sourceMappingURL=Validator.js.map