2015-11-19 00:23:18 +03:00
|
|
|
'use strict';
|
|
|
|
|
2015-12-14 18:20:40 +03:00
|
|
|
import {ElementRef} from 'angular2/core';
|
2016-02-10 14:19:50 +03:00
|
|
|
|
|
|
|
import {RedocComponent, BaseComponent, SchemaManager} from '../base';
|
|
|
|
import {Tabs, Tab} from '../../common/components/Tabs/tabs';
|
2015-11-29 18:06:08 +03:00
|
|
|
import JsonPointer from '../../utils/JsonPointer';
|
2015-11-19 00:23:18 +03:00
|
|
|
|
|
|
|
@RedocComponent({
|
|
|
|
selector: 'json-schema',
|
|
|
|
templateUrl: './lib/components/JsonSchema/json-schema.html',
|
|
|
|
styleUrls: ['./lib/components/JsonSchema/json-schema.css'],
|
2016-01-09 23:34:44 +03:00
|
|
|
directives: [JsonSchema, Tabs, Tab],
|
|
|
|
inputs: ['isArray', 'final']
|
2015-11-19 00:23:18 +03:00
|
|
|
})
|
2016-02-10 14:19:50 +03:00
|
|
|
@Reflect.metadata('parameters', [[SchemaManager], [ElementRef]])
|
2015-11-19 00:23:18 +03:00
|
|
|
export default class JsonSchema extends BaseComponent {
|
|
|
|
constructor(schemaMgr, elementRef) {
|
|
|
|
super(schemaMgr);
|
2016-02-10 16:48:07 +03:00
|
|
|
this.$element = elementRef.nativeElement;
|
2016-01-09 23:34:44 +03:00
|
|
|
this.final = false;
|
2015-11-19 00:23:18 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
prepareModel() {
|
|
|
|
this.data = {};
|
|
|
|
this.data.properties = [];
|
2016-01-09 23:34:44 +03:00
|
|
|
this.data.derived = [];
|
2015-11-29 13:04:28 +03:00
|
|
|
|
|
|
|
if (!this.componentSchema) {
|
2016-01-09 18:16:43 +03:00
|
|
|
throw new Error(`Can't load component schema at ${this.pointer}`);
|
2015-11-19 00:23:18 +03:00
|
|
|
}
|
2015-11-28 01:44:35 +03:00
|
|
|
|
2015-11-29 13:04:28 +03:00
|
|
|
this.dereference();
|
|
|
|
let schema = this.componentSchema;
|
|
|
|
|
2015-11-28 01:44:35 +03:00
|
|
|
if (schema.type === 'array') {
|
2015-11-29 13:04:28 +03:00
|
|
|
this.isArray = true;
|
2016-01-17 00:24:05 +03:00
|
|
|
if (schema._pointer) {
|
|
|
|
this.pointer = JsonPointer.join(schema._pointer, 'items');
|
|
|
|
}
|
2015-11-28 01:44:35 +03:00
|
|
|
schema = schema.items;
|
|
|
|
}
|
2016-01-09 23:34:44 +03:00
|
|
|
let normPtr = schema._pointer || this.pointer;
|
|
|
|
let derived = this.schemaMgr.findDerivedDefinitions( normPtr );
|
|
|
|
if (!this.final && derived.length) {
|
|
|
|
this.data.derived = derived;
|
|
|
|
this.data.discriminator = schema.discriminator;
|
|
|
|
}
|
|
|
|
|
2016-01-10 18:29:35 +03:00
|
|
|
this.joinAllOf(schema, {omitParent: true});
|
2016-01-17 00:24:05 +03:00
|
|
|
|
2015-11-29 13:04:28 +03:00
|
|
|
if (schema.type !== 'object') {
|
2015-11-29 18:02:54 +03:00
|
|
|
this.isTrivial = true;
|
|
|
|
this._displayType = schema.type;
|
|
|
|
if (schema.format) this._displayType = `${this.displayType} <${schema.format}>`;
|
2015-11-29 13:04:28 +03:00
|
|
|
return;
|
2015-11-28 01:44:35 +03:00
|
|
|
}
|
|
|
|
|
2015-11-29 13:04:28 +03:00
|
|
|
this.pointer = schema._pointer || this.pointer;
|
|
|
|
|
|
|
|
this.requiredMap = {};
|
2016-03-02 07:56:09 +03:00
|
|
|
if (this.componentSchema.required) {
|
|
|
|
this.componentSchema.required.forEach(prop => this.requiredMap[prop] = true);
|
2015-11-29 13:04:28 +03:00
|
|
|
}
|
2015-11-28 01:44:35 +03:00
|
|
|
|
2016-01-10 18:29:35 +03:00
|
|
|
let discriminatorFieldIdx = -1;
|
|
|
|
let props = Object.keys(schema.properties).map((prop, idx) => {
|
2015-11-19 00:23:18 +03:00
|
|
|
let propData = schema.properties[prop];
|
2016-02-04 12:49:00 +03:00
|
|
|
let propPointer = JsonPointer.join(this.pointer, ['properties', prop]);
|
|
|
|
propData = JsonSchema.injectPropData(propData, prop, propPointer, this.requiredMap, schema);
|
2016-01-10 18:29:35 +03:00
|
|
|
if (propData.isDiscriminator) discriminatorFieldIdx = idx;
|
2015-11-19 00:23:18 +03:00
|
|
|
return propData;
|
2015-11-19 00:51:19 +03:00
|
|
|
});
|
2016-01-10 18:29:35 +03:00
|
|
|
// Move discriminator field to the end of properties list
|
|
|
|
if (discriminatorFieldIdx > -1) {
|
|
|
|
let discrProp = props.splice(discriminatorFieldIdx, 1);
|
|
|
|
props.push(discrProp[0]);
|
|
|
|
}
|
2015-11-19 00:23:18 +03:00
|
|
|
this.data.properties = props;
|
|
|
|
}
|
|
|
|
|
2016-02-04 12:49:00 +03:00
|
|
|
static injectPropData(propData, propName, propPointer, requiredMap, schema) {
|
2016-02-06 18:00:31 +03:00
|
|
|
let propEnum;
|
|
|
|
|
2016-01-23 17:29:34 +03:00
|
|
|
propData = Object.assign({}, propData);
|
2016-02-04 12:49:00 +03:00
|
|
|
propData._name = propName;
|
|
|
|
propData.required = propData.required || (requiredMap && requiredMap[propName]);
|
2015-11-28 01:44:35 +03:00
|
|
|
propData._displayType = propData.type;
|
2016-02-04 12:49:00 +03:00
|
|
|
propData.isDiscriminator = (schema && schema.discriminator === propName);
|
2016-02-06 18:00:31 +03:00
|
|
|
propEnum = propData.enum;
|
2015-11-19 00:23:18 +03:00
|
|
|
if (propData.type === 'array') {
|
|
|
|
let itemType = propData.items.type;
|
2015-11-29 18:02:54 +03:00
|
|
|
let itemFormat = propData.items.format;
|
2016-02-06 18:00:31 +03:00
|
|
|
propEnum = propData.items.enum;
|
2016-01-16 01:44:10 +03:00
|
|
|
if (itemType === 'object' || !itemType) {
|
2015-11-19 00:51:19 +03:00
|
|
|
itemType = propData.items.title || 'object';
|
2016-02-04 12:49:00 +03:00
|
|
|
propData._pointer = propData.items._pointer
|
|
|
|
|| JsonPointer.join(propPointer, ['items']);
|
2015-11-19 00:51:19 +03:00
|
|
|
}
|
2016-01-23 17:29:34 +03:00
|
|
|
propData._displayType = `${itemType}`;
|
2015-11-29 18:02:54 +03:00
|
|
|
propData.format = itemFormat;
|
2015-11-28 01:44:35 +03:00
|
|
|
propData._isArray = true;
|
2016-01-23 17:29:34 +03:00
|
|
|
propData.type = 'array ' + propData.items.type;
|
2016-03-13 02:54:53 +03:00
|
|
|
} else if (propData.type === 'object' && propData.properties) {
|
2015-11-28 01:44:35 +03:00
|
|
|
propData._displayType = propData.title || 'object';
|
2016-03-09 01:28:55 +03:00
|
|
|
} else if (!propData.type) {
|
2016-01-23 17:01:10 +03:00
|
|
|
propData._displayType = '< * >';
|
|
|
|
propData._displayTypeHint = 'This field may contain data of any type';
|
2016-03-09 01:28:55 +03:00
|
|
|
} else {
|
2016-03-13 02:54:53 +03:00
|
|
|
// here we are sure that property has simple type (integer, string, object withou properties)
|
2016-03-09 01:28:55 +03:00
|
|
|
// delete pointer for simple types to not show it as subschema
|
|
|
|
if (propData._pointer) {
|
|
|
|
propData._pointer = undefined;
|
|
|
|
propData._displayType = propData.title ? `${propData.title} (${propData.type})` : propData.type;
|
|
|
|
}
|
2016-01-23 17:01:10 +03:00
|
|
|
}
|
|
|
|
|
2015-11-29 18:02:54 +03:00
|
|
|
if (propData.format) propData._displayFormat = `<${propData.format}>`;
|
2016-02-06 18:00:31 +03:00
|
|
|
if (propEnum) {
|
|
|
|
propData.enum = propEnum.map((value) => {
|
|
|
|
return {val: value, type: typeof value};
|
|
|
|
});
|
|
|
|
}
|
2016-01-23 17:29:34 +03:00
|
|
|
|
|
|
|
return propData;
|
2015-11-19 00:23:18 +03:00
|
|
|
}
|
|
|
|
|
2016-02-06 19:02:10 +03:00
|
|
|
ngAfterViewInit() {
|
2016-02-07 17:11:15 +03:00
|
|
|
// adjust widht only on parent level
|
2016-02-10 16:48:07 +03:00
|
|
|
let $el = this.$element.parentElement;
|
|
|
|
while($el && $el.tagName !== 'JSON-SCHEMA' && $el.tagName !== 'REDOC') {
|
|
|
|
$el = $el.parentElement;
|
2016-02-07 17:11:15 +03:00
|
|
|
}
|
2016-02-10 16:48:07 +03:00
|
|
|
if ($el && $el.tagName === 'REDOC' ) {
|
2016-02-07 17:11:15 +03:00
|
|
|
this.adjustNameColumnWidth();
|
|
|
|
}
|
2015-11-19 00:23:18 +03:00
|
|
|
}
|
2016-02-10 16:48:07 +03:00
|
|
|
|
|
|
|
adjustNameColumnWidth() {
|
|
|
|
// TODO handle internal schemes differently
|
|
|
|
|
|
|
|
let names = [].slice.call(this.$element.querySelectorAll('.param-name-content'));
|
2016-02-28 00:30:46 +03:00
|
|
|
let widths = names.map(el => el.offsetWidth);
|
2016-02-10 16:48:07 +03:00
|
|
|
let maxWidth = Math.max(...widths);
|
|
|
|
if (!maxWidth) return;
|
|
|
|
names.forEach(el => {
|
|
|
|
el.parentNode.style.minWidth = maxWidth + 'px';
|
|
|
|
});
|
|
|
|
|
|
|
|
let discrValues = this.$element.querySelector('tabs ul');
|
|
|
|
if (discrValues) discrValues.style.paddingLeft = maxWidth + 'px';
|
|
|
|
}
|
2015-11-19 00:23:18 +03:00
|
|
|
}
|