Comparing version 0.0.1 to 0.1.0
@@ -1,1 +0,1 @@ | ||
module.exports = require('./lib/McFly'); | ||
module.exports = require('./lib/Biff'); |
@@ -1,15 +0,5 @@ | ||
'use strict'; | ||
var Dispatcher = require('./Dispatcher'); | ||
var Promise = require('es6-promise').Promise; | ||
"use strict"; | ||
var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; | ||
function reThrow(reject, error) { | ||
setTimeout(function(){ | ||
if (error && error.stack) { | ||
console.error(error.stack); | ||
} | ||
throw error; }, 0); | ||
return reject(); | ||
} | ||
/** | ||
@@ -19,40 +9,17 @@ * Action class | ||
var Action = | ||
/** | ||
* Constructs an Action object | ||
* | ||
* @param {function} callback - Callback method for Action | ||
* @constructor | ||
*/ | ||
function Action(callback) { | ||
this.callback = callback; | ||
} | ||
/** | ||
* Constructs an Action object | ||
* | ||
* @param {function} callback - Callback method for Action | ||
* @constructor | ||
*/ | ||
function Action(callback, dispatcher) { | ||
_classCallCheck(this, Action); | ||
/** | ||
* Calls callback method from Dispatcher | ||
* | ||
* @param {...*} arguments - arguments for callback method | ||
* @returns Promise object | ||
*/ | ||
Action.prototype.dispatch=function() { | ||
return Promise.resolve(this.callback.apply(this, arguments)) | ||
.then(function(payload){ | ||
return new Promise(function(resolve, reject){ | ||
if (!payload) return reject(); | ||
if (!payload.actionType) return reThrow(reject, | ||
"Payload object requires an actionType property" | ||
); | ||
this.callback = callback; | ||
this.dispatch = dispatcher.dispatch.bind(dispatcher); | ||
}; | ||
try { | ||
Dispatcher.dispatch(payload); | ||
} catch (error) { | ||
reThrow(reject, error); | ||
} | ||
resolve(); | ||
}); | ||
}); | ||
}; | ||
module.exports = Action; | ||
module.exports = Action; |
@@ -1,6 +0,8 @@ | ||
'use strict'; | ||
"use strict"; | ||
var Action = require('./Action'); | ||
var assign = require('object-assign'); | ||
var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; | ||
var Action = require("./Action"); | ||
var assign = require("object-assign"); | ||
/** | ||
@@ -10,22 +12,27 @@ * ActionsFactory class | ||
var ActionsFactory = | ||
/** | ||
* Constructs an ActionsFactory object and translates actions parameter into | ||
* Action objects. | ||
* | ||
* @param {object} actions - Object with methods to create actions with | ||
* @constructor | ||
*/ | ||
function ActionsFactory(actions) { | ||
var $ActionsFactory_actions = {}, a, action; | ||
for (a in actions) { | ||
if(actions.hasOwnProperty(a)){ | ||
action = new Action(actions[a]); | ||
$ActionsFactory_actions[a] = action.dispatch.bind(action); | ||
} | ||
/** | ||
* Constructs an ActionsFactory object and translates actions parameter into | ||
* Action objects. | ||
* | ||
* @param {object} actions - Object with methods to create actions with | ||
* @constructor | ||
*/ | ||
function ActionsFactory(actions, dispatcher) { | ||
_classCallCheck(this, ActionsFactory); | ||
var _actions = {}; | ||
var a; | ||
var action; | ||
for (a in actions) { | ||
if (actions.hasOwnProperty(a)) { | ||
action = new Action(actions[a], dispatcher); | ||
_actions[a] = action.callback.bind(action); | ||
} | ||
assign(this, $ActionsFactory_actions); | ||
} | ||
assign(this, _actions); | ||
}; | ||
module.exports = ActionsFactory; | ||
module.exports = ActionsFactory; |
237
lib/Store.js
@@ -1,7 +0,11 @@ | ||
'use strict'; | ||
"use strict"; | ||
var EventEmitter = require('events').EventEmitter; | ||
var assign = require('object-assign'); | ||
var iv = require('invariant'); | ||
var _prototypeProperties = function (child, staticProps, instanceProps) { if (staticProps) Object.defineProperties(child, staticProps); if (instanceProps) Object.defineProperties(child.prototype, instanceProps); }; | ||
var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; | ||
var EventEmitter = require("events").EventEmitter; | ||
var assign = require("object-assign"); | ||
var con = require("./util/console"); | ||
/** | ||
@@ -11,2 +15,3 @@ * Store class | ||
var Store = (function () { | ||
@@ -21,62 +26,198 @@ /** | ||
*/ | ||
function Store(methods, callback) { | ||
_classCallCheck(this, Store); | ||
var self = this; | ||
this.callback = callback; | ||
iv(!methods.callback, '"callback" is a reserved name and cannot be used as a method name.'); | ||
iv(!methods.mixin,'"mixin" is a reserved name and cannot be used as a method name.'); | ||
this.callback = callback.bind(this); | ||
this._pending = false; | ||
this._errors = []; | ||
if (process.env.NODE_ENV !== "production" && methods.callback) { | ||
throw new Error("Invariant Violation: \"callback\" is a reserved name and cannot be used as a method name."); | ||
} | ||
if (process.env.NODE_ENV !== "production" && methods.mixin) { | ||
throw new Error("Invariant Violation: \"mixin\" is a reserved name and cannot be used as a method name."); | ||
} | ||
assign(this, EventEmitter.prototype, methods); | ||
this.mixin = { | ||
componentDidMount: function() { | ||
var warn = (console.warn || console.log).bind(console), | ||
changeFn; | ||
if(!this.storeDidChange){ | ||
warn("A component that uses a McFly Store mixin is not implementing storeDidChange. onChange will be called instead, but this will no longer be supported from version 1.0."); | ||
componentDidMount: function componentDidMount() { | ||
var _this = this; | ||
if (!this.storeDidChange) { | ||
con.warn("A change handler is missing from a component with a Biff mixin. Notifications from Stores are not being handled."); | ||
} | ||
changeFn = this.storeDidChange || this.onChange; | ||
if(!changeFn){ | ||
warn("A change handler is missing from a component with a McFly mixin. Notifications from Stores are not being handled."); | ||
} | ||
this.listener = function(){ this.isMounted() && changeFn(); }.bind(this) | ||
this.listener = function () { | ||
_this.isMounted() && _this.storeDidChange(); | ||
}; | ||
this.errorListener = function (event) { | ||
_this.isMounted() && _this.storeError && _this.storeError.call(_this, event); | ||
}; | ||
self.addChangeListener(this.listener); | ||
self.addErrorListener(this.errorListener); | ||
}, | ||
componentWillUnmount: function() { | ||
componentWillUnmount: function componentWillUnmount() { | ||
this.listener && self.removeChangeListener(this.listener); | ||
this.errorListener && self.removeErrorListener(this.errorListener); | ||
} | ||
} | ||
}; | ||
} | ||
/** | ||
* Returns dispatch token | ||
*/ | ||
Store.prototype.getDispatchToken=function() { | ||
return this.dispatcherID; | ||
}; | ||
_prototypeProperties(Store, null, { | ||
getDispatchToken: { | ||
/** | ||
* Emits change event | ||
*/ | ||
Store.prototype.emitChange=function() { | ||
this.emit('change'); | ||
}; | ||
/** | ||
* Returns dispatch token | ||
*/ | ||
/** | ||
* Adds a change listener | ||
* | ||
* @param {function} callback - Callback method for change event | ||
*/ | ||
Store.prototype.addChangeListener=function(callback) { | ||
this.on('change', callback); | ||
}; | ||
value: function getDispatchToken() { | ||
return this.dispatcherID; | ||
}, | ||
writable: true, | ||
configurable: true | ||
}, | ||
getPending: { | ||
/** | ||
* Removes a change listener | ||
* | ||
* @param {function} callback - Callback method for change event | ||
*/ | ||
Store.prototype.removeChangeListener=function(callback) { | ||
this.removeListener('change', callback); | ||
}; | ||
/** | ||
* Returns a Store's "pending" state | ||
*/ | ||
value: function getPending() { | ||
return this._pending; | ||
}, | ||
writable: true, | ||
configurable: true | ||
}, | ||
_setPending: { | ||
/** | ||
* Sets a Store's "pending" state | ||
*/ | ||
module.exports = Store; | ||
value: function _setPending(pending) { | ||
this._pending = pending; | ||
}, | ||
writable: true, | ||
configurable: true | ||
}, | ||
getErrors: { | ||
/** | ||
* Returns a Store's "errors" array | ||
*/ | ||
value: function getErrors() { | ||
return this._errors; | ||
}, | ||
writable: true, | ||
configurable: true | ||
}, | ||
_setError: { | ||
/** | ||
* Adds an error to a Store's "errors" array | ||
*/ | ||
value: function _setError(error) { | ||
this._errors.push(error); | ||
}, | ||
writable: true, | ||
configurable: true | ||
}, | ||
_clearErrors: { | ||
/** | ||
* Clears a Store's "errors" array | ||
*/ | ||
value: function _clearErrors(error) { | ||
this._errors.splice(0, this.errors.length); | ||
}, | ||
writable: true, | ||
configurable: true | ||
}, | ||
emitChange: { | ||
/** | ||
* Emits change event | ||
*/ | ||
value: function emitChange() { | ||
this.emit("change"); | ||
}, | ||
writable: true, | ||
configurable: true | ||
}, | ||
emitError: { | ||
/** | ||
* Emits an error event | ||
*/ | ||
value: function emitError() { | ||
this.emit("error", arguments); | ||
}, | ||
writable: true, | ||
configurable: true | ||
}, | ||
addChangeListener: { | ||
/** | ||
* Adds a change listener | ||
* | ||
* @param {function} callback - Callback method for change event | ||
*/ | ||
value: function addChangeListener(callback) { | ||
this.on("change", callback); | ||
}, | ||
writable: true, | ||
configurable: true | ||
}, | ||
removeChangeListener: { | ||
/** | ||
* Removes a change listener | ||
* | ||
* @param {function} callback - Callback method for change event | ||
*/ | ||
value: function removeChangeListener(callback) { | ||
this.removeListener("change", callback); | ||
}, | ||
writable: true, | ||
configurable: true | ||
}, | ||
addErrorListener: { | ||
/** | ||
* Adds an error listener | ||
* | ||
* @param {function} callback - Callback method for error event | ||
*/ | ||
value: function addErrorListener(callback) { | ||
this.on("error", callback); | ||
}, | ||
writable: true, | ||
configurable: true | ||
}, | ||
removeErrorListener: { | ||
/** | ||
* Removes an error listener | ||
* | ||
* @param {function} callback - Callback method for error event | ||
*/ | ||
value: function removeErrorListener(callback) { | ||
this.removeListener("error", callback); | ||
}, | ||
writable: true, | ||
configurable: true | ||
} | ||
}); | ||
return Store; | ||
})(); | ||
module.exports = Store; |
{ | ||
"name": "biff", | ||
"version": "0.0.1", | ||
"version": "0.1.0", | ||
"description": "Flux architecture made easy", | ||
@@ -8,3 +8,3 @@ "keywords": [ | ||
"react", | ||
"mcfly" | ||
"biff" | ||
], | ||
@@ -20,5 +20,5 @@ "files": [ | ||
"type": "git", | ||
"url": "https://github.com/kenwheeler/mcfly" | ||
"url": "https://github.com/formidablelabs/biff" | ||
}, | ||
"bugs": "https://github.com/kenwheeler/mcfly/issues", | ||
"bugs": "https://github.com/formidablelabs/biff/issues", | ||
"license": "BSD", | ||
@@ -35,4 +35,4 @@ "scripts": { | ||
"flux": "^2.0.1", | ||
"invariant": "^1.0.2", | ||
"object-assign": "^1.0.0" | ||
"object-assign": "^1.0.0", | ||
"simple-console": "^0.1.0" | ||
}, | ||
@@ -42,9 +42,10 @@ "devDependencies": { | ||
"del": "^0.1.2", | ||
"envify": "^3.2.0", | ||
"gulp": "^3.8.6", | ||
"gulp-react": "^0.5.0", | ||
"gulp-babel": "^4.0.0", | ||
"gulp-jscs-custom": "^0.1.2", | ||
"gulp-replace": "^0.4.0", | ||
"jest-cli": "^0.1.18", | ||
"react-tools": "^0.12.0", | ||
"jest-cli": "^0.4.0", | ||
"vinyl-source-stream": "^0.1.1" | ||
} | ||
} |
168
README.md
@@ -1,36 +0,55 @@ | ||
#McFly | ||
#Biff | ||
Flux Architecture Made Easy | ||
*What is McFly?* | ||
*What is Biff?* | ||
When writing ReactJS apps, it is enormously helpful to use Facebook's Flux architecture. It truly complements ReactJS' unidirectional data flow model. Facebook's Flux library provides a Dispatcher, and some examples of how to write Actions and Stores. However, there are no helpers for Action & Store creation, and Stores require 3rd part eventing. | ||
McFly is a library that provides all 3 components of Flux architecture, using Facebook's Dispatcher, and providing factories for Actions & Stores. | ||
Biff is a library that provides all 3 components of Flux architecture, using Facebook's Dispatcher, and providing factories for Actions & Stores. | ||
###Demo | ||
Check out this JSFiddle Demo to see how McFly can work for you: | ||
Check out this JSFiddle Demo to see how Biff can work for you: | ||
[http://jsfiddle.net/6rauuetb/](http://jsfiddle.net/6rauuetb/) | ||
[http://jsfiddle.net/2xtqx3u3/](http://jsfiddle.net/2xtqx3u3/) | ||
###Dispatcher | ||
###Getting Started | ||
McFly uses Facebook Flux's dispatcher. When McFly is instantiated, and a single dispatcher instance is created and can be accessed like shown below: | ||
The first step to using Biff is to create a new instance of Biff. | ||
####Standalone | ||
```javascript | ||
var mcFly = new McFly(); | ||
var biff = new Biff(); | ||
``` | ||
return mcFly.dispatcher; | ||
####Modular | ||
```javascript | ||
var Biff = require('biff'); | ||
module.exports = new Biff(); | ||
``` | ||
In fact, all created Actions & Stores are also stored on the McFly object as `actions` and `stores` respectively. | ||
Each instance of Biff has its own Dispatcher instance created and attached. | ||
In fact, all created Actions & Stores are also stored on the Biff object as `actions` and `stores` respectively. | ||
```javascript | ||
biff.dispatcher // Dispatcher instance | ||
biff.actions // Array of actions | ||
biff.stores // Array of stores | ||
``` | ||
###Stores | ||
McFly has a **createStore** helper method that creates an instance of a Store. Store instances have been merged with EventEmitter and come with **emitChange**, **addChangeListener** and **removeChangeListener** methods built in. | ||
Biff has a **createStore** helper method that creates an instance of a Store. Store instances have been merged with EventEmitter and come with **emitChange**, **addChangeListener** and **removeChangeListener** methods built in. | ||
When a store is created, its methods parameter specified what public methods should be added to the Store object. Every store is automatically registered with the Dispatcher and the `dispatcherID` is stored on the Store object itself, for use in `waitFor` methods. | ||
Creating a store with McFly looks like this: | ||
Creating a store with Biff looks like this: | ||
```javascript | ||
// Require the Biff instance you created | ||
var biff = require('./biff'); | ||
// Internal data object | ||
var _todos = []; | ||
@@ -42,3 +61,3 @@ | ||
var TodoStore = mcFly.createStore({ | ||
var TodoStore = biff.createStore({ | ||
@@ -54,2 +73,3 @@ getTodos: function() { | ||
addTodo(payload.text); | ||
this.emitChange(); | ||
break; | ||
@@ -60,4 +80,2 @@ default: | ||
TodoStore.emitChange(); | ||
return true; | ||
@@ -71,5 +89,6 @@ | ||
```javascript | ||
var mcFly = new McFly(); | ||
var Dispatcher = mcFly.dispatcher; | ||
var biff = require('./biff'); | ||
var Dispatcher = Biff.dispatcher; | ||
var OtherStore = require('../stores/OtherStore'); | ||
var _todos = []; | ||
@@ -102,8 +121,99 @@ | ||
mixins: [TodoStore.mixin], | ||
storeDidChange: function () { | ||
// Handle store change here | ||
} | ||
... | ||
``` | ||
This mixin also adds listeners that call a **storeError** component method, so that if you call `this.emitError('Error Messaging')` in your store, you can respond and handle this in your components: | ||
```javascript | ||
var TodoStore = require('../stores/TodoStore'); | ||
var TodoApp = React.createClass({ | ||
mixins: [TodoStore.mixin], | ||
storeError: function (error) { | ||
console.log(error); | ||
} | ||
... | ||
``` | ||
A simple example of how this works can be seen here: | ||
[http://jsfiddle.net/p6q8ghpc/](http://jsfiddle.net/p6q8ghpc/) | ||
Stores in Biff also have helpers for managing the state of the store's data. Each Biff instance has `_pending` and `_errors` properties. These are exposed via getters and setters. These methods are: | ||
- getPending() - Returns store pending state | ||
- getErrors() - Returns store errors array | ||
- _setPending(arg) - Sets store pending state | ||
- _setError(arg) - Adds an error to the store errors array | ||
- _clearErrors() - Clears store errors array | ||
Below, see an example of how they can be used: | ||
```javascript | ||
// In Your Store | ||
var TodoStore = biff.createStore({ | ||
getTodos: function() { | ||
return _todos; | ||
} | ||
}, function(payload){ | ||
switch(payload.actionType) { | ||
case 'ADD_START': | ||
this._setPending(true); | ||
break; | ||
case 'ADD_SUCCESS': | ||
this._setPending(false); | ||
addTodo(payload.text); | ||
this._clearErrors(); | ||
this.emitChange(); | ||
break; | ||
case 'ADD_ERROR': | ||
this._setPending(false); | ||
this._setError(payload.error); | ||
this.emitChange(); | ||
break; | ||
default: | ||
return true; | ||
} | ||
return true; | ||
}); | ||
// In your component | ||
function getState(){ | ||
return { | ||
errors: TodoStore.getErrors() | ||
pending: TodoStore.getPending() | ||
todos: TodoStore.getTodos() | ||
} | ||
} | ||
var TodoApp = React.createClass({ | ||
mixins: [TodoStore.mixin], | ||
getInitialState: function () { | ||
return getState(); | ||
}, | ||
storeDidChange: function () { | ||
this.setState(getState()); | ||
} | ||
... | ||
``` | ||
###Actions | ||
McFly's **createActions** method creates an Action Creator object with the supplied singleton object. The supplied methods are inserted into a Dispatcher.dispatch call and returned with their original name, so that when you call these methods, the dispatch takes place automatically. | ||
Biff's **createActions** method creates an Action Creator object with the supplied singleton object. The methods of the supplied object are given an instance of the Biff instance's dispatcher object so that you can make dispatch calls from them. It is available via `this.dispatch` in the interior of your methods. | ||
@@ -113,10 +223,10 @@ Adding actions to your app looks like this: | ||
```javascript | ||
var mcFly = require('../controller/mcFly'); | ||
var biff = require('../biff'); | ||
var TodoActions = mcFly.createActions({ | ||
var TodoActions = biff.createActions({ | ||
addTodo: function(text) { | ||
return { | ||
this.dispatch({ | ||
actionType: 'ADD_TODO', | ||
text: text | ||
} | ||
}); | ||
} | ||
@@ -126,16 +236,16 @@ }); | ||
All actions methods return promise objects so that components can respond to long functions. The promise will be resolved with no parameters as information should travel through the dispatcher and stores. To reject the promise, return a falsy value from the action's method. The dispatcher will not be called if the returned value is falsy or has no actionType. | ||
### Async In Biff | ||
You can see an example of how to use this functionality here: | ||
Check out the example below to show you can handle async in Biff: | ||
http://jsfiddle.net/thekenwheeler/32hgqsxt/ | ||
http://jsfiddle.net/29L0anf1/ | ||
## API | ||
###McFly | ||
###Biff | ||
```javascript | ||
var McFly = require('mcfly'); | ||
var Biff = require('biff'); | ||
var mcFly = new McFly(); | ||
module.exports = new Biff(); | ||
``` | ||
@@ -160,2 +270,2 @@ | ||
*/ | ||
``` | ||
``` |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
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
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
17982
294
263
9
3
2
+ Addedsimple-console@^0.1.0
+ Addedsimple-console@0.1.1(transitive)
- Removedinvariant@^1.0.2
- Removedinvariant@1.0.2(transitive)