redoc
Version:
Swagger-generated API Reference Documentation
232 lines • 9.36 kB
JavaScript
;
import { JsonPointer } from '../utils/JsonPointer';
import { defaults } from '../utils/helpers';
import { WarningsService } from './warnings.service';
var SchemaNormalizer = /** @class */ (function () {
function SchemaNormalizer(_schema) {
this._dereferencer = new SchemaDereferencer(_schema, this);
}
SchemaNormalizer.prototype.normalize = function (schema, ptr, opts) {
var _this = this;
if (opts === void 0) { opts = {}; }
var hasPtr = !!schema.$ref;
if (opts.resolved && !hasPtr)
this._dereferencer.visit(ptr);
if (opts.childFor)
this._dereferencer.visit(opts.childFor);
if (schema['x-redoc-normalized'])
return schema;
var res = SchemaWalker.walk(schema, ptr, function (subSchema, ptr) {
var resolved = _this._dereferencer.dereference(subSchema, ptr);
if (resolved.allOf) {
resolved._pointer = resolved._pointer || ptr;
resolved = Object.assign({}, resolved);
AllOfMerger.merge(resolved, resolved.allOf);
}
return resolved;
});
if (opts.resolved && !hasPtr)
this._dereferencer.exit(ptr);
if (opts.childFor)
this._dereferencer.exit(opts.childFor);
res['x-redoc-normalized'] = true;
return res;
};
SchemaNormalizer.prototype.reset = function () {
this._dereferencer.reset();
};
return SchemaNormalizer;
}());
export { SchemaNormalizer };
var SchemaWalker = /** @class */ (function () {
function SchemaWalker() {
}
SchemaWalker.walk = function (obj, pointer, visitor) {
if (obj == undefined || typeof (obj) !== 'object') {
return;
}
if (obj['x-redoc-visited']) {
obj['x-redoc-visited'] = false;
var res = visitor(obj, pointer);
// circular, return only title and description
return { title: res.title, description: res.description };
}
obj['x-redoc-visited'] = true;
if (obj.properties) {
var ptr = JsonPointer.join(pointer, ['properties']);
SchemaWalker.walkEach(obj.properties, ptr, visitor);
}
if (obj.additionalProperties) {
var ptr = JsonPointer.join(pointer, ['additionalProperties']);
if (Array.isArray(obj.additionalProperties)) {
SchemaWalker.walkEach(obj.additionalProperties, ptr, visitor);
}
else {
var res = SchemaWalker.walk(obj.additionalProperties, ptr, visitor);
if (res)
obj.additionalProperties = res;
}
}
if (obj.allOf) {
var ptr = JsonPointer.join(pointer, ['allOf']);
SchemaWalker.walkEach(obj.allOf, ptr, visitor);
}
if (obj.items) {
var ptr = JsonPointer.join(pointer, ['items']);
if (Array.isArray(obj.items)) {
SchemaWalker.walkEach(obj.items, ptr, visitor);
}
else {
var res = SchemaWalker.walk(obj.items, ptr, visitor);
if (res)
obj.items = res;
}
}
obj['x-redoc-visited'] = false;
return visitor(obj, pointer);
};
SchemaWalker.walkEach = function (obj, pointer, visitor) {
for (var _i = 0, _a = Object.keys(obj); _i < _a.length; _i++) {
var key = _a[_i];
var ptr = JsonPointer.join(pointer, [key]);
var res = SchemaWalker.walk(obj[key], ptr, visitor);
if (res)
obj[key] = res;
}
};
return SchemaWalker;
}());
var AllOfMerger = /** @class */ (function () {
function AllOfMerger() {
}
AllOfMerger.merge = function (into, schemas) {
into['x-derived-from'] = [];
var hadDiscriminator = !!into.discriminator;
for (var i = 0; i < schemas.length; i++) {
var subSchema = schemas[i];
into['x-derived-from'].push(subSchema._pointer);
AllOfMerger.checkCanMerge(subSchema, into);
into.type = into.type || subSchema.type;
if (into.type === 'object') {
AllOfMerger.mergeObject(into, subSchema, i);
}
// don't merge _pointer
var tmpPtr = subSchema._pointer;
subSchema._pointer = null;
defaults(into, subSchema);
subSchema._pointer = tmpPtr;
}
if (!hadDiscriminator)
into.discriminator = null;
delete into.allOf;
};
AllOfMerger.mergeObject = function (into, subSchema, allOfNumber) {
if (subSchema.properties) {
into.properties = Object.assign({}, into.properties || {});
Object.assign(into.properties, subSchema.properties);
Object.keys(subSchema.properties).forEach(function (propName) {
var prop = subSchema.properties[propName];
if (!prop._pointer) {
var schemaPtr = subSchema._pointer || JsonPointer.join(into._pointer, ['allOf', allOfNumber]);
prop._pointer = prop._pointer || JsonPointer.join(schemaPtr, ['properties', propName]);
}
});
}
if (subSchema.required) {
if (!into.required)
into.required = [];
(_a = into.required).push.apply(_a, subSchema.required);
}
var _a;
};
AllOfMerger.checkCanMerge = function (subSchema, into) {
// TODO: add support for merge array schemas
if (typeof subSchema !== 'object') {
var errMessage = "Items of allOf should be Object: " + typeof subSchema + " found " +
(subSchema + " at \"#" + into._pointer + "\"");
throw new Error(errMessage);
}
if (into.type && subSchema.type && into.type !== subSchema.type) {
var errMessage = "allOf merging error: schemas with different types can't be merged: " +
("\"" + into.type + "\" and \"" + subSchema.type + "\" at \"#" + into._pointer + "\"");
throw new Error(errMessage);
}
if (into.type === 'array') {
WarningsService.warn('allOf: subschemas with type "array" are not supported yet');
}
// TODO: add check if can be merged correctly (no different properties with the same name)
// TODO: merge properties
};
return AllOfMerger;
}());
export { AllOfMerger };
var RefCounter = /** @class */ (function () {
function RefCounter() {
this._counter = {};
}
RefCounter.prototype.reset = function () {
this._counter = {};
};
RefCounter.prototype.visit = function (ref) {
this._counter[ref] = this._counter[ref] ? this._counter[ref] + 1 : 1;
};
RefCounter.prototype.exit = function (ref) {
this._counter[ref] = this._counter[ref] && this._counter[ref] - 1;
};
RefCounter.prototype.visited = function (ref) {
return !!this._counter[ref];
};
return RefCounter;
}());
var SchemaDereferencer = /** @class */ (function () {
function SchemaDereferencer(_spec, normalizator) {
this._spec = _spec;
this.normalizator = normalizator;
this._refCouner = new RefCounter();
}
SchemaDereferencer.prototype.reset = function () {
this._refCouner.reset();
};
SchemaDereferencer.prototype.visit = function ($ref) {
this._refCouner.visit($ref);
};
SchemaDereferencer.prototype.exit = function ($ref) {
this._refCouner.exit($ref);
};
SchemaDereferencer.prototype.dereference = function (schema, pointer) {
if (!schema || !schema.$ref)
return schema;
var $ref = schema.$ref;
var resolved = this._spec.byPointer($ref);
if (!this._refCouner.visited($ref)) {
resolved._pointer = $ref;
}
else {
// for circular referenced save only title and type
resolved = {
title: resolved.title,
type: resolved.type
};
}
this._refCouner.visit($ref);
// if resolved schema doesn't have title use name from ref
resolved.title = resolved.title || JsonPointer.baseName($ref);
var keysCount = Object.keys(schema).filter(function (key) { return !key.startsWith('x-redoc'); }).length;
if (keysCount > 2 || (keysCount === 2 && !schema.description)) {
WarningsService.warn("Other properties are defined at the same level as $ref at \"#" + pointer + "\". " +
'They are IGNORED according to the JsonSchema spec');
}
resolved = this.normalizator.normalize(resolved, $ref);
this._refCouner.exit($ref);
// schema description should always override $ref description
if (schema.description) {
// make a copy of resolved object with updated description, do not globally override the description
resolved = Object.assign({}, resolved);
resolved.description = schema.description;
}
return resolved;
};
return SchemaDereferencer;
}());
export { SchemaDereferencer };
//# sourceMappingURL=schema-normalizer.service.js.map