ng2-json-editor
Version:
Angular2 component for editing large json documents
283 lines • 11.1 kB
JavaScript
/*
* This file is part of ng2-json-editor.
* Copyright (C) 2016 CERN.
*
* ng2-json-editor is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* ng2-json-editor is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ng2-json-editor; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
* In applying this license, CERN does not
* waive the privileges and immunities granted to it by virtue of its status
* as an Intergovernmental Organization or submit itself to any jurisdiction.
*/
import { Injectable } from '@angular/core';
import * as _ from 'lodash';
import { JsonUtilService } from './json-util.service';
import { ComponentTypeService } from './component-type.service';
var SchemaFixerService = (function () {
function SchemaFixerService(jsonUtilService, componentTypeService) {
this.jsonUtilService = jsonUtilService;
this.componentTypeService = componentTypeService;
}
/**
* Fixes schema to be in a format that expected by json-editor
*
* @param schema - json schema
* @param config - schema specific options
* @return - fixed schema
*/
SchemaFixerService.prototype.fixSchema = function (originalSchema, config) {
var schema = _.cloneDeep(originalSchema);
if (config) {
schema = this.enrichSchemaWithConfig(schema, config);
}
schema = this.fixRecursively(schema);
return schema;
};
/**
* Enriches given schema with given configuration objects
* puts config into correct places in schema.
*
* @param schema - json schema
* @param config - schema specific options
*/
SchemaFixerService.prototype.enrichSchemaWithConfig = function (schema, config) {
return _.mergeWith(schema, config, function (currentSchema, currentConfig, key) {
if ((key === 'properties' || key === 'items') && !currentSchema) {
console.warn("config => " + JSON.stringify(currentConfig, function (configKey, value) {
if (typeof value === 'function') {
return 'ƒ()';
}
return value;
}, 2) + " should not be under \"" + key + "\" because schema does not have \"" + key + "\"");
// cancel merge to avoid creating broken json schema
return null;
}
if (currentSchema && key === 'properties') {
var configKeys = Object.keys(currentConfig);
configKeys
.filter(function (configKey) { return !currentSchema[configKey]; })
.forEach(function (wrongConfigKey) {
delete currentConfig[wrongConfigKey];
console.warn(wrongConfigKey);
});
}
});
};
/**
* Applies all fixes to schema recursively
*/
SchemaFixerService.prototype.fixRecursively = function (schema) {
var _this = this;
if (schema.anyOf) {
schema = this.fixAnyOf(schema);
}
else if (schema.allOf) {
schema = this.fixAllOf(schema);
}
if (schema.order) {
schema = this.fixOrder(schema);
}
if (schema.disabled) {
schema = this.fixDisabled(schema);
}
if (schema.isDeleteDisabled) {
schema = this.fixIsDeleteDisabled(schema);
}
if (schema.alwaysShow) {
schema = this.fixAlwaysShow(schema);
}
if (schema.alwaysShowRegExp) {
schema = this.fixAlwaysShowRegExp(schema);
}
// schema fixes must be done above
// recursively call for deeper parts of schema
if (schema.properties) {
Object.keys(schema.properties)
.forEach(function (prop) {
schema.properties[prop] = _this.fixRecursively(schema.properties[prop]);
});
}
else if (schema.items) {
schema.items = this.fixRecursively(schema.items);
}
// fixes that needs above fixes to be done deeply for the current schema
schema.componentType = this.componentTypeService.getComponentType(schema);
return schema;
};
/**
* Fixes disabled config to assign the disabled attribute
* to array items or object properties
*/
SchemaFixerService.prototype.fixDisabled = function (schema) {
if (schema.items) {
schema.items.disabled = true;
}
else if (schema.properties) {
Object.keys(schema.properties)
.forEach(function (prop) {
schema.properties[prop].disabled = true;
});
}
return schema;
};
/**
* Fixes isDeleteDisabled config to assign the isDeleteDisabled attribute
* to array items or object properties
*/
SchemaFixerService.prototype.fixIsDeleteDisabled = function (schema) {
if (schema.items) {
schema.items.isDeleteDisabled = false;
}
else if (schema.properties) {
Object.keys(schema.properties)
.forEach(function (prop) {
schema.properties[prop].isDeleteDisabled = false;
});
}
return schema;
};
/**
* Fixes order config to assign the right priority to properties
*/
SchemaFixerService.prototype.fixOrder = function (schema) {
var order = schema.order;
order.forEach(function (orderKey, index) {
var priority = order.length - index;
if (orderKey in schema.properties) {
schema.properties[orderKey].priority = priority;
}
else {
console.warn(orderKey + " defined in order config does not exist in schema.");
}
});
return schema;
};
/**
* Fixes anyOf schemas with exactly same property structure
* it merges all enum fields in anyOf elements
*/
SchemaFixerService.prototype.fixAnyOf = function (schema) {
var anyOf = schema.anyOf;
// find existence count of all enum properties in anyOf elements
// the reason of this, a field could be enum type for some and not for some other anyOf element
var enumPropCount = {};
anyOf.forEach(function (anyOfElement) {
Object.keys(anyOfElement.properties)
.filter(function (prop) { return anyOfElement.properties[prop].enum; })
.forEach(function (prop) {
if (!enumPropCount[prop]) {
enumPropCount[prop] = 0;
}
enumPropCount[prop]++;
});
});
// combine all enum arrays in anyOf elements
var enums = {};
Object.keys(enumPropCount)
.forEach(function (prop) {
anyOf.forEach(function (anyOfElement) {
if (!enums[prop]) {
enums[prop] = [];
}
var enumValues = anyOfElement.properties[prop].enum;
// check if current field is enum for current anyOf element
if (enumValues) {
enums[prop] = enums[prop].concat(enumValues);
}
});
});
var fixedSchema = anyOf[0];
// shallow cleaning of format and pattern
Object.keys(fixedSchema.properties)
.forEach(function (prop) {
delete fixedSchema.properties[prop].format;
delete fixedSchema.properties[prop].pattern;
});
Object.keys(enumPropCount)
.forEach(function (prop) {
var uniqueEnumValues = Array.from(new Set(enums[prop]));
// if a field enum for all anyOf elements
if (enumPropCount[prop] === anyOf.length) {
// merge all enum values into one
fixedSchema.properties[prop].enum = uniqueEnumValues;
// if a field enum for some of anyOf elements
}
else {
// create a autocomplete config so that it will allow any values
// but autocomplete from enum values from where the field is defined as enum
delete fixedSchema.properties[prop].enum;
fixedSchema.properties[prop].autocompletionConfig = {
source: uniqueEnumValues,
size: 7
};
}
});
// copy disabled attribute inside fixedSchema because it
// is outside anyOf element and is ignored
if (schema.disabled) {
fixedSchema.disabled = true;
}
return fixedSchema;
};
SchemaFixerService.prototype.fixAllOf = function (schema) {
return _.merge.apply(_, [{}].concat(schema.allOf));
};
/**
* Adds keys that matches `alwaysShowRegExp` to `alwaysShow`.
* Passes `alwaysShowRegExp` down to children so that it is applied recursively.
*/
SchemaFixerService.prototype.fixAlwaysShowRegExp = function (schema) {
if (!schema.alwaysShow) {
schema.alwaysShow = [];
}
Object.keys(schema.properties)
.forEach(function (key) {
// pass alwaysShowRegExp down to apply it recursively.
var subSchema = schema.properties[key];
if (subSchema.type === 'object') {
subSchema.alwaysShowRegExp = schema.alwaysShowRegExp;
}
if (key.search(schema.alwaysShowRegExp) > -1) {
schema.alwaysShow.push(key);
}
});
return schema;
};
/**
* Removes alwayShow fields that aren't in the schema.properties
* and warns on console.
*/
SchemaFixerService.prototype.fixAlwaysShow = function (schema) {
var alwaysShow = schema.alwaysShow;
schema.alwaysShow = alwaysShow.filter(function (key) {
if (schema.properties[key]) {
return true;
}
else {
console.warn(key + " is configured as alwaysShow but it is not in " + JSON.stringify(Object.keys(schema.properties)));
}
});
return schema;
};
return SchemaFixerService;
}());
export { SchemaFixerService };
SchemaFixerService.decorators = [
{ type: Injectable },
];
/** @nocollapse */
SchemaFixerService.ctorParameters = function () { return [
{ type: JsonUtilService, },
{ type: ComponentTypeService, },
]; };
//# sourceMappingURL=schema-fixer.service.js.map