ampersand-state
Advanced tools
Comparing version 2.0.1 to 3.0.0
var _ = require('underscore'); | ||
var BBEvents = require('backbone-events-standalone'); | ||
var arrayNext = require('array-next'); | ||
var dataTypes = require('./dataTypes'); | ||
@@ -49,5 +50,4 @@ | ||
var triggers = []; | ||
var changing, previous, changes, newType, | ||
interpretedType, newVal, def, attr, attrs, | ||
silent, unset, currentVal, initial; | ||
var changing, previous, changes, newType, newVal, def, cast, err, attr, | ||
attrs, dataType, silent, unset, currentVal, initial, hasChanged; | ||
@@ -100,5 +100,7 @@ // Handle both `"key", value` and `{key: value}` -style arguments. | ||
dataType = this._dataTypes[def.type]; | ||
// check type if we have one | ||
if (dataTypes[def.type]) { | ||
var cast = dataTypes[def.type].set(newVal); | ||
if (dataType && dataType.set) { | ||
cast = dataType.set(newVal); | ||
newVal = cast.val; | ||
@@ -110,3 +112,3 @@ newType = cast.type; | ||
if (def.test) { | ||
var err = def.test.call(this, newVal, newType); | ||
err = def.test.call(this, newVal, newType); | ||
if (err) { | ||
@@ -134,4 +136,10 @@ throw new TypeError('Property \'' + attr + '\' failed validation with error: ' + err); | ||
if (dataType && dataType.compare) { | ||
hasChanged = !dataType.compare(currentVal, newVal); | ||
} else { | ||
hasChanged = !_.isEqual(currentVal, newVal); | ||
} | ||
// enforce `setOnce` for properties if set | ||
if (def.setOnce && currentVal !== undefined && !_.isEqual(currentVal, newVal)) { | ||
if (def.setOnce && currentVal !== undefined && hasChanged) { | ||
throw new TypeError('Property \'' + key + '\' can only be set once.'); | ||
@@ -141,3 +149,3 @@ } | ||
// push to changes array if different | ||
if (!_.isEqual(currentVal, newVal)) { | ||
if (hasChanged) { | ||
changes.push({prev: currentVal, val: newVal, key: attr}); | ||
@@ -290,9 +298,4 @@ } | ||
_getDefaultForType: function (type) { | ||
if (type === 'string') { | ||
return ''; | ||
} else if (type === 'object') { | ||
return {}; | ||
} else if (type === 'array') { | ||
return []; | ||
} | ||
var dataType = this._dataTypes[type]; | ||
return dataType && dataType.default && dataType.default(); | ||
}, | ||
@@ -318,3 +321,3 @@ | ||
_ensureValidType: function (type) { | ||
return _.contains(['string', 'number', 'boolean', 'array', 'object', 'date', 'any'].concat(_.keys(dataTypes)), type) ? type : undefined; | ||
return _.contains(['string', 'number', 'boolean', 'array', 'object', 'date', 'any'].concat(_.keys(this._dataTypes)), type) ? type : undefined; | ||
}, | ||
@@ -428,5 +431,6 @@ | ||
var result = this._values[name]; | ||
var typeDef = this._dataTypes[def.type]; | ||
if (typeof result !== 'undefined') { | ||
if (dataTypes[def.type] && dataTypes[def.type].get) { | ||
result = dataTypes[def.type].get(result); | ||
if (typeDef && typeDef.get) { | ||
result = typeDef.get(result); | ||
} | ||
@@ -499,2 +503,3 @@ return result; | ||
child.prototype._collections = _.extend({}, parent.prototype._collections); | ||
child.prototype._dataTypes = _.extend({}, parent.prototype._dataTypes || dataTypes); | ||
@@ -504,21 +509,32 @@ // Mix in all prototype properties to the subclass if supplied. | ||
args.forEach(function processArg(def) { | ||
_.each(def, function (value, key) { | ||
if (key === 'props' || key === 'session') { | ||
_.each(value, function (def, name) { | ||
createPropertyDefinition(child.prototype, name, def, key === 'session'); | ||
}); | ||
} else if (key === 'derived') { | ||
_.each(value, function (def, name) { | ||
createDerivedProperty(child.prototype, name, def); | ||
}); | ||
} else if (key === 'collections') { | ||
_.each(value, function (constructor, name) { | ||
child.prototype._collections[name] = constructor; | ||
}); | ||
} | ||
}); | ||
delete def.props; | ||
delete def.session; | ||
delete def.derived; | ||
delete def.collections; | ||
if (def.dataTypes) { | ||
_.each(def.dataTypes, function (def, name) { | ||
child.prototype._dataTypes[name] = def; | ||
}); | ||
delete def.dataTypes; | ||
} | ||
if (def.props) { | ||
_.each(def.props, function (def, name) { | ||
createPropertyDefinition(child.prototype, name, def); | ||
}); | ||
delete def.props; | ||
} | ||
if (def.session) { | ||
_.each(def.session, function (def, name) { | ||
createPropertyDefinition(child.prototype, name, def, true); | ||
}); | ||
delete def.session; | ||
} | ||
if (def.derived) { | ||
_.each(def.derived, function (def, name) { | ||
createDerivedProperty(child.prototype, name, def); | ||
}); | ||
delete def.derived; | ||
} | ||
if (def.collections) { | ||
_.each(def.collections, function (constructor, name) { | ||
child.prototype._collections[name] = constructor; | ||
}); | ||
delete def.collections; | ||
} | ||
_.extend(child.prototype, def); | ||
@@ -537,53 +553,2 @@ }); | ||
// also expose data types in our export | ||
var dataTypes = Base.dataTypes = { | ||
date: { | ||
set: function (newVal) { | ||
var newType; | ||
if (!_.isDate(newVal)) { | ||
try { | ||
newVal = (new Date(parseInt(newVal, 10))).valueOf(); | ||
newType = 'date'; | ||
} catch (e) { | ||
newType = typeof newVal; | ||
} | ||
} else { | ||
newType = 'date'; | ||
newVal = newVal.valueOf(); | ||
} | ||
return { | ||
val: newVal, | ||
type: newType | ||
}; | ||
}, | ||
get: function (val) { | ||
return new Date(val); | ||
} | ||
}, | ||
array: { | ||
set: function (newVal) { | ||
return { | ||
val: newVal, | ||
type: _.isArray(newVal) ? 'array' : typeof newVal | ||
}; | ||
} | ||
}, | ||
object: { | ||
set: function (newVal) { | ||
var newType = typeof newVal; | ||
// we have to have a way of supporting "missing" objects. | ||
// Null is an object, but setting a value to undefined | ||
// should work too, IMO. We just override it, in that case. | ||
if (newType !== 'object' && _.isUndefined(newVal)) { | ||
newVal = null; | ||
newType = 'object'; | ||
} | ||
return { | ||
val: newVal, | ||
type: newType | ||
}; | ||
} | ||
} | ||
}; | ||
Base.extend = extend; | ||
@@ -590,0 +555,0 @@ |
{ | ||
"name": "ampersand-state", | ||
"description": "An observable, extensible state object with derived watchable properties.", | ||
"version": "2.0.1", | ||
"version": "3.0.0", | ||
"author": "Henrik Joreteg <henrik@andyet.net>", | ||
@@ -6,0 +6,0 @@ "bugs": { |
@@ -175,17 +175,21 @@ var tape = require('tape'); | ||
test('should throw a type error for bad data types', function (t) { | ||
try { new Foo({firstName: 3}); } | ||
catch (err) { t.ok(err instanceof TypeError); } | ||
try { new Foo({num: 'foo'}); } | ||
catch (err) { t.ok(err instanceof TypeError); } | ||
try { new Foo({hash: 10}); } | ||
catch (err) { t.ok(err instanceof TypeError); } | ||
try { new Foo({today: 10}); } | ||
catch (err) { t.ok(err instanceof TypeError); } | ||
try { new Foo({list: 10}); } | ||
catch (err) { t.ok(err instanceof TypeError); } | ||
t.throws(function () { | ||
new Foo({firstName: 3}); | ||
}, TypeError); | ||
t.throws(function () { | ||
new Foo({num: 'foo'}); | ||
}, TypeError); | ||
t.throws(function () { | ||
new Foo({hash: 10}); | ||
}, TypeError); | ||
t.throws(function () { | ||
new Foo({today: 'asdfadsfa'}); | ||
}, TypeError); | ||
t.doesNotThrow(function () { | ||
new Foo({today: 1397631169892}); | ||
new Foo({today: '1397631169892'}); | ||
}); | ||
t.throws(function () { | ||
new Foo({list: 10}); | ||
}, TypeError); | ||
t.end(); | ||
@@ -499,17 +503,18 @@ }); | ||
test('Should be able to define and use custom data types', function (t) { | ||
State.dataTypes.crazyType = { | ||
set: function (newVal) { | ||
return { | ||
val: newVal, | ||
type: 'crazyType' | ||
}; | ||
}, | ||
get: function (val) { | ||
return val + 'crazy!'; | ||
} | ||
}; | ||
var Foo = State.extend({ | ||
props: { | ||
silliness: 'crazyType' | ||
}, | ||
dataTypes: { | ||
crazyType: { | ||
set: function (newVal) { | ||
return { | ||
val: newVal, | ||
type: 'crazyType' | ||
}; | ||
}, | ||
get: function (val) { | ||
return val + 'crazy!'; | ||
} | ||
} | ||
} | ||
@@ -516,0 +521,0 @@ }); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
56017
10
1356