2018-05-23 16:02:36 -04:00
|
|
|
import SimpleSchema from 'simpl-schema';
|
|
|
|
|
|
|
|
|
2018-03-26 11:51:08 +09:00
|
|
|
/*
|
|
|
|
|
|
|
|
Convert a nested SimpleSchema schema into a JSON object
|
|
|
|
If flatten = true, will create a flat object instead of nested tree
|
|
|
|
|
|
|
|
*/
|
|
|
|
export const convertSchema = (schema, flatten = false) => {
|
2018-03-26 14:49:05 +09:00
|
|
|
if (schema._schema) {
|
|
|
|
let jsonSchema = {};
|
2018-03-26 11:51:08 +09:00
|
|
|
|
2018-03-26 14:49:05 +09:00
|
|
|
Object.keys(schema._schema).forEach(fieldName => {
|
|
|
|
// exclude array fields
|
|
|
|
if (fieldName.includes('$')) {
|
|
|
|
return;
|
2018-03-26 11:51:08 +09:00
|
|
|
}
|
2018-03-26 14:49:05 +09:00
|
|
|
|
|
|
|
// extract schema
|
|
|
|
jsonSchema[fieldName] = getFieldSchema(fieldName, schema);
|
|
|
|
|
|
|
|
// check for existence of nested schema on corresponding array field
|
2018-05-23 16:02:36 -04:00
|
|
|
const arraySubSchema = getArraySubSchema(fieldName, schema);
|
2018-03-26 14:49:05 +09:00
|
|
|
// if nested schema exists, call convertSchema recursively
|
2018-05-23 16:02:36 -04:00
|
|
|
if (arraySubSchema) {
|
|
|
|
const convertedArraySubSchema = convertSchema(arraySubSchema);
|
2018-03-26 14:49:05 +09:00
|
|
|
if (flatten) {
|
2018-05-23 16:02:36 -04:00
|
|
|
jsonSchema = { ...jsonSchema, ...convertedArraySubSchema };
|
2018-03-26 14:49:05 +09:00
|
|
|
} else {
|
2018-05-23 16:02:36 -04:00
|
|
|
jsonSchema[fieldName].schema = convertedArraySubSchema;
|
2018-03-26 14:49:05 +09:00
|
|
|
}
|
|
|
|
}
|
2018-05-23 16:02:36 -04:00
|
|
|
|
|
|
|
// check if the type of this field is a nested schema
|
|
|
|
const objectSubSchema = getObjectSubSchema(fieldName, schema);
|
|
|
|
if (objectSubSchema) {
|
|
|
|
let convertedObjectSubSchema = convertSchema(objectSubSchema);
|
|
|
|
const mergedSubSchema = mergeSubSchemaWithParent(convertedObjectSubSchema, jsonSchema, fieldName);
|
|
|
|
jsonSchema = { ...jsonSchema, ...mergedSubSchema };
|
|
|
|
delete jsonSchema[fieldName];
|
|
|
|
}
|
2018-03-26 14:49:05 +09:00
|
|
|
});
|
|
|
|
return jsonSchema;
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
2018-03-26 11:51:08 +09:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
Get a JSON object representing a field's schema
|
|
|
|
|
|
|
|
*/
|
|
|
|
export const getFieldSchema = (fieldName, schema) => {
|
|
|
|
let fieldSchema = {};
|
|
|
|
schemaProperties.forEach(property => {
|
2018-03-26 14:49:05 +09:00
|
|
|
const propertyValue = schema.get(fieldName, property);
|
|
|
|
if (propertyValue) {
|
|
|
|
fieldSchema[property] = propertyValue;
|
2018-03-26 11:51:08 +09:00
|
|
|
}
|
|
|
|
});
|
|
|
|
return fieldSchema;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
Given an array field, get its nested schema
|
|
|
|
|
|
|
|
*/
|
2018-05-23 16:02:36 -04:00
|
|
|
export const getArraySubSchema = (fieldName, schema) => {
|
2018-03-26 11:51:08 +09:00
|
|
|
const arrayItemSchema = schema._schema[`${fieldName}.$`];
|
2018-05-23 16:02:36 -04:00
|
|
|
return arrayItemSchema && arrayItemSchema.type.definitions[0].type;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
Given an object field, get its sub schema
|
|
|
|
|
|
|
|
*/
|
|
|
|
export const getObjectSubSchema = (fieldName, schema) => {
|
|
|
|
const objectItemSchema = schema._schema[fieldName].type.definitions[0].type;
|
|
|
|
if (SimpleSchema.isSimpleSchema(objectItemSchema)) {
|
|
|
|
return objectItemSchema;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
Given a subschema, prefixes the field names with the parent's, and merges the parent's values
|
|
|
|
into each child (this way field properties like 'editableBy' and 'group' can be set on the parent
|
|
|
|
for all children, and can still be overridden by children.
|
|
|
|
|
|
|
|
*/
|
|
|
|
export const mergeSubSchemaWithParent = (schema, jsonSchema, parentName) => {
|
|
|
|
const merged = {};
|
|
|
|
for (const key in schema) {
|
|
|
|
merged[`${parentName}.${key}`] = Object.assign({}, jsonSchema[parentName], schema[key]);
|
|
|
|
}
|
|
|
|
return merged;
|
2018-03-26 11:51:08 +09:00
|
|
|
};
|
|
|
|
|
|
|
|
export const schemaProperties = [
|
|
|
|
'type',
|
|
|
|
'label',
|
|
|
|
'optional',
|
|
|
|
'required',
|
|
|
|
'min',
|
|
|
|
'max',
|
|
|
|
'exclusiveMin',
|
|
|
|
'exclusiveMax',
|
|
|
|
'minCount',
|
|
|
|
'maxCount',
|
|
|
|
'allowedValues',
|
|
|
|
'regEx',
|
|
|
|
'blackbox',
|
|
|
|
'trim',
|
|
|
|
'custom',
|
|
|
|
'defaultValue',
|
|
|
|
'autoValue',
|
|
|
|
'hidden', // hidden: true means the field is never shown in a form no matter what
|
|
|
|
'mustComplete', // mustComplete: true means the field is required to have a complete profile
|
|
|
|
'profile', // profile: true means the field is shown on user profiles
|
|
|
|
'form', // form placeholder
|
2018-04-14 18:09:35 +09:00
|
|
|
'inputProperties', // form placeholder
|
2018-03-26 11:51:08 +09:00
|
|
|
'control', // SmartForm control (String or React component)
|
2018-04-14 18:09:35 +09:00
|
|
|
'input', // SmartForm control (String or React component)
|
|
|
|
'autoform', // legacy form placeholder; backward compatibility (not used anymore)
|
2018-03-26 11:51:08 +09:00
|
|
|
'order', // position in the form
|
|
|
|
'group', // form fieldset group
|
|
|
|
'onInsert', // field insert callback
|
|
|
|
'onEdit', // field edit callback
|
|
|
|
'onRemove', // field remove callback
|
|
|
|
'viewableBy',
|
|
|
|
'insertableBy',
|
|
|
|
'editableBy',
|
|
|
|
'resolveAs',
|
|
|
|
'searchable',
|
|
|
|
'description',
|
2018-03-26 14:27:45 +09:00
|
|
|
'beforeComponent',
|
|
|
|
'afterComponent',
|
|
|
|
'placeholder',
|
|
|
|
'options',
|
|
|
|
'query',
|
|
|
|
'fieldProperties',
|
|
|
|
];
|
|
|
|
|
|
|
|
export const formProperties = [
|
|
|
|
'optional',
|
|
|
|
'required',
|
|
|
|
'min',
|
|
|
|
'max',
|
|
|
|
'exclusiveMin',
|
|
|
|
'exclusiveMax',
|
|
|
|
'minCount',
|
|
|
|
'maxCount',
|
|
|
|
'allowedValues',
|
|
|
|
'regEx',
|
|
|
|
'blackbox',
|
|
|
|
'trim',
|
|
|
|
'custom',
|
|
|
|
'defaultValue',
|
|
|
|
'autoValue',
|
|
|
|
'mustComplete', // mustComplete: true means the field is required to have a complete profile
|
|
|
|
'form', // form placeholder
|
2018-04-14 18:09:35 +09:00
|
|
|
'inputProperties', // form placeholder
|
2018-03-26 11:51:08 +09:00
|
|
|
'control', // SmartForm control (String or React component)
|
2018-04-14 18:09:35 +09:00
|
|
|
'input', // SmartForm control (String or React component)
|
2018-03-26 14:27:45 +09:00
|
|
|
'order', // position in the form
|
2018-03-26 14:49:05 +09:00
|
|
|
'group', // form fieldset group
|
2018-03-26 14:27:45 +09:00
|
|
|
'description',
|
2018-03-26 11:51:08 +09:00
|
|
|
'beforeComponent',
|
|
|
|
'afterComponent',
|
|
|
|
'placeholder',
|
|
|
|
'options',
|
|
|
|
'query',
|
|
|
|
'fieldProperties',
|
2018-03-26 14:49:05 +09:00
|
|
|
];
|