abstract-type
Version:
The abstract-type library includes the abstract `Type` class and `Value` class for streamable type info and validating value.
515 lines (438 loc) • 14.2 kB
JavaScript
(function() {
var Attributes, Type, Value, attributes, createObject, defineProperty, extend, factory, getObjectKeys, isArray, isFunction, isInheritedFrom, isObject, isString, isUndefined, objectToString, properties;
properties = require('property-manager/ability');
factory = require('custom-factory');
createObject = require('inherits-ex/lib/createObject');
isInheritedFrom = require('inherits-ex/lib/isInheritedFrom');
isObject = require('util-ex/lib/is/type/object');
isFunction = require('util-ex/lib/is/type/function');
isString = require('util-ex/lib/is/type/string');
isArray = require('util-ex/lib/is/type/array');
isUndefined = require('util-ex/lib/is/type/undefined');
defineProperty = require('util-ex/lib/defineProperty');
extend = require('util-ex/lib/_extend');
Attributes = require('./attributes/');
attributes = new Attributes();
objectToString = Object.prototype.toString;
getObjectKeys = Object.keys;
Value = (function() {
Value.tryGetTypeName = function(aValue) {
var i, result;
if (aValue instanceof Object) {
result = objectToString.call(aValue);
i = result.lastIndexOf(' ');
if (i >= 0) {
result = result.substring(i + 1, result.length - 1);
}
} else {
result = typeof aValue;
result = result.charAt(0).toUpperCase() + result.substring(1);
}
return result;
};
function Value(aValue, aType, aOptions) {
var vTypeName;
if (!(aType instanceof Type)) {
aOptions = aType;
vTypeName = Value.tryGetTypeName(aValue);
if (aOptions) {
aType = Type.create(vTypeName, aOptions);
} else {
aType = Type(vTypeName);
}
if (!aType) {
throw new TypeError('can not determine the value type.');
}
}
if (!(this instanceof Value)) {
return createObject(aType.ValueType, aValue, aType, aOptions);
}
defineProperty(this, '$type', aType);
this._initialize(aValue, aType, aOptions);
this.assign(aValue, aOptions);
}
Value.prototype.isValid = function(aOptions) {
return this.$type.isValid(this.valueOf(), aOptions);
};
Value.prototype._initialize = function(aValue, aType, aOptions) {
return defineProperty(this, 'value', null);
};
Value.prototype._assign = function(aValue) {
this.value = aValue;
};
Value.prototype.assign = function(aValue, aOptions) {
var checkValidity, vType;
if (aOptions) {
checkValidity = aOptions.checkValidity;
}
vType = this.$type;
if (isFunction(vType.toValue)) {
aValue = vType.toValue(aValue, aOptions);
} else if (aValue instanceof Value) {
aValue = aValue.valueOf();
}
if (checkValidity !== false) {
this.$type.validate(aValue, checkValidity);
}
this._assign(aValue);
return this;
};
Value.prototype.create = function(aValue, aOptions) {
return this.$type.createValue(aValue, aOptions);
};
Value.prototype.clone = function(aOptions) {
return this.create(this.valueOf(), aOptions);
};
Value.prototype.toString = function() {
return String(this.valueOf());
};
Value.prototype.valueOf = function() {
return this.value;
};
Value.prototype._toObject = function(aOptions) {
return this.valueOf();
};
Value.prototype.toObject = function(aOptions) {
var result;
if (aOptions && aOptions.withType) {
delete aOptions.withType;
result = this.toObjectWithType(aOptions);
} else {
result = this._toObject(aOptions);
}
return result;
};
Value.prototype.toObjectWithType = function(aOptions) {
var result, value;
value = this._toObject(aOptions);
result = this.$type.toObject(aOptions);
result.value = value;
return result;
};
Value.prototype.fromJson = function(aString) {
aString = JSON.parse(aString);
return this.assign(aString);
};
Value.prototype.createFromJson = function(aString) {
var vType;
aString = JSON.parse(aString);
vType = this.$type;
if (vType.toValue) {
aString = vType.toValue(aString);
}
return createObject(this.$type.ValueType, aString, vType);
};
Value.prototype.toJSON = function(aOptions) {
var result, vType;
result = this.toObject(aOptions);
vType = this.$type;
if (vType.valueToString) {
if (result.hasOwnProperty('value')) {
result.value = vType.valueToString(result.value);
} else {
result = vType.valueToString(result);
}
}
return result;
};
Value.prototype.toJson = function(aOptions) {
var result;
result = this.toJSON(aOptions);
return JSON.stringify(result);
};
Value.prototype.inspect = function() {
return '<type ' + this.$type._inspect({
value: this._toObject()
}) + '>';
};
return Value;
})();
module.exports = Type = (function() {
var oldAssign;
factory(Type);
properties(Type, {
name: 'advance'
});
Type.ROOT_NAME = 'type';
Type.Value = Value;
Type.prototype.ValueType = Value;
Type.prototype.$attributes = attributes;
function Type(aTypeName, aOptions) {
var vCaller, vTypeClass;
if (!(this instanceof Type) && !(aTypeName instanceof Type)) {
if (aTypeName) {
if (isObject(aTypeName)) {
aOptions = aTypeName;
aTypeName = attributes.getValue(aOptions, 'name');
} else if (!isString(aTypeName)) {
aOptions = aTypeName;
aTypeName = void 0;
}
}
if (!aTypeName) {
try {
vCaller = arguments.callee.caller;
} catch (_error) {}
if (vCaller && isInheritedFrom(vCaller, Type)) {
aTypeName = vCaller;
vCaller = vCaller.caller;
while (isInheritedFrom(vCaller, aTypeName)) {
aTypeName = vCaller;
vCaller = vCaller.caller;
}
if (aTypeName) {
aTypeName = Type.getNameFromClass(aTypeName);
}
}
if (!aTypeName) {
return;
}
}
vTypeClass = Type.registeredClass(aTypeName);
if (vTypeClass && aOptions && !vTypeClass.prototype.$attributes.isDefaultObject(aOptions)) {
return createObject(vTypeClass, aOptions);
}
}
return Type.__super__.constructor.apply(this, arguments);
}
Type.prototype.initialize = function(aOptions) {
defineProperty(this, 'errors', null);
if (this.$attributes) {
this.$attributes.initializeTo(this);
}
if (this._initialize) {
this._initialize(aOptions);
}
if (aOptions != null) {
return this.assign(aOptions);
}
};
Type.prototype.finalize = function(aOptions) {
if (this.errors) {
this.errors = null;
}
if (this._finalize) {
return this._finalize(aOptions);
}
};
Type.validators = {};
Type.registerValidator = function(aValidator, aValidatorFn) {
var result, vIsFn;
vIsFn = null;
if (isObject(aValidator)) {
if (vIsFn = isFunction(aValidator.validate)) {
aValidatorFn = aValidator.validate;
}
if (aValidator.name) {
aValidator = aValidator.name;
}
}
if (vIsFn === null) {
vIsFn = isFunction(aValidatorFn);
}
result = vIsFn && isString(aValidator) && !Type.validators[aValidator];
if (result) {
Type.validators[aValidator] = aValidatorFn;
}
return result;
};
Type.unregisterValidator = function(aValidatorName) {
return delete Type.validators[aValidatorName];
};
Type.prototype._checkValidator = function(aValue, aOptions) {
var result, vFn, vName, _ref;
if (!isObject(aOptions)) {
aOptions = this;
}
result = true;
_ref = Type.validators;
for (vName in _ref) {
vFn = _ref[vName];
if ((aOptions[vName] != null) || this.$attributes.getRealAttrName(vName)) {
result = vFn.call(this, aValue, aOptions);
if (!result) {
break;
}
}
}
return result;
};
oldAssign = Type.prototype.assign;
Type.prototype.assign = function(aOptions, aExclude) {
this.errors = [];
return oldAssign.call(this, aOptions, aExclude);
};
Type.prototype._validate = function(aValue, aOptions) {
return true;
};
Type.prototype.error = function(aMessage, aOptions) {
var name;
name = (aOptions && this.$attributes.getValue(aOptions, 'name')) || String(this);
this.errors.push({
name: name,
message: aMessage
});
};
Type.prototype.isRequired = function(aValue, aOptions) {
var result, vRequired;
if (!isObject(aOptions)) {
aOptions = this;
}
vRequired = this.$attributes.getValue(aOptions, 'required');
return result = !vRequired || (vRequired === true && (aValue != null));
};
Type.prototype.validateRequired = function(aValue, aOptions) {
var result;
result = this.isRequired(aValue, aOptions);
if (!result) {
this.error('is required', aOptions);
}
return result;
};
Type.prototype.validate = function(aValue, raiseError, aOptions) {
var customValidate, result;
this.errors = [];
if (isObject(raiseError)) {
aOptions = raiseError;
raiseError = aOptions.raiseError;
}
if (aOptions) {
customValidate = this.$attributes.getValue(aOptions, 'customValidate');
}
aOptions = this.mergeTo(aOptions, 'name');
if (!customValidate) {
customValidate = aOptions.customValidate;
}
if (raiseError) {
aOptions.raiseError = true;
}
result = this.validateRequired(aValue, aOptions);
if (result) {
result = this._checkValidator(aValue, aOptions);
}
if (result && isFunction(customValidate)) {
result = customValidate.call(this, aValue, aOptions);
}
if (result && (aValue != null)) {
result = this._validate(aValue, aOptions);
}
if (raiseError !== false && !result) {
throw new TypeError('"' + aValue + '" is an invalid ' + this.name);
}
return result;
};
Type.prototype.isValid = function(aValue, aOptions) {
return this.validate(aValue, false, aOptions);
};
Type.prototype.createValue = function(aValue, aOptions) {
var vType;
if (aOptions && !this.isSame(aOptions)) {
aOptions = this.mergeTo(aOptions, 'name');
if (isFunction(Type.getCacheItem)) {
if (aOptions.cached == null) {
aOptions.cached = true;
}
vType = Factory.getCacheItem(this.Class, aOptions);
} else {
vType = this.createType(aOptions);
}
} else {
vType = this;
}
return createObject(vType.ValueType, aValue, vType, aOptions);
};
Type.prototype.create = Type.prototype.createValue;
Type.prototype.createType = function(aOptions) {
var result;
if (aOptions) {
delete aOptions.value;
}
result = createObject(this.Class, aOptions);
return result;
};
Type.prototype.cloneType = function(aOptions) {
aOptions = this.exportTo(aOptions, 'name', true, true);
if (!aOptions.name) {
aOptions.name = this.name;
}
return this.createType(aOptions);
};
Type.prototype.clone = Type.prototype.cloneType;
Type.fromJson = function(aString) {
return Type.from(JSON.parse(aString));
};
Type.createFromJson = function(aString) {
return Type.createFrom(JSON.parse(aString));
};
Type.from = function(aObject) {
var result;
result = Type(aObject);
if ((aObject.value != null) && result) {
result = result.createValue(aObject.value);
}
return result;
};
Type.createFrom = function(aObject) {
var result, value;
value = aObject.value;
result = Type.create(aObject.name, aObject);
if ((value != null) && result) {
result = result.createValue(value);
}
return result;
};
Type.prototype.toString = function(aOptions) {
return '[type ' + this.name + ']';
};
Type.prototype._inspect = function(aOptions, aNameRequired) {
var result, vAttrs;
if (aNameRequired == null) {
aNameRequired = false;
}
result = '"' + this.name + '"';
vAttrs = this.toJson(aOptions, aNameRequired).slice(1, -1);
if (vAttrs) {
result += ': ' + vAttrs;
}
return result;
};
Type.prototype.inspect = function() {
return '<type ' + this._inspect() + '>';
};
Type.prototype.toJson = function(aOptions, aNameRequired) {
var result;
result = this.toObject(aOptions, aNameRequired);
result = JSON.stringify(result);
return result;
};
Type.prototype._toObject = function(aOptions, aNameRequired) {
var result, vExclude;
if (aNameRequired == null) {
aNameRequired = true;
}
if (!aNameRequired) {
vExclude = 'name';
}
result = this.exportTo(aOptions, vExclude, true, true);
return result;
};
Type.prototype.toObject = function(aOptions, aNameRequired) {
var result, value;
if (aOptions) {
if (!(aOptions.typeOnly || isUndefined(aOptions.value))) {
value = aOptions.value;
}
aOptions = extend({}, aOptions);
delete aOptions.typeOnly;
delete aOptions.value;
}
result = this._toObject(aOptions, aNameRequired);
if (!isUndefined(value)) {
result.value = value;
}
return result;
};
return Type;
})();
}).call(this);
//# sourceMappingURL=index.js.map