swagger-object-validator
Version:
Validate your objects against a swagger spec and receive in-depth error traces
204 lines (203 loc) • 7.22 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadSchema = exports.resolveInternalPath = exports.loadSchemaByName = exports.loader = void 0;
var Promise = require("bluebird");
var fs_1 = require("fs");
var http_1 = require("http");
var https_1 = require("https");
var js_yaml_1 = require("js-yaml");
var path = require("path");
var getTypeName_1 = require("./getTypeName");
var HTTPCache = {};
function splitPath(descriptor) {
var hashPos = descriptor.indexOf('#/');
if (hashPos !== -1) {
var fileName = descriptor.substr(0, hashPos);
var path_1 = descriptor.substr(hashPos);
return [fileName, path_1];
}
return [descriptor, undefined];
}
function loader(input, config) {
if (typeof (input) === 'string') {
return _loadFromString(input, config);
}
else if (!input) {
return Promise.resolve(null);
}
else {
var spec = JSON.parse(JSON.stringify(input));
spec = convertRefsToAbsolute(config.partialsDir, spec);
return Promise.resolve(spec);
}
}
exports.loader = loader;
function loadSchemaByName(schemaName, spec, config) {
var schema = spec.definitions[schemaName];
if (!schema) {
throw new Error("Schema ".concat(schemaName, " not found in definitions"));
}
return loadSchema(schema, spec, config);
}
exports.loadSchemaByName = loadSchemaByName;
function resolveInternalPath(path, obj) {
if (!path.startsWith('#/')) {
throw new Error("Path ".concat(path, " not a hashed path"));
}
path = path.substr(2);
var components = path.split('/');
var location = obj;
for (var _i = 0, components_1 = components; _i < components_1.length; _i++) {
var component = components_1[_i];
if (!(location instanceof Object)) {
throw new Error("Path ".concat(path, " could not be found in spec, ").concat(component, " could not be resolved"));
}
if (!location.hasOwnProperty(component)) {
throw new Error("Path ".concat(path, " could not be found in spec, ").concat(component, " could not be resolved"));
}
location = location[component];
}
return location;
}
exports.resolveInternalPath = resolveInternalPath;
function loadSchema(schema, spec, config) {
if (!schema.$ref) {
return Promise.resolve(schema);
}
return _loadFromString(schema.$ref, config, spec).then(function (dereferencedSchema) { return replaceRef(schema, dereferencedSchema); });
}
exports.loadSchema = loadSchema;
function replaceRef(schema, dereferencedSchema) {
delete schema.$ref;
for (var propertyName in dereferencedSchema) {
if (dereferencedSchema.hasOwnProperty(propertyName)) {
schema[propertyName] = dereferencedSchema[propertyName];
}
}
return schema;
}
function _loadFromString(fullPath, config, spec) {
var _a = splitPath(fullPath), filePath = _a[0], internalPath = _a[1];
var extension = path.extname(filePath);
var childCwd = config.partialsDir;
var contents;
if (!filePath) {
if (!internalPath) {
return Promise.reject("Invalid path: ".concat(fullPath));
}
if (!spec) {
return Promise.reject("Missing Spec to resolve ".concat(fullPath, " against"));
}
return loadSchema(resolveInternalPath(internalPath, spec), spec, config);
}
else if (_needsDownload(filePath)) {
contents = _download(filePath, config);
}
else {
if (!path.isAbsolute(filePath)) {
filePath = path.join(config.partialsDir, filePath);
}
childCwd = path.dirname(filePath);
if (!fs_1.existsSync || !fs_1.readFile) {
return Promise.reject('Cannot read file system, seems like you are using this module in frontend');
}
if (!(0, fs_1.existsSync)(filePath)) {
return Promise.reject("File ".concat(filePath, " does not exist"));
}
contents = new Promise(function (resolve, reject) {
(0, fs_1.readFile)(filePath, 'utf-8', function (err, file) {
if (err) {
reject("Error loading file ".concat(filePath));
}
else {
resolve(file);
}
});
});
}
if (extension === '.json') {
contents = contents.then(function (file) { return JSON.parse(file); });
}
else if (extension === '.yaml' || extension === '.yml') {
contents = contents.then(function (file) { return (0, js_yaml_1.load)(file); });
}
else {
return Promise.reject("File extension ".concat(extension, " is not supported"));
}
contents = contents.then(function (obj) { return convertRefsToAbsolute(childCwd, obj); });
if (internalPath) {
contents = contents.then(function (obj) { return resolveInternalPath(internalPath, obj); });
}
return contents;
}
function convertRefsToAbsolute(cwd, obj) {
if (!cwd.endsWith('/')) {
cwd += '/';
}
switch ((0, getTypeName_1.getTypeName)(obj)) {
case 'array':
for (var _i = 0, _a = obj; _i < _a.length; _i++) {
var prop = _a[_i];
convertRefsToAbsolute(cwd, prop);
}
break;
case 'object':
if (obj.hasOwnProperty('$ref')) {
var ref = obj['$ref'];
if (!_needsDownload(ref) && !ref.startsWith('/') && !ref.startsWith('#/')) {
obj['$ref'] = cwd + obj['$ref'];
}
}
for (var propertyName in obj) {
convertRefsToAbsolute(cwd, obj[propertyName]);
}
break;
default:
break;
}
return obj;
}
function _needsDownload(path) {
return path.indexOf('http://') === 0 || path.indexOf('https://') === 0;
}
function _download(url, config) {
if (!config.disableDownloadCache && HTTPCache[url]) {
return HTTPCache[url];
}
var downloadMethod;
if (url.indexOf('http://') === 0) {
if (config.disallowHttp) {
return Promise.reject('Definition needs HTTP, which is disallowed');
}
downloadMethod = http_1.get;
}
else {
if (config.disallowHttps) {
return Promise.reject('Definition needs HTTPS, which is disallowed');
}
downloadMethod = https_1.get;
}
var loadPromise = new Promise(function (resolve, reject) {
downloadMethod(url, function (response) { return _downloadStarted(response, config, resolve, reject); })
.on('error', function (err) {
if (!config.disableDownloadCache) {
delete HTTPCache[url];
}
return reject(err.message);
});
});
if (!config.disableDownloadCache) {
HTTPCache[url] = loadPromise;
}
return loadPromise;
}
function _downloadStarted(response, config, resolve, reject) {
response.setEncoding('utf8');
var file = '';
response.on('data', function (chunk) {
file += chunk;
});
response.on('end', function () {
resolve(file);
});
}