Socket
Socket
Sign inDemoInstall

ampersand-state

Package Overview
Dependencies
Maintainers
1
Versions
65
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ampersand-state - npm Package Compare versions

Comparing version 0.3.2 to 0.4.0

.jshintignore

348

ampersand-state.js

@@ -1,9 +0,4 @@

/* jshint expr: true, eqnull: true */
// (c) 2013 Henrik Joreteg
// MIT Licensed
// For all details and documentation:
// https://github.com/HenrikJoreteg/human-model
//
var _ = require('underscore');
var BBEvents = require('backbone-events-standalone');
var arrayNext = require('array-next');

@@ -18,3 +13,2 @@

if (options.parse) attrs = this.parse(attrs, options);
options._attrs = attrs;
this._initted = false;

@@ -34,18 +28,4 @@ this._values = {};

var accessors = {
attributes: {
get: function () {
return this._getAttributes(true);
}
},
derived: {
get: function () {
var res = {};
for (var item in this._derived) res[item] = this._derived[item].fn.apply(this);
return res;
}
}
};
var prototypeMixins = {
_.extend(Base.prototype, BBEvents, {
idAttribute: 'id',

@@ -290,13 +270,2 @@

// Returns `true` if the attribute contains a value that is not null
// or undefined.
has: function (attr) {
return this.get(attr) != null;
},
// return copy of model
clone: function () {
return new this.constructor(this._getAttributes(true));
},
unset: function (attr, options) {

@@ -354,42 +323,3 @@ var def = this._definition[attr];

_createPropertyDefinition: function (name, desc, isSession) {
var self = this;
var def = this._definition[name] = {};
var type;
if (_.isString(desc)) {
// grab our type if all we've got is a string
type = this._ensureValidType(desc);
if (type) def.type = type;
} else {
type = this._ensureValidType(desc[0] || desc.type);
if (type) def.type = type;
if (desc[1] || desc.required) def.required = true;
// set default if defined
def.default = !_.isUndefined(desc[2]) ? desc[2] : desc.default;
def.allowNull = desc.allowNull ? desc.allowNull : false;
if (desc.setOnce) def.setOnce = true;
if (def.required && _.isUndefined(def.default)) def.default = this._getDefaultForType(type);
def.test = desc.test;
def.values = desc.values;
}
if (isSession) def.session = true;
// define a getter/setter on the prototype
// but they get/set on the instance
Object.defineProperty(self, name, {
set: function (val) {
this.set(name, val);
},
get: function () {
var result = this._values[name];
if (typeof result !== 'undefined') {
if (dataTypes[def.type] && dataTypes[def.type].get) {
result = dataTypes[def.type].get(result);
}
return result;
}
return def.default;
}
});
return def;
return createPropertyDefinition(this, name, desc, isSession);
},

@@ -449,18 +379,156 @@

}
});
// getter for attributes
Object.defineProperties(Base.prototype, {
attributes: {
get: function () {
return this._getAttributes(true);
}
},
derived: {
get: function () {
var res = {};
for (var item in this._derived) res[item] = this._derived[item].fn.apply(this);
return res;
}
}
});
// helper for creating/storing property definitions and creating
// appropriate getters/setters
var createPropertyDefinition = function (object, name, desc, isSession) {
var def = object._definition[name] = {};
var type;
if (_.isString(desc)) {
// grab our type if all we've got is a string
type = object._ensureValidType(desc);
if (type) def.type = type;
} else {
type = object._ensureValidType(desc[0] || desc.type);
if (type) def.type = type;
if (desc[1] || desc.required) def.required = true;
// set default if defined
def.default = !_.isUndefined(desc[2]) ? desc[2] : desc.default;
def.allowNull = desc.allowNull ? desc.allowNull : false;
if (desc.setOnce) def.setOnce = true;
if (def.required && _.isUndefined(def.default)) def.default = object._getDefaultForType(type);
def.test = desc.test;
def.values = desc.values;
}
if (isSession) def.session = true;
// define a getter/setter on the prototype
// but they get/set on the instance
Object.defineProperty(object, name, {
set: function (val) {
this.set(name, val);
},
get: function () {
var result = this._values[name];
if (typeof result !== 'undefined') {
if (dataTypes[def.type] && dataTypes[def.type].get) {
result = dataTypes[def.type].get(result);
}
return result;
}
return def.default;
}
});
return def;
};
// Underscore methods we want to add
_.each(['keys', 'values', 'pairs', 'invert', 'pick', 'omit'], function (method) {
prototypeMixins[method] = function () {
var args = Array.prototype.slice.call(arguments);
args.unshift(this.attributes);
return _[method].apply(_, args);
// helper for creating derived property definitions
var createDerivedProperty = function (modelProto, name, definition) {
var def = modelProto._derived[name] = {
fn: _.isFunction(definition) ? definition : definition.fn,
cache: (definition.cache !== false),
depList: definition.deps || []
};
});
// add event methods
BBEvents.mixin(prototypeMixins);
// add to our shared dependency list
_.each(def.depList, function (dep) {
modelProto._deps[dep] = _(modelProto._deps[dep] || []).union([name]);
});
// our dataTypes
var dataTypes = {
// defined a top-level getter for derived names
Object.defineProperty(modelProto, name, {
get: function () {
return this._getDerivedProperty(name);
},
set: function () {
throw new TypeError('"' + name + '" is a derived property, it can\'t be set directly.');
}
});
};
// the extend method used to extend prototypes, maintain inheritance chains for instanceof
// and allow for additions to the model definitions.
var extend = function (protoProps) {
var parent = this;
var child;
var args = [].slice.call(arguments);
var prop, item;
// The constructor function for the new subclass is either defined by you
// (the "constructor" property in your `extend` definition), or defaulted
// by us to simply call the parent's constructor.
if (protoProps && protoProps.hasOwnProperty('constructor')) {
child = protoProps.constructor;
} else {
child = function () {
return parent.apply(this, arguments);
};
}
// Add static properties to the constructor function from parent
_.extend(child, parent);
// Set the prototype chain to inherit from `parent`, without calling
// `parent`'s constructor function.
var Surrogate = function () { this.constructor = child; };
Surrogate.prototype = parent.prototype;
child.prototype = new Surrogate();
// set prototype level objects
child.prototype._derived = _.extend({}, parent.prototype._derived);
child.prototype._deps = _.extend({}, parent.prototype._deps);
child.prototype._definition = _.extend({}, parent.prototype._definition);
// Mix in all prototype properties to the subclass if supplied.
if (protoProps) {
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;
_.extend(child.prototype, def);
});
}
// Set a convenience property in case the parent's prototype is needed
// later.
child.__super__ = parent.prototype;
return child;
};
// also expose data types in our export
var dataTypes = Base.dataTypes = {
date: {

@@ -514,114 +582,2 @@ set: function (newVal) {

};
var arrayNext = function (array, currentItem) {
var len = array.length;
var newIndex = array.indexOf(currentItem) + 1;
if (newIndex > (len - 1)) newIndex = 0;
return array[newIndex];
};
var createDerivedProperty = function (modelProto, name, definition) {
var def = modelProto._derived[name] = {
fn: _.isFunction(definition) ? definition : definition.fn,
cache: (definition.cache !== false),
depList: definition.deps || []
};
// add to our shared dependency list
_.each(def.depList, function (dep) {
modelProto._deps[dep] = _(modelProto._deps[dep] || []).union([name]);
});
// defined a top-level getter for derived names
Object.defineProperty(modelProto, name, {
get: function () {
return this._getDerivedProperty(name);
},
set: function () {
throw new TypeError('"' + name + '" is a derived property, it can\'t be set directly.');
}
});
};
var extend = function (spec) {
spec = spec || {};
var parent = this;
var BaseClass = this._super || Base;
var props, session, derived, collections;
function State() {
BaseClass.apply(this, arguments);
}
// Add our special accessor properties
Object.defineProperties(State.prototype, accessors);
// Mix in our methods
_.extend(State.prototype, prototypeMixins, {
// storage for our rules about derived properties
_derived: {},
_deps: {},
_definition: {}
});
// Copy any methods from existing prototype
_.each(BaseClass.prototype, function (value, key) {
if (value instanceof Function) {
State.prototype[key] = value;
}
});
// Pull out previous model spec
if (this._spec) {
props = this._spec.props;
session = this._spec.session;
derived = this._spec.derived;
collections = this._spec.collections;
}
// Extend previous with new special attributes
State._spec = {
props: _.extend({}, props, spec.props),
session: _.extend({}, session, spec.session),
derived: _.extend({}, derived, spec.derived),
collections: _.extend({}, collections, spec.collections)
};
// remove handled references before we loop
delete spec.props;
delete spec.session;
delete spec.derived;
delete spec.collections;
// Extend spec with any new proto methods we may have just added
_.extend(State._spec, spec);
_.each(State._spec, function (value, key) {
if (key === 'props' || key === 'session') {
_.each(value, function (def, name) {
State.prototype._createPropertyDefinition.call(State.prototype, name, def, key === 'session');
});
} else if (key === 'derived') {
_.each(value, function (def, name) {
createDerivedProperty(State.prototype, name, def);
});
} else if (key === 'collections') {
State.prototype._collections = value;
} else {
State.prototype[key] = value;
}
});
// Keep reference to super human™
State._super = State;
// Maintain ability to further extend
State.extend = extend;
State.dataTypes = dataTypes;
return State;
};
// also expose data types in our export
Base.dataTypes = dataTypes;
Base.extend = extend;

@@ -628,0 +584,0 @@

{
"name": "ampersand-state",
"description": "An observable, extensible state object with derived watchable properties.",
"version": "0.3.2",
"version": "0.4.0",
"author": "Henrik Joreteg <henrik@andyet.net>",

@@ -11,6 +11,10 @@ "bugs": {

"backbone-events-standalone": "~0.2.1",
"underscore": "~1.6.0"
"underscore": "~1.6.0",
"array-next": "~0.0.1"
},
"devDependencies": {
"tape": "~2.11.0"
"ampersand-registry": "0.x.x",
"run-browser": "~1.2.0",
"tape": "~2.11.0",
"precommit-hook": "~0.3.10"
},

@@ -30,3 +34,5 @@ "homepage": "https://github.com/ampersandjs/ampersand-state",

"scripts": {
"test": "node test/main.js"
"test": "node test/index.js",
"validate": "jshint .",
"start": "run-browser test/index.js"
},

@@ -33,0 +39,0 @@ "testling": {

@@ -261,4 +261,4 @@ # ampersand-state

// *BUT* it doesn't maintain the prototype chain
// so instanceof checks will fail up the chain
// it also maintains the prototype chain
// so instanceof checks will work up the chain

@@ -268,4 +268,4 @@ // so this is true

// but this is false
awesome instanceof Person; // false
// and so is this
awesome instanceof Person; // true

@@ -276,2 +276,3 @@ ```

- 0.1.0 - lots of cleanup, grabbing tests from human-model, now maintains the prototype chain so `instanceof` checks pass no matter how many times it's been extended.
- 0.0.2 - improved doc

@@ -278,0 +279,0 @@ - 0.0.1 - initial publish

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc