angular2-json-schema-form
Version:
Angular 2 JSON Schema Form builder
450 lines • 20.1 kB
JavaScript
"use strict";
var _ = require("lodash");
var validator_functions_1 = require("./validator.functions");
var utility_functions_1 = require("./utility.functions");
var jsonpointer_functions_1 = require("./jsonpointer.functions");
var json_validators_1 = require("./json.validators");
function buildSchemaFromLayout(layout) {
return;
}
exports.buildSchemaFromLayout = buildSchemaFromLayout;
function buildSchemaFromData(data, requireAllFields, isRoot) {
if (requireAllFields === void 0) { requireAllFields = false; }
if (isRoot === void 0) { isRoot = true; }
var newSchema = {};
if (isRoot) {
newSchema.$schema = 'http://json-schema.org/draft-04/schema#';
}
var getFieldType = function (value) {
var fieldType = validator_functions_1.getType(value, 'strict');
if (fieldType === 'integer') {
return 'number';
}
if (fieldType === 'null') {
return 'string';
}
return fieldType;
};
newSchema.type = getFieldType(data);
if (newSchema.type === 'object') {
newSchema.properties = {};
if (requireAllFields) {
newSchema.required = [];
}
for (var _i = 0, _a = Object.keys(data); _i < _a.length; _i++) {
var key = _a[_i];
newSchema.properties[key] = buildSchemaFromData(data[key], requireAllFields, false);
if (requireAllFields) {
newSchema.required.push(key);
}
}
}
else if (newSchema.type === 'array') {
var itemTypes = data.map(getFieldType).reduce(function (types, type) { return types.concat(types.indexOf(type) === -1 ? type : []); }, []);
var buildSubSchemaFromData = function (value) { return buildSchemaFromData(value, requireAllFields, false); };
if (itemTypes.length === 1) {
newSchema.items = data.map(buildSubSchemaFromData).reduce(function (combined, item) { return Object.assign(combined, item); }, {});
}
else {
newSchema.items = data.map(buildSubSchemaFromData);
}
if (requireAllFields) {
newSchema.minItems = 1;
}
}
return newSchema;
}
exports.buildSchemaFromData = buildSchemaFromData;
function getFromSchema(schema, dataPointer, returnContainer) {
if (returnContainer === void 0) { returnContainer = false; }
var dataPointerArray = jsonpointer_functions_1.JsonPointer.parse(dataPointer);
var subSchema = schema;
if (dataPointerArray === null) {
console.error('getFromSchema error: Invalid JSON Pointer: ' + dataPointer);
return null;
}
var l = returnContainer ? dataPointerArray.length - 1 : dataPointerArray.length;
for (var i = 0; i < l; ++i) {
var parentSchema = subSchema;
var key = dataPointerArray[i];
var subSchemaArray = false;
var subSchemaObject = false;
if (typeof subSchema !== 'object') {
console.error('getFromSchema error: Unable to find "' + key +
'" key in schema.');
console.error(schema);
console.error(dataPointer);
return null;
}
if (subSchema['type'] === 'array' && subSchema.hasOwnProperty('items') &&
(!isNaN(key) || key === '-')) {
subSchema = subSchema['items'];
subSchemaArray = true;
}
if (subSchema['type'] === 'object' && subSchema.hasOwnProperty('properties')) {
subSchema = subSchema['properties'];
subSchemaObject = true;
}
if (!subSchemaArray || !subSchemaObject) {
if (subSchemaArray && key === '-') {
subSchema = (parentSchema.hasOwnProperty('additionalItems')) ?
parentSchema.additionalItems : {};
}
else if (typeof subSchema === 'object' && subSchema.hasOwnProperty(key)) {
subSchema = subSchema[key];
}
else {
console.error('getFromSchema error: Unable to find "' + key +
'" item in schema.');
console.error(schema);
console.error(dataPointer);
return;
}
}
}
return subSchema;
}
exports.getFromSchema = getFromSchema;
function getSchemaReference(schema, reference, schemaRefLibrary, recursiveRefMap) {
if (schemaRefLibrary === void 0) { schemaRefLibrary = null; }
if (recursiveRefMap === void 0) { recursiveRefMap = null; }
var schemaPointer;
var newSchema;
if (validator_functions_1.isArray(reference) || typeof reference === 'string') {
schemaPointer = jsonpointer_functions_1.JsonPointer.compile(reference);
}
else if (validator_functions_1.isObject(reference) && Object.keys(reference).length === 1 &&
reference.hasOwnProperty('$ref') && typeof reference.$ref === 'string') {
schemaPointer = jsonpointer_functions_1.JsonPointer.compile(reference.$ref);
}
else {
console.error('getSchemaReference error: ' +
'reference must be a JSON Pointer or $ref link');
console.error(reference);
return reference;
}
if (recursiveRefMap) {
schemaPointer = resolveRecursiveReferences(schemaPointer, recursiveRefMap);
}
if (schemaPointer === '') {
return _.cloneDeep(schema);
}
else if (schemaRefLibrary && schemaRefLibrary.hasOwnProperty(schemaPointer)) {
return _.cloneDeep(schemaRefLibrary[schemaPointer]);
}
else {
newSchema = _.cloneDeep(jsonpointer_functions_1.JsonPointer.get(schema, schemaPointer));
if (validator_functions_1.isObject(newSchema) && Object.keys(newSchema).length === 1 &&
utility_functions_1.hasOwn(newSchema, 'allOf') && validator_functions_1.isArray(newSchema.allOf)) {
newSchema = newSchema.allOf
.map(function (object) { return getSchemaReference(schema, object, schemaRefLibrary, recursiveRefMap); })
.reduce(function (schema1, schema2) { return Object.assign(schema1, schema2); }, {});
}
if (schemaRefLibrary) {
schemaRefLibrary[schemaPointer] = _.cloneDeep(newSchema);
}
return newSchema;
}
}
exports.getSchemaReference = getSchemaReference;
function resolveRecursiveReferences(pointer, recursiveRefMap, arrayMap) {
if (arrayMap === void 0) { arrayMap = new Map(); }
var genericPointer = jsonpointer_functions_1.JsonPointer.toGenericPointer(jsonpointer_functions_1.JsonPointer.compile(pointer), arrayMap);
var possibleReferences = true;
var previousPointerValues = [];
var catchCircularLinks = function (newPointer) {
if (previousPointerValues.indexOf(newPointer) !== -1) {
console.error('resolveRecursiveReferences error: ' +
'recursive reference map contains circular links');
console.error(recursiveRefMap);
return;
}
previousPointerValues.push(genericPointer);
return newPointer;
};
while (possibleReferences) {
possibleReferences = false;
recursiveRefMap.forEach(function (toPointer, fromPointer) {
if (jsonpointer_functions_1.JsonPointer.isSubPointer(toPointer, fromPointer)) {
while (jsonpointer_functions_1.JsonPointer.isSubPointer(fromPointer, genericPointer)) {
genericPointer = catchCircularLinks(jsonpointer_functions_1.JsonPointer.toGenericPointer(toPointer + genericPointer.slice(fromPointer.length), arrayMap));
possibleReferences = true;
}
}
});
}
return genericPointer;
}
exports.resolveRecursiveReferences = resolveRecursiveReferences;
function getInputType(schema, layoutNode) {
if (layoutNode === void 0) { layoutNode = null; }
var controlType = jsonpointer_functions_1.JsonPointer.getFirst([
[schema, '/x-schema-form/type'],
[schema, '/x-schema-form/widget/component'],
[schema, '/x-schema-form/widget'],
[schema, '/widget/component'],
[schema, '/widget']
]);
if (validator_functions_1.isString(controlType)) {
return checkInlineType(controlType, schema, layoutNode);
}
var schemaType = schema.type;
if (schemaType) {
if (validator_functions_1.isArray(schemaType)) {
if (validator_functions_1.inArray('object', schemaType) && utility_functions_1.hasOwn(schema, 'properties')) {
schemaType = 'object';
}
else if (validator_functions_1.inArray('array', schemaType) && utility_functions_1.hasOwn(schema, 'items')) {
schemaType = 'array';
}
else if (validator_functions_1.inArray('string', schemaType)) {
schemaType = 'string';
}
else if (validator_functions_1.inArray('number', schemaType)) {
schemaType = 'number';
}
else if (validator_functions_1.inArray('integer', schemaType)) {
schemaType = 'integer';
}
else if (validator_functions_1.inArray('boolean', schemaType)) {
schemaType = 'boolean';
}
else {
schemaType = 'null';
}
}
if (schemaType === 'boolean') {
return 'checkbox';
}
if (schemaType === 'object') {
if (utility_functions_1.hasOwn(schema, 'properties')) {
return 'fieldset';
}
if (utility_functions_1.hasOwn(schema, '$ref') ||
jsonpointer_functions_1.JsonPointer.has(schema, '/additionalProperties/$ref')) {
return '$ref';
}
return null;
}
if (schemaType === 'array') {
var itemsObject = jsonpointer_functions_1.JsonPointer.getFirst([
[schema, '/items'],
[schema, '/additionalItems']
]);
if (!itemsObject) {
return null;
}
if (utility_functions_1.hasOwn(itemsObject, 'enum')) {
return checkInlineType('checkboxes', schema, layoutNode);
}
else {
return 'array';
}
}
if (schemaType === 'null') {
return 'hidden';
}
if (utility_functions_1.hasOwn(schema, 'enum')) {
return 'select';
}
if (schemaType === 'number' || schemaType === 'integer') {
if (utility_functions_1.hasOwn(schema, 'maximum') && utility_functions_1.hasOwn(schema, 'minimum') &&
(schemaType === 'integer' || utility_functions_1.hasOwn(schema, 'multipleOf'))) {
return 'range';
}
return schemaType;
}
if (schemaType === 'string') {
if (utility_functions_1.hasOwn(schema, 'format')) {
if (schema.format === 'color') {
return 'color';
}
if (schema.format === 'date') {
return 'date';
}
if (schema.format === 'date-time') {
return 'datetime-local';
}
if (schema.format === 'email') {
return 'email';
}
if (schema.format === 'uri') {
return 'url';
}
}
return 'text';
}
}
if (utility_functions_1.hasOwn(schema, '$ref')) {
return '$ref';
}
return 'text';
}
exports.getInputType = getInputType;
function checkInlineType(controlType, schema, layoutNode) {
if (layoutNode === void 0) { layoutNode = null; }
if (!validator_functions_1.isString(controlType) || (controlType.slice(0, 8) !== 'checkbox' && controlType.slice(0, 5) !== 'radio')) {
return controlType;
}
if (jsonpointer_functions_1.JsonPointer.getFirst([
[layoutNode, '/inline'],
[layoutNode, '/options/inline'],
[schema, '/inline'],
[schema, '/x-schema-form/inline'],
[schema, '/x-schema-form/options/inline'],
[schema, '/x-schema-form/widget/inline'],
[schema, '/x-schema-form/widget/component/inline'],
[schema, '/x-schema-form/widget/component/options/inline'],
[schema, '/widget/inline'],
[schema, '/widget/component/inline'],
[schema, '/widget/component/options/inline'],
]) === true) {
return controlType.slice(0, 5) === 'radio' ?
'radios-inline' : 'checkboxes-inline';
}
else {
return controlType;
}
}
exports.checkInlineType = checkInlineType;
function isInputRequired(schema, pointer) {
if (!validator_functions_1.isObject(schema)) {
console.error('isInputRequired error: Input schema must be an object.');
return false;
}
var listPointerArray = jsonpointer_functions_1.JsonPointer.parse(pointer);
if (validator_functions_1.isArray(listPointerArray) && listPointerArray.length) {
var keyName = listPointerArray.pop();
var requiredList = void 0;
if (listPointerArray.length) {
if (listPointerArray[listPointerArray.length - 1] === '-') {
requiredList = jsonpointer_functions_1.JsonPointer.get(schema, listPointerArray.slice(-1).concat(['items', 'required']));
}
else {
requiredList = jsonpointer_functions_1.JsonPointer.get(schema, listPointerArray.concat('required'));
}
}
else {
requiredList = schema['required'];
}
if (validator_functions_1.isArray(requiredList)) {
return requiredList.indexOf(keyName) !== -1;
}
}
return false;
}
exports.isInputRequired = isInputRequired;
;
function updateInputOptions(layoutNode, schema, jsf) {
if (!validator_functions_1.isObject(layoutNode)) {
return;
}
var templatePointer = jsonpointer_functions_1.JsonPointer.get(jsf, ['dataMap', layoutNode.dataPointer, 'templatePointer']);
Object.keys(layoutNode).forEach(function (option) {
if (option !== 'type' && validator_functions_1.isFunction(json_validators_1.JsonValidators[option]) && (!utility_functions_1.hasOwn(schema, option) || (schema[option] !== layoutNode[option] &&
!(option.slice(0, 3) === 'min' && schema[option] < layoutNode[option]) &&
!(option.slice(0, 3) === 'max' && schema[option] > layoutNode[option])))) {
var validatorPointer = templatePointer + '/validators/' + option;
jsf.formGroupTemplate = jsonpointer_functions_1.JsonPointer.set(jsf.formGroupTemplate, validatorPointer, [layoutNode[option]]);
}
});
var newOptions = {};
var fixUiKeys = function (key) { return key.slice(0, 3) === 'ui:' ? key.slice(3) : key; };
utility_functions_1.mergeFilteredObject(newOptions, jsf.globalOptions.formDefaults, [], fixUiKeys);
if (jsonpointer_functions_1.JsonPointer.has(schema, '/items/enum')) {
newOptions.enum = schema.items.enum;
}
if (jsonpointer_functions_1.JsonPointer.has(schema, '/items/titleMap')) {
newOptions.enum = schema.items.titleMap;
}
utility_functions_1.mergeFilteredObject(newOptions, jsonpointer_functions_1.JsonPointer.get(schema, '/ui:widget/options'), [], fixUiKeys);
utility_functions_1.mergeFilteredObject(newOptions, jsonpointer_functions_1.JsonPointer.get(schema, '/ui:widget'), [], fixUiKeys);
utility_functions_1.mergeFilteredObject(newOptions, schema, ['properties', 'items', 'required',
'type', 'x-schema-form', '$ref'], fixUiKeys);
utility_functions_1.mergeFilteredObject(newOptions, jsonpointer_functions_1.JsonPointer.get(schema, '/x-schema-form/options'), [], fixUiKeys);
utility_functions_1.mergeFilteredObject(newOptions, jsonpointer_functions_1.JsonPointer.get(schema, '/x-schema-form'), ['items', 'options'], fixUiKeys);
utility_functions_1.mergeFilteredObject(newOptions, layoutNode, ['arrayItem', 'dataPointer',
'dataType', 'items', 'layoutPointer', 'listItems', 'name', 'options',
'tupleItems', 'type', 'widget', '_id', '$ref'], fixUiKeys);
utility_functions_1.mergeFilteredObject(newOptions, layoutNode.options, [], fixUiKeys);
layoutNode.options = newOptions;
if (schema.type === 'integer' && !validator_functions_1.hasValue(layoutNode.options.multipleOf)) {
layoutNode.options.multipleOf = 1;
}
if (jsonpointer_functions_1.JsonPointer.has(newOptions, '/autocomplete/source')) {
newOptions.typeahead = newOptions.autocomplete;
}
else if (jsonpointer_functions_1.JsonPointer.has(newOptions, '/tagsinput/source')) {
newOptions.typeahead = newOptions.tagsinput;
}
else if (jsonpointer_functions_1.JsonPointer.has(newOptions, '/tagsinput/typeahead/source')) {
newOptions.typeahead = newOptions.tagsinput.typeahead;
}
if (templatePointer && schema.type !== 'array' && schema.type !== 'object') {
var layoutNodeValue = jsonpointer_functions_1.JsonPointer.getFirst([
[jsf.defaultValues, layoutNode.dataPointer],
[layoutNode, '/value'],
[layoutNode, '/default']
]);
var templateValue = jsonpointer_functions_1.JsonPointer.get(jsf.formGroupTemplate, templatePointer + '/value/value');
if (validator_functions_1.hasValue(layoutNodeValue) && layoutNodeValue !== templateValue) {
jsf.formGroupTemplate = jsonpointer_functions_1.JsonPointer.set(jsf.formGroupTemplate, templatePointer + '/value/value', layoutNodeValue);
}
delete layoutNode.value;
delete layoutNode.default;
}
}
exports.updateInputOptions = updateInputOptions;
function getControlValidators(schema) {
if (!validator_functions_1.isObject(schema)) {
return null;
}
var validators = {};
if (utility_functions_1.hasOwn(schema, 'type')) {
switch (schema.type) {
case 'string':
utility_functions_1.forEach(['pattern', 'format', 'minLength', 'maxLength'], function (prop) {
if (utility_functions_1.hasOwn(schema, prop)) {
validators[prop] = [schema[prop]];
}
});
break;
case 'number':
case 'integer':
utility_functions_1.forEach(['Minimum', 'Maximum'], function (Limit) {
var eLimit = 'exclusive' + Limit;
var limit = Limit.toLowerCase();
if (utility_functions_1.hasOwn(schema, limit)) {
var exclusive = utility_functions_1.hasOwn(schema, eLimit) && schema[eLimit] === true;
validators[limit] = [schema[limit], exclusive];
}
});
utility_functions_1.forEach(['multipleOf', 'type'], function (prop) {
if (utility_functions_1.hasOwn(schema, prop)) {
validators[prop] = [schema[prop]];
}
});
break;
case 'object':
utility_functions_1.forEach(['minProperties', 'maxProperties', 'dependencies'], function (prop) {
if (utility_functions_1.hasOwn(schema, prop)) {
validators[prop] = [schema[prop]];
}
});
break;
case 'array':
utility_functions_1.forEach(['minItems', 'maxItems', 'uniqueItems'], function (prop) {
if (utility_functions_1.hasOwn(schema, prop)) {
validators[prop] = [schema[prop]];
}
});
break;
}
}
if (utility_functions_1.hasOwn(schema, 'enum')) {
validators['enum'] = [schema['enum']];
}
return validators;
}
exports.getControlValidators = getControlValidators;
//# sourceMappingURL=json-schema.functions.js.map