var DataMapping = require("./data-mapping").DataMapping,
assign = require("frb/assign"),
compile = require("frb/compile-evaluator"),
ObjectDescriptorReference = require("core/meta/object-descriptor-reference").ObjectDescriptorReference,
parse = require("frb/parse"),
MappingRule = require("data/service/mapping-rule").MappingRule,
Promise = require("core/promise").Promise,
Scope = require("frb/scope"),
Set = require("collections/set");
var ONE_WAY_BINDING = "<-";
var TWO_WAY_BINDING = "<->";
/**
* Maps raw data to data objects, using FRB expressions, of a specific type.
*
* TODO: Write more thorough description.
*
* @class
* @extends external:DataMapping
*/
exports.ExpressionDataMapping = DataMapping.specialize(/** @lends ExpressionDataMapping.prototype */ {
/***************************************************************************
* Serialization
*/
serializeSelf: {
value: function (serializer) {
// serializer.setProperty("name", this.name);
// if ((this._model) && (!this.model.isDefault)) {
// serializer.setProperty("model", this._model, "reference");
// }
//
// if (this.objectDescriptorInstanceModule) {
// serializer.setProperty("objectDescriptorModule", this.objectDescriptorInstanceModule);
// }
}
},
deserializeSelf: {
value: function (deserializer) {
var value = deserializer.getProperty("objectDescriptor");
if (value instanceof ObjectDescriptorReference) {
this.objectDescriptorReference = value;
} else {
this.objectDescriptor = value;
}
this.schemaReference = deserializer.getProperty("schema");
value = deserializer.getProperty("objectMapping");
if (value) {
this._objectMappingRules = value.rules;
}
value = deserializer.getProperty("rawDataMapping");
if (value) {
this._rawDataMappingRules = value.rules;
}
value = deserializer.getProperty("requisitePropertyNames");
if (value) {
this.addRequisitePropertyName.apply(this, value);
}
value = deserializer.getProperty("rawDataPrimaryKeys");
if (value) {
this.rawDataPrimaryKeys = value;
}
}
},
/**
* @param {ObjectDescriptor} objectDescriptor - the definition of the objects
* mapped by this mapping.
* @param {DataService} service - the data service this mapping should use.
* @return itself
*/
initWithServiceObjectDescriptorAndSchema: {
value: function (service, objectDescriptor, schema) {
this.service = service;
this.objectDescriptor = objectDescriptor;
this.schemaDescriptor = schema;
return this;
}
},
resolveReferences: {
value: function () {
var self = this;
return this._resolveObjectDescriptorReferenceIfNecessary().then(function () {
return self._resolveSchemaReferenceIfNecessary();
});
}
},
_resolveObjectDescriptorReferenceIfNecessary: {
value: function () {
var self = this,
requiresInitialization = !this.objectDescriptor && this.objectDescriptorReference,
promise = requiresInitialization ? this.objectDescriptorReference.promise(require) :
Promise.resolve(null);
return promise.then(function (objectDescriptor) {
if (objectDescriptor) {
self.objectDescriptor = objectDescriptor;
}
return null;
});
}
},
_resolveSchemaReferenceIfNecessary: {
value: function () {
var self = this,
requiresInitialization = !this.schemaDescriptor && this.schemaDescriptorReference,
promise = requiresInitialization ? this.schemaReference.promise(require) :
Promise.resolve(null);
return promise.then(function (objectDescriptor) {
if (objectDescriptor) {
self.schemaDescriptor = objectDescriptor;
}
return null;
});
}
},
/***************************************************************************
* Properties
*/
/**
* The descriptor of the objects that are mapped to by this
* data mapping.
* @type {ObjectDescriptor}
*/
objectDescriptor: {
get: function () {
return this._objectDescriptor;
},
set: function (value) {
this._objectDescriptor = value;
this._objectDescriptorReference = new ObjectDescriptorReference().initWithValue(value);
}
},
/**
* The descriptor of the "raw data" mapped from by this
* data mapping.
* @type {ObjectDescriptor}
*/
schemaDescriptor: {
get: function () {
return this._schemaDescriptor;
},
set: function (value) {
this._schemaDescriptor = value;
this._schemaDescriptorReference = new ObjectDescriptorReference().initWithValue(value);
}
},
/**
* A reference to the object descriptor that is used
* by this mapping. Used by serialized data mappings.
* @type {ObjectDescriptorReference}
*/
objectDescriptorReference: {
get: function () {
return this._objectDescriptorReference ? this._objectDescriptorReference.promise(require) :
Promise.resolve(null);
},
set: function (value) {
this._objectDescriptorReference = value;
}
},
/**
* A reference to the object descriptor of the "raw data" that
* is used by this mapping. Used by serialized data mappings.
* @type {ObjectDescriptorReference}
*/
schemaDescriptorReference: {
get: function () {
return this._schemaDescriptorReference ? this._schemaDescriptorReference.promise(require) :
Promise.resolve(null);
},
set: function (value) {
this._schemaDescriptorReference = value;
}
},
/**
* The service that owns this mapping object.
* Used to create fetches for relationships.
* @type {DataService}
*/
service: {
value: undefined
},
/**
* Adds a name to the list of properties that will participate in
* eager mapping. The requisite property names will be mapped
* during the map from raw data phase.
* @param {...string} propertyName
*/
addRequisitePropertyName: {
value: function () {
// TODO: update after changing requisitePropertyNames to a set.
var i, length, arg;
for (i = 0, length = arguments.length; i < length; i += 1) {
arg = arguments[i];
if (!this._requisitePropertyNames.has(arg)) {
this._requisitePropertyNames.add(arg);
}
}
}
},
/**
* @return {Set}
*/
requisitePropertyNames: {
get: function () {
return this._requisitePropertyNames;
}
},
/***************************************************************************
* Mapping
*/
/**
* Adds a rule to be used for mapping objects to raw data.
* @param {string} targetPath - The path to assign on the target
* @param {object} rule - The rule to be used when processing
* the mapping. The rule must contain
* the direction and path of the properties
* to map. Optionally can include
* a converter.
*/
addObjectMappingRule: {
value: function (targetPath, rule) {
var rawRule = {};
rawRule[targetPath] = rule;
this._mapObjectMappingRules(rawRule, true);
this._mapRawDataMappingRules(rawRule);
}
},
/**
* Adds a rule to be used for mapping raw data to objects.
* @param {string} targetPath - The path to assign on the target
* @param {object} rule - The rule to be used when processing
* the mapping. The rule must contain
* the direction and path of the properties
* to map. Optionally can include
* a converter.
*/
addRawDataMappingRule: {
value: function (targetPath, rule) {
var rawRule = {};
rawRule[targetPath] = rule;
this._mapRawDataMappingRules(rawRule, true);
this._mapObjectMappingRules(rawRule);
}
},
/**
* Convert raw data to data objects of an appropriate type.
*
* Subclasses should override this method to map properties of the raw data
* to data objects, as in the following:
*
* mapRawDataToObject: {
* value: function (data, object) {
* object.firstName = data.GIVEN_NAME;
* object.lastName = data.FAMILY_NAME;
* }
* }
*
* The default implementation of this method copies the properties defined
* by the raw data object to the data object.
*
* @method
* @argument {Object} data - An object whose properties' values hold
* the raw data.
* @argument {Object} object - An object whose properties must be set or
* modified to represent the raw data.
*/
mapRawDataToObject: {
value: function (data, object) {
var requisitePropertyNames = this.requisitePropertyNames,
iterator = requisitePropertyNames.values(),
promises, propertyName, result;
if (requisitePropertyNames.size) {
promises = [];
while ((propertyName = iterator.next().value)) {
promises.push(this.mapRawDataToObjectProperty(data, object, propertyName));
}
result = Promise.all(promises);
} else {
result = Promise.resolve(null);
}
return result;
}
},
/**
* Convert model objects to raw data objects of an appropriate type.
*
* Subclasses should override this method to map properties of the model objects
* to raw data, as in the following:
*
* mapObjectToRawData: {
* value: function (object, data) {
* data.GIVEN_NAME = object.firstName;
* data.FAMILY_NAME = object.lastName;
* }
* }
*
* The default implementation of this method copies the properties defined
* by the model object to the raw data object.
*
* @method
* @argument {Object} object - An object whose properties' values
* hold the model data.
* @argument {Object} data - An object whose properties must be set or
* modified to represent the model data
*/
mapObjectToRawData: {
value: function (object, data) {
var rules = this._compiledRawDataMappingRules,
promises = [],
keys = Object.keys(rules),
key, i;
for (i = 0; (key = keys[i]); ++i) {
promises.push(this.mapObjectToRawDataProperty(object, data, key));
}
return promises && promises.length && Promise.all(promises) || Promise.resolve(null);
}
},
/**
* Convert model object properties to the raw data properties present in the requirements
* for a given propertyName
*
* @method
* @argument {Object} object - An object whose properties' values
* hold the model data.
* @argument {Object} data - An object whose properties must be set or
* modified to represent the model data.
* @argument {string} propertyName - The name of the property whose requirements
* need to be populated in the raw data.
*/
mapObjectToCriteriaSourceForProperty: {
value: function (object, data, propertyName) {
var rules = this._compiledRawDataMappingRules,
rule = this._compiledObjectMappingRules[propertyName],
requiredRawProperties = rule ? rule.requirements : [],
rawRequirementsToMap = new Set(requiredRawProperties),
promises = [], key;
for (key in rules) {
if (rules.hasOwnProperty(key) && rawRequirementsToMap.has(key)) {
promises.push(this._getAndMapObjectProperty(object, data, key, propertyName));
}
}
return promises && promises.length && Promise.all(promises) || Promise.resolve(null);
}
},
_propertiesRequestedForLayer: {
get: function () {
if (!this.__propertiesRequestedForLayer) {
this.__propertiesRequestedForLayer = new Map();
}
return this.__propertiesRequestedForLayer;
}
},
_getAndMapObjectProperty: {
value: function (object, data, propertyName) {
var self = this,
rules = this._compiledRawDataMappingRules,
rule = rules[propertyName],
requiredObjectProperties = rule ? rule.requirements : [],
result;
result = this.service.rootService.getObjectPropertyExpressions(object, requiredObjectProperties);
if (result && typeof result.then === "function") {
return result.then(function () {
return self.mapObjectToRawDataProperty(object, data, propertyName);
});
} else {
return this.mapObjectToRawDataProperty(object, data, propertyName);
}
}
},
/**
* Returns the value of a single raw data property evaluated against the model object
*
* @method
* @argument {Object} object - An object whose properties' values
* hold the model data.
* @argument {Object} data - The object on which to assign the property
* @argument {string} propertyName - The name of the raw property to which
* to assign the values.
*/
mapObjectToRawDataProperty: {
value: function(object, data, property) {
var self = this,
rules = this._compiledRawDataMappingRules,
scope = new Scope(object),
rule = rules[property],
propertyDescriptor = rule && rule.propertyDescriptor,
promise;
if (propertyDescriptor) {
promise = propertyDescriptor.valueDescriptor.then(function (descriptor) {
self._prepareObjectToRawDataRule(rule);
return descriptor && rule.converter ? self._convertRelationshipToRawData(object, propertyDescriptor, rule, scope) :
self._parse(rule, scope);
});
} else /*if (propertyDescriptor)*/ { //relaxing this for now
promise = Promise.resolve(this._parse(rule, scope));
}
return promise && promise.then(function(value){
data[property] = value;
}) || Promise.resolve(null);
}
},
_prepareObjectToRawDataRule: {
value: function (rule) {
var converter = rule.converter,
propertyDescriptor = rule.propertyDescriptor;
if (converter) {
converter.expression = converter.expression || rule.expression;
converter.foreignDescriptor = converter.foreignDescriptor || propertyDescriptor.valueDescriptor;
}
}
},
/**
* Returns the identifier of the child service of .service that is used to
* fetch propertyName
*
* @method
* @argument {string} propertyName - The name of a model property
*/
serviceIdentifierForProperty: {
value: function (propertyName) {
var rule = this._compiledObjectMappingRules[propertyName];
return rule && rule.serviceIdentifier;
}
},
_compiledObjectMappingRules: {
get: function () {
if (!this.__compiledObjectMappingRules) {
this.__compiledObjectMappingRules = {};
this._mapObjectMappingRules(this._rawDataMappingRules);
this._mapObjectMappingRules(this._objectMappingRules, true);
}
return this.__compiledObjectMappingRules;
}
},
_compiledRawDataMappingRules: {
get: function () {
if (!this.__compiledRawDataMappingRules) {
this.__compiledRawDataMappingRules = {};
this._mapRawDataMappingRules(this._objectMappingRules);
this._mapRawDataMappingRules(this._rawDataMappingRules, true);
}
return this.__compiledRawDataMappingRules;
}
},
_rawDataMappingRules: {
value: undefined
},
rawDataPrimaryKeys: {
value: undefined
},
_requisitePropertyNames: {
get: function () {
if (!this.__requisitePropertyNames) {
this.__requisitePropertyNames = new Set();
}
return this.__requisitePropertyNames;
}
},
_mapObjectMappingRules: {
value: function (rawRules, addOneWayBindings) {
var rules = this._compiledObjectMappingRules,
propertyNames = rawRules ? Object.keys(rawRules) : [],
propertyName, rawRule, rule, i;
for (i = 0; (propertyName = propertyNames[i]); ++i) {
rawRule = rawRules[propertyName];
if (this._shouldMapRule(rawRule, addOneWayBindings)) {
rule = this._makeRuleFromRawRule(rawRule, propertyName, addOneWayBindings);
rules[rule.targetPath] = rule;
}
}
}
},
_mapRawDataMappingRules: {
value: function (rawRules, addOneWayBindings) {
var rules = this._compiledRawDataMappingRules,
propertyNames = rawRules ? Object.keys(rawRules) : [],
propertyName, rawRule, rule, i;
for (i = 0; (propertyName = propertyNames[i]); ++i) {
rawRule = rawRules[propertyName];
if (this._shouldMapRule(rawRule, addOneWayBindings)) {
rule = this._makeRuleFromRawRule(rawRule, propertyName, addOneWayBindings);
rules[rule.targetPath] = rule;
}
}
}
},
_makeRuleFromRawRule: {
value: function (rawRule, propertyName, addOneWayBindings) {
var propertyDescriptorName = addOneWayBindings ? rawRule[ONE_WAY_BINDING] || rawRule[TWO_WAY_BINDING] : propertyName,
propertyDescriptor = this.objectDescriptor.propertyDescriptorForName(propertyDescriptorName),
sourcePath = addOneWayBindings ? rawRule[ONE_WAY_BINDING] || rawRule[TWO_WAY_BINDING] : propertyName,
targetPath = addOneWayBindings && propertyName || rawRule[TWO_WAY_BINDING],
compiled = this._compileRuleExpression(sourcePath),
rule = new MappingRule();
rule.converter = rawRule.converter || this._defaultConverter(sourcePath, targetPath);
rule.expression = compiled.expression;
rule.inversePropertyName = rawRule.inversePropertyName;
rule.isReverter = rawRule.converter && !addOneWayBindings;
rule.propertyDescriptor = propertyDescriptor;
rule.requirements = this._parseRequirementsFromParsedExpression(compiled.parsed);
rule.serviceIdentifier = rawRule.serviceIdentifier;
rule.targetPath = targetPath;
return rule;
}
},
_convertRelationshipToRawData: {
value: function (object, propertyDescriptor, rule, scope) {
if (!rule.converter.revert) {
console.log("Converter does not have a revert function for property (" + propertyDescriptor.name + ")");
}
return rule.converter.revert(rule.expression(scope));
}
},
__scope: {
value: null
},
_scope: {
get: function() {
return this.__scope || new Scope();
}
},
/**
* Returns the value of a single model property evaluated against the raw data object
*
* @method
* @argument {Object} data - An object whose properties' values
* hold the raw data.
* @argument {Object} object - The object on which to assign the property
* @argument {string} propertyName - The name of the model property to which
* to assign the values.
*/
mapRawDataToObjectProperty: {
value: function (data, object, propertyName) {
//We should probably shift rules to be a Map rather than an anonymous object.
var rules = this._compiledObjectMappingRules,
rule = rules.hasOwnProperty(propertyName) && rules[propertyName],
propertyDescriptor = rule && this.objectDescriptor.propertyDescriptorForName(propertyName),
scope = this._scope,
self = this,
result;
scope.value = data;
if (!propertyDescriptor || propertyDescriptor.definition) {
result = Promise.resolve(null);
} else {
result = propertyDescriptor.valueDescriptor.then(function (descriptor) {
var isRelationship = !!descriptor;
self._prepareRawDataToObjectRule(rule, propertyDescriptor);
return isRelationship ? self._resolveRelationship(object, propertyDescriptor, rule, scope) :
self._resolvePrimitive(object, propertyDescriptor, rule, scope);
});
}
return result;
}
},
_prepareRawDataToObjectRule: {
value: function (rule, propertyDescriptor) {
var converter = rule.converter;
if (converter) {
converter.expression = converter.expression || rule.expression;
converter.foreignDescriptor = converter.foreignDescriptor || propertyDescriptor.valueDescriptor;
converter.objectDescriptor = this.objectDescriptor;
converter.serviceIdentifier = rule.serviceIdentifier;
}
}
},
/**
* Pre-fetches the model properties that are required to map another model property
*
* @method
* @argument {Object} object - The object on which to prefetch properties
* @argument {string} propertyName - The name of the model property for which
* there are prerequisites
*/
resolvePrerequisitesForProperty: {
value: function (object, propertyName) {
var rule = this._compiledObjectMappingRules[propertyName],
prerequisites = rule && rule.prerequisitePropertyNames || null;
if (!rule) {
console.log("No Rule For:", propertyName);
}
return prerequisites ? this.service.rootService.getObjectProperties(object, prerequisites) : Promise.resolve(null);
}
},
_resolvePrimitive: {
value: function (object, propertyDescriptor, rule, scope) {
var value = this._parse(rule, scope),
self = this;
return new Promise(function (resolve, reject) {
if (self._isThenable(value)) {
value.then(function (data) {
self._assignDataToObjectProperty(object, propertyDescriptor, data);
resolve(null);
});
} else {
object[propertyDescriptor.name] = value;
resolve(null);
}
});
}
},
_isThenable: {
value: function (object) {
return object && object.then && typeof object.then === "function";
}
},
_assignDataToObjectProperty: {
value: function (object, propertyDescriptor, data) {
var hasData = data && data.length,
isToMany = propertyDescriptor.cardinality !== 1,
propertyName = propertyDescriptor.name;
//Add checks to make sure that data matches expectations of propertyDescriptor.cardinality
//
if (Array.isArray(data)) {
if (isToMany && Array.isArray(object[propertyName])) {
object[propertyName].splice.apply(object[propertyName], [0, Infinity].concat(data));
} else if (isToMany) {
object[propertyName] = data;
} else if (hasData) {
//Cardinality is 1, if data contains more than 1 item, we throw
if (data.length && data.length > 1) {
throw new Error("ExpressionDataMapping for property \""+ this.objectDescriptor.name + "." + propertyName+"\" expects a cardinality of 1 but data to map doesn't match: "+data);
}
object[propertyName] = data[0];
}
} else {
object[propertyName] = data;
}
}
},
_assignObjectToDataInverseProperty: {
value: function (object, propertyDescriptor, data, inversePropertyName) {
return propertyDescriptor.valueDescriptor.then(function (valueDescriptor) {
var inversePropertyDescriptor = valueDescriptor.propertyDescriptorForName(inversePropertyName);
if (inversePropertyDescriptor.cardinality === 1) {
data.forEach(function (item) {
item[inversePropertyName] = object;
});
}
return null;
});
}
},
_resolveRelationship: {
value: function (object, propertyDescriptor, rule, scope) {
var self = this;
return rule.converter.convert(rule.expression(scope)).then(function (data) {
self._assignDataToObjectProperty(object, propertyDescriptor, data);
return rule.inversePropertyName && data && data.length ? self._assignObjectToDataInverseProperty(object, propertyDescriptor, data, rule.inversePropertyName) :
null;
});
}
},
_compileRuleExpression: {
value: function (rule) {
var parsed = parse(rule),
expression = compile(parsed);
return {
parsed: parsed,
expression: expression
};
}
},
_parseRequirementsFromParsedExpression: {
value: function (parsedExpression, requirements) {
var args = parsedExpression.args,
type = parsedExpression.type;
requirements = requirements || [];
if (type === "property" && args[0].type === "value") {
requirements.push(args[1].value);
} else if (type === "property" && args[0].type === "property") {
var subProperty = [args[1].value];
this._parseRequirementsFromParsedExpression(args[0], subProperty);
requirements.push(subProperty.reverse().join("."));
} else if (type === "record") {
this._parseRequirementsFromParsedRecord(parsedExpression, requirements);
}
return requirements;
}
},
_parseRequirementsFromParsedRecord: {
value: function (parsedExpression, requirements) {
var self = this,
args = parsedExpression.args,
keys = Object.keys(args);
keys.forEach(function (key) {
self._parseRequirementsFromParsedExpression(args[key], requirements);
});
}
},
_parse: {
value: function (rule, scope) {
var value = rule.expression(scope);
return rule.converter ? rule.isReverter ?
rule.converter.revert(value) :
rule.converter.convert(value) :
value;
}
},
_parseObject: {
value: function (rule, scope) {
var value = rule.expression(scope);
return rule.converter && rule.converter.revert(value) || value;
}
},
_shouldMapRule: {
value: function (rawRule, addOneWayBindings) {
var isOneWayBinding = rawRule.hasOwnProperty(ONE_WAY_BINDING),
isTwoWayBinding = !isOneWayBinding && rawRule.hasOwnProperty(TWO_WAY_BINDING);
return isOneWayBinding && addOneWayBindings || isTwoWayBinding;
}
},
_defaultConverter: {
value: function (sourcePath, targetPath, isObjectMappingRule) {
var sourceObjectDescriptor = isObjectMappingRule ? this.schemaDescriptor : this.objectDescriptor,
targetObjectDescriptor = isObjectMappingRule ? this.objectDescriptor : this.schemaDescriptor,
sourceDescriptor = sourceObjectDescriptor && sourceObjectDescriptor.propertyDescriptorForName(sourcePath),
targetDescriptor = targetObjectDescriptor && targetObjectDescriptor.propertyDescriptorForName(targetPath),
sourceDescriptorValueType = sourceDescriptor && sourceDescriptor.valueType,
targetDescriptorValueType = targetDescriptor && targetDescriptor.valueType,
shouldUseDefaultConverter = sourceDescriptor && targetDescriptor &&
sourceDescriptorValueType !== targetDescriptorValueType;
return shouldUseDefaultConverter ? this._converterForValueTypes(targetDescriptorValueType, sourceDescriptorValueType) :
null;
}
},
_converterForValueTypes: {
value: function (sourceType, destinationType) {
var converters = exports.ExpressionDataMapping.defaultConverters;
return converters[sourceType] && converters[sourceType][destinationType] || null;
}
},
/***************************************************************************
* Deprecated
*/
/**
* @todo Document deprecation in favor of
* [mapRawDataToObject()]{@link DataMapping#mapRawDataToObject}
*/
mapFromRawData: {
value: function (object, record, context) {
return this.mapRawDataToObject(record, object, context);
}
},
/**
* @todo Document deprecation in favor of
* [mapObjectToRawData()]{@link DataMapping#mapObjectToRawData}
*/
mapToRawData: {
value: function (object, record) {
this.mapObjectToRawData(object, record);
}
}
}, {
defaultConverters: {
get: function () {
if (!exports.ExpressionDataMapping._defaultConverters) {
var defaultConverters = {};
exports.ExpressionDataMapping._addDefaultConvertersToMap(defaultConverters);
exports.ExpressionDataMapping._defaultConverters = defaultConverters;
}
return exports.ExpressionDataMapping._defaultConverters;
}
},
_addDefaultConvertersToMap: {
value: function (converters) {
exports.ExpressionDataMapping._addDefaultBooleanConvertersToConverters(converters);
exports.ExpressionDataMapping._addDefaultNumberConvertersToConverters(converters);
exports.ExpressionDataMapping._addDefaultStringConvertersToConverters(converters);
}
},
_addDefaultBooleanConvertersToConverters: {
value: function (converters) {
var booleanConverters = {};
booleanConverters["string"] = Object.create({}, {
convert: {
value: function (value) {
return Boolean(value);
}
},
revert: {
value: function (value) {
return String(value);
}
}
});
booleanConverters["number"] = Object.create({}, {
convert: {
value: function (value) {
return Boolean(value);
}
},
revert: {
value: function (value) {
return Number(value);
}
}
});
converters["boolean"] = booleanConverters;
}
},
_addDefaultNumberConvertersToConverters: {
value: function (converters) {
var numberConverters = {};
numberConverters["string"] = Object.create({}, {
convert: {
value: function (value) {
return Number(value);
}
},
revert: {
value: function (value) {
return String(value);
}
}
});
numberConverters["boolean"] = Object.create({}, {
convert: {
value: function (value) {
return Number(value);
}
},
revert: {
value: function (value) {
return Boolean(value);
}
}
});
converters["number"] = numberConverters;
}
},
_addDefaultStringConvertersToConverters: {
value: function (converters) {
var stringConverters = {};
stringConverters["number"] = Object.create({}, {
convert: {
value: function (value) {
return String(value);
}
},
revert: {
value: function (value) {
return Number(value);
}
}
});
stringConverters["boolean"] = Object.create({}, {
convert: {
value: function (value) {
return String(value);
}
},
revert: {
value: function (value) {
return Boolean(value);
}
}
});
converters["string"] = stringConverters;
}
}
});