Last active
August 29, 2015 14:26
-
-
Save morlay/9cb4a83dd36ac02b3c1f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import isFunction from 'lodash.isFunction'; | |
import isArray from 'lodash.isArray'; | |
import Immutable from 'immutable'; | |
import isTypeObject from './isTypeObject'; | |
import isTypeArray from './isTypeArray'; | |
import SchemaRecord from './../models/SchemaRecord'; | |
export default function completeSchema(schema) { | |
schema = schema.asMutable(); | |
if (isTypeObject(schema)) { | |
return schema.update('properties', (schemaProps)=> { | |
return schemaProps.map(updateSchemaItem); | |
} | |
); | |
} | |
function updateSchemaItem(schemaItem) { | |
if (isTypeObject(schemaItem)) { | |
const factory = schemaItem.get('factory'); | |
return Immutable.fromJS({ | |
factory: isFunction(factory) ? factory : SchemaRecord.createFactory(SchemaRecord(schemaItem.toJS())) | |
}); | |
} | |
if (isTypeArray(schemaItem)) { | |
const isItemTypeObject = isTypeObject(schemaItem.get('items')); | |
if (isItemTypeObject) { | |
schemaItem = schemaItem.update('items', updateSchemaItem); | |
} | |
return schemaItem.set('factory', schemaListFactory(schemaItem, isItemTypeObject)); | |
} | |
return schemaItem; | |
} | |
function schemaListFactory(arraySchema = {}, isItemTypeObject = false) { | |
return (values)=> { | |
if (!(values instanceof Immutable.List)) { | |
values = Immutable.List(isArray(values) ? values : undefined); | |
} | |
return values.update((list)=> { | |
return list.map((listItem)=> { | |
if (isItemTypeObject) { | |
return arraySchema.getIn(['items', 'factory'])(listItem); | |
} | |
return listItem; | |
}); | |
}); | |
}; | |
} | |
return schema; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import immutable from 'immutable'; | |
export default function isTypeArray(schema = {}) { | |
return immutable.Map.isMap(schema.get('items')); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import immutable from 'immutable'; | |
export default function isTypeObject(schema = {}) { | |
return immutable.Map.isMap(schema.get('properties')); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Immutable from 'immutable'; | |
import _ from 'lodash' | |
import jsen from 'jsen' | |
import isTypeArray from './../libs/isTypeArray'; | |
import updateData from './../libs/updateData'; | |
import completeSchema from './../libs/completeSchema'; | |
function SchemaRecord(schema = {}) { | |
if (!(this instanceof SchemaRecord)) { | |
return new SchemaRecord(schema); | |
} | |
schema = Immutable.fromJS(schema); | |
schema = completeSchema(schema); | |
const DefinedRecord = Immutable.Record(updateData(schema), schema.id); | |
function SchemaRecordType(values = {}) { | |
DefinedRecord.call(this, updateData(schema, values)); | |
} | |
SchemaRecordType.prototype = Object.create(DefinedRecord.prototype); | |
SchemaRecordType.prototype.constructor = SchemaRecordType; | |
SchemaRecordType.prototype._factories = schema.get('properties') | |
.map((schemaItem)=> { | |
return schemaItem.get('factory', null); | |
}) | |
.toObject(); | |
SchemaRecordType.getSchema = SchemaRecordType.prototype.getSchema = function () { | |
return schema; | |
}; | |
SchemaRecordType.setSchema = SchemaRecordType.prototype.setSchema = function (newSchema) { | |
schema = schema.merge(newSchema); | |
}; | |
SchemaRecordType.createFactory = SchemaRecordType.prototype.createFactory = function (Model) { | |
if (new Model() instanceof SchemaRecordType) { | |
schema = schema.merge({'factory': SchemaRecord.createFactory(Model)}); | |
} | |
}; | |
SchemaRecordType.prototype.set = function (key, val) { | |
const factories = this._factories; | |
const factory = factories && factories[key]; | |
return Object.getPrototypeOf(SchemaRecordType.prototype).set.call(this, key, factory ? factory(val) : val); | |
}; | |
SchemaRecordType.getMeta = SchemaRecordType.prototype.getMeta = function (key) { | |
return getMetaFromSchema(schema, key); | |
}; | |
SchemaRecordType.getMetaIn = SchemaRecordType.prototype.getMetaIn = function (keyPath) { | |
if (keyPath) { | |
keyPath = [].concat(keyPath); | |
return keyPath.reduce(getMetaFromSchema, schema); | |
} | |
}; | |
SchemaRecordType.prototype.validate = function () { | |
return this.reduce((valid, value, key)=> { | |
return this.getValidator(key)(value) && valid; | |
}, true); | |
}; | |
SchemaRecordType.prototype.setValidateError = function (key, errorKeyword) { | |
const validate = this.getValidator(key); | |
if (errorKeyword && validate) { | |
const errors = validate.errors; | |
errors.push({ | |
keyword: errorKeyword, | |
path: '' | |
}); | |
validate.errors = errors; | |
} | |
return this; | |
}; | |
SchemaRecordType.prototype._validators = schema.get('properties') | |
.map((schemaItem)=> { | |
return createValidator(schemaItem) | |
}); | |
SchemaRecordType.prototype.getValidator = function (key) { | |
if (!this._validators.has(key)) { | |
throw new Error(`${key} is not in ${String(this)}`) | |
} | |
return this._validators.get(key); | |
}; | |
SchemaRecordType.prototype.getErrorMsg = function (key) { | |
const validate = this.getValidator(key); | |
if (validate.errors.length) { | |
const errorMsg = this.getMeta(key).get('errorMsg', Immutable.fromJS({})); | |
const displayErrorList = []; | |
validate.errors.forEach((errorItem)=> { | |
const msg = errorMsg.get(errorItem.keyword); | |
if (msg) { | |
displayErrorList.push(msg); | |
} | |
}); | |
if (displayErrorList.length) { | |
return displayErrorList.join('; ') | |
} | |
return errorMsg.get('default') || '未知错误'; | |
} | |
return null; | |
}; | |
return SchemaRecordType; | |
} | |
SchemaRecord.createFactory = function (Model) { | |
const factory = function (values) { | |
return new Model(values); | |
}; | |
factory.type = Model; | |
return factory; | |
}; | |
function getMetaFromSchema(schema, key) { | |
if (key) { | |
const fieldSchema = schema.getIn(['properties', key]); | |
if (fieldSchema) { | |
if (isTypeArray(fieldSchema)) { | |
return getItemSchema(fieldSchema.get('items')); | |
} | |
return getItemSchema(fieldSchema); | |
} | |
} | |
return schema; | |
} | |
function getItemSchema(itemSchema = {}) { | |
if (itemSchema.has('factory')) { | |
return itemSchema.get('factory').type.getMeta(); | |
} | |
return itemSchema; | |
} | |
function createValidator(itemSchema = {}) { | |
let options = {}; | |
if (itemSchema.has('formats')) { | |
options.formats = itemSchema.get('formats').toObject(); | |
itemSchema = itemSchema.remove('formats'); | |
} | |
const validate = jsen(itemSchema.toJS(), options); | |
function customValidate(value) { | |
validate(value); | |
let errors = validate.errors; | |
if (itemSchema.has('required')) { | |
if (_.isEmpty(value)) { | |
errors = [{ | |
'keyword': 'required', | |
'path': '' | |
}] | |
} | |
} | |
return (customValidate.errors = errors) && errors.length === 0; | |
} | |
return customValidate; | |
} | |
export default SchemaRecord; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import isTypeObject from './isTypeObject'; | |
import isFunction from 'lodash.isFunction'; | |
export default function updateData(schema = {}, data = {}) { | |
if (isTypeObject(schema)) { | |
return schema | |
.get('properties') | |
.map((schemaItem, key)=> { | |
const factory = schemaItem.get('factory'); | |
let values = data && data[key]; | |
return isFunction(factory) ? factory(values) : (values || schemaItem.get('default', null)); | |
}) | |
.toObject(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment