Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

cerebral

Package Overview
Dependencies
Maintainers
1
Versions
638
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cerebral - npm Package Compare versions

Comparing version 0.20.5 to 0.20.6

demo/signals/allTodosClicked.js

34

CHANGELOG.md

@@ -0,1 +1,35 @@

# 0.20.2
- Several updates to the webpage
- IE 9 support
- Signals will not fail with no actions
- `unset` can now take a second array argument to unset multiple keys on objects
- `defaultInput` can now be attached to an action to set default inputs to that action
- The **experimental** compute functions are in
- State packages now uses a concept of *accessors*. Now you can use `state.key(path)` and `state.findWhere(path, checkObj)` in addition to `state.get(path)`. You can also use `state.export()` for guaranteed serialized version of store and `state.import(obj)` to deep merge state
- Fixed error on custom outputs where indexes were shown in error instead of output names
- Synchronous actions running async output now throws error
- Now all signal are defined with an array `signal('appMounted', [syncAction])`. You will getting a DEPRECATION warning if not doing so. The reason is that signals are most commonly defined in separate files as arrays. It will also be easier for new devs to learn how to read signals. "Arrays inside arrays means actions runs async". "Arrays defined as paths runs sync"
- By default signals are **not** stored in localStorage on refresh. People not using the debugger should not have an insane amounts of signals in their local storage :-) Will also make sure that if the debugger has not been registered to the app it will not store signals, even though it is set to do so
# 0.19.4
- The debugger has been updated
- Buttons to step, instead of slider
- Now always remembers state
- You can check/uncheck if you want to reset state on refresh
- Fixed issues with Baobab Monkeys
# 0.19.0
- Namespace signals
- Better error on non serializable inputs
- Passing the signal itself on `signalStart` and `signalEnd` events
- Naming actions
- `import` and `export` methods exposed on the state store
- The recorder is now a default service
- Durations are displayed in the debugger
- Signals now has a `sync` method on them to trigger the signal synchronously (for inputs etc.)
- A couple of small UI fixes on the debugger
- Paths on sync actions now remembered correctly
- Increased debugger debounce to 100ms. Fixes problem where lots of signals trigger
# 0.18.4

@@ -2,0 +36,0 @@ > Changes since 0.17.7

2

demo/actions/clearCompleted.js

@@ -7,3 +7,3 @@ function clearCompleted (args, state) {

if (todos[key].completed && !todos[key].$isSaving) {
state.unset('todos', key);
state.unset(['todos', key]);
}

@@ -10,0 +10,0 @@ });

@@ -8,6 +8,7 @@ import React from 'react';

@Cerebral({
visibleTodos: 'visibleTodos',
todos: ['todos'],
recorder: ['recorder'],
isSaving: ['isSaving']
}, {
visibleTodos: ['visibleTodos']
})

@@ -14,0 +15,0 @@ class App extends React.Component {

@@ -1,14 +0,12 @@

import React from 'react/addons';
import React from 'react';
import {Decorator as Cerebral} from 'cerebral-react';
@Cerebral((props) => {
return {
remainingCount: ['remainingCount'],
filter: ['filter'],
completedCount: ['completedCount']
}
@Cerebral({
filter: ['filter']
}, {
counts: ['counts']
})
class TodosFooter extends React.Component {
renderRemainingCount() {
let count = this.props.remainingCount;
let count = this.props.counts.remainingCount;
if (count === 0 || count > 1) {

@@ -28,3 +26,3 @@ return count + ' items left';

<button id="clear-completed" onClick={() => this.props.signals.clearCompletedClicked()}>
Clear completed ({this.props.completedCount})
Clear completed ({this.props.counts.completedCount})
</button>

@@ -49,3 +47,3 @@ );

</ul>
{this.props.completedCount ? this.renderCompletedButton() : null}
{this.props.counts.completedCount ? this.renderCompletedButton() : null}
</footer>

@@ -52,0 +50,0 @@ );

@@ -5,5 +5,5 @@ import React from 'react';

@Cerebral({
todos: 'visibleTodos',
isAllChecked: ['isAllChecked']
@Cerebral({}, {
isAllChecked: ['isAllChecked'],
todos: ['visibleTodos']
})

@@ -10,0 +10,0 @@ class TodosList extends React.Component {

@@ -25,12 +25,56 @@ import Controller from './../src/index.js';

const controller = Controller(model);
const services = {};
controller.compute({
const computed = {
visibleTodos: function (get) {
return get(['visibleTodosRefs']).map(function (id) {
return get(['todos', id]);
const todos = get(['todos']);
const filter = get(['filter']);
return Object.keys(todos).filter(function(key) {
let todo = todos[key];
return (
filter === 'all' ||
(filter === 'completed' && todo.completed) ||
(filter === 'active' && !todo.completed)
);
}).map(function (key) {
return todos[key];
});
},
isAllChecked: function (get, getComputed) {
let todos = getComputed(['visibleTodos']);
return todos.filter(function(todo) {
return !todo.completed;
}).length === 0 && todos.length !== 0;
},
counts: function (get) {
let todos = get(['todos']);
let counts = Object.keys(todos).reduce(function(counts, key) {
let todo = todos[key];
if (todo.completed) {
counts.completedCount++;
} else if (!todo.completed) {
counts.remainingCount++;
}
return counts;
}, {
completedCount: 0,
remainingCount: 0
});
return {
remainingCount: counts.remainingCount,
completedCount: counts.completedCount
};
}
});
};
export default controller;
export default Controller(model, services, computed);

@@ -6,2 +6,3 @@ import './../node_modules/todomvc-common/base.css';

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.js';

@@ -12,59 +13,32 @@ import controller from './controller.js';

console.log(React.PropTypes.string(false, {foo: 'bar'}, 'foo'));
import allTodosClicked from './signals/allTodosClicked.js';
import newTodoTitleChanged from './signals/newTodoTitleChanged.js';
import newTodoSubmitted from './signals/newTodoSubmitted.js';
import removeTodoClicked from './signals/removeTodoClicked.js';
import toggleCompletedChanged from './signals/toggleCompletedChanged.js';
import toggleAllChanged from './signals/toggleAllChanged.js';
import filterClicked from './signals/filterClicked.js';
import clearCompletedClicked from './signals/clearCompletedClicked.js';
import todoDoubleClicked from './signals/todoDoubleClicked.js';
import newTitleChanged from './signals/newTitleChanged.js';
import newTitleSubmitted from './signals/newTitleSubmitted.js';
import recordClicked from './signals/recordClicked.js';
import playClicked from './signals/playClicked.js';
import stopClicked from './signals/stopClicked.js';
// ACTIONS
import addTodo from './actions/addTodo.js';
import removeTodo from './actions/removeTodo.js';
import toggleTodoCompleted from './actions/toggleTodoCompleted.js';
import setVisibleTodos from './actions/setVisibleTodos.js';
import setNewTodoTitle from './actions/setNewTodoTitle.js';
import setAllChecked from './actions/setAllChecked.js';
import setCounters from './actions/setCounters.js';
import toggleAllChecked from './actions/toggleAllChecked.js';
import saveTodo from './actions/saveTodo.js';
import updateTodo from './actions/updateTodo.js';
import setFilter from './actions/setFilter.js';
import clearCompleted from './actions/clearCompleted.js';
import editTodo from './actions/editTodo.js';
import setTodoNewTitle from './actions/setTodoNewTitle.js';
import stopEditingTodo from './actions/stopEditingTodo.js';
import setUrl from './actions/setUrl.js';
import unsetFilter from './actions/unsetFilter.js';
import setTodoError from './actions/setTodoError.js';
import record from './actions/record.js';
import stop from './actions/stop.js';
import play from './actions/play.js';
import setSaving from './actions/setSaving.js';
import unsetSaving from './actions/unsetSaving.js';
controller.signal('allTodosClicked', allTodosClicked);
controller.signal('newTodoTitleChanged', newTodoTitleChanged);
controller.signal('newTodoSubmitted', newTodoSubmitted);
controller.signal('removeTodoClicked', removeTodoClicked);
controller.signal('toggleCompletedChanged', toggleCompletedChanged);
controller.signal('toggleAllChanged', toggleAllChanged);
controller.signal('filterClicked', filterClicked);
controller.signal('clearCompletedClicked', clearCompletedClicked);
controller.signal('todoDoubleClicked', todoDoubleClicked);
controller.signal('newTitleChanged', newTitleChanged);
controller.signal('newTitleSubmitted', newTitleSubmitted);
controller.signal('recordClicked', recordClicked);
controller.signal('playClicked', playClicked);
controller.signal('stopClicked', stopClicked);
// SIGNALS
controller.signal('allTodosClicked', [unsetFilter, setVisibleTodos])
controller.signal('newTodoTitleChanged', [setNewTodoTitle]);
controller.signal('newTodoSubmitted', [
addTodo,
setVisibleTodos,
setAllChecked,
setCounters,
setSaving,
[
saveTodo, {
success: [updateTodo],
error: [setTodoError]
}
],
unsetSaving
]);
controller.signal('removeTodoClicked', [removeTodo, setVisibleTodos, setAllChecked, setCounters]);
controller.signal('toggleCompletedChanged', [toggleTodoCompleted, setVisibleTodos, setAllChecked, setCounters]);
controller.signal('toggleAllChanged', [toggleAllChecked, setVisibleTodos, setCounters]);
controller.signal('filterClicked', [setFilter, setVisibleTodos]);
controller.signal('clearCompletedClicked', [clearCompleted, setVisibleTodos, setAllChecked, setCounters]);
controller.signal('todoDoubleClicked', [editTodo]);
controller.signal('newTitleChanged', [setTodoNewTitle]);
controller.signal('newTitleSubmitted', [stopEditingTodo]);
controller.signal('recordClicked', [record]);
controller.signal('playClicked', [play]);
controller.signal('stopClicked', [stop]);
// ROUTER

@@ -79,2 +53,5 @@ const router = CerebralRouter(controller, {

// RENDER
React.render(<Container controller={controller} app={App}/>, document.querySelector('#app'));
ReactDOM.render(
<Container controller={controller}>
<App/>
</Container>, document.querySelector('#app'));
{
"name": "cerebral",
"version": "0.20.5",
"version": "0.20.6",
"description": "A state controller with its own debugger",

@@ -29,3 +29,4 @@ "main": "src/index.js",

"nodeunit-watcher": "0.0.3",
"react": "^0.13.3",
"react": "^0.14.0",
"react-dom": "^0.14.0",
"style-loader": "^0.8.3",

@@ -32,0 +33,0 @@ "todomvc-app-css": "^1.0.1",

@@ -7,2 +7,25 @@ var utils = require('./utils.js');

var getComputedValue = function (path) {
if (!computed) {
return;
}
if (typeof path === 'string') {
path = path.split('.');
} else {
path = path.slice();
}
var level = computed;
var key = path.pop();
while(path.length) {
level = level[path.shift()];
}
if (typeof level[key] !== 'function') {
throw new Error('CEREBRAL Computed - You are not passing a correct path to a computed');
}
return level[key]();
};
var createMapper = function(stringPath, cb) {

@@ -12,9 +35,13 @@

var currentState = {};
var currentComputedState = {};
var currentValue;
var get = function(path) {
path = typeof path === 'string' ? [].slice.call(arguments) : path;
return currentState[path.join('.')] = model.accessors.get(path);
};
var getComputed = function (path) {
return currentComputedState[path.join('.')] = getComputedValue(path);
}
return function() {

@@ -29,7 +56,15 @@

var hasChangedComputed = Object.keys(currentComputedState).reduce(function (hasChanged, key) {
if (hasChanged) {
return true;
}
return getComputedValue(key.split('.')) !== currentComputedState[key];
}, false);
if (hasChanged || initialRun) {
if (hasChanged || hasChangedComputed || initialRun) {
currentState = {};
currentComputedState = {};
initialRun = false;
return currentValue = cb(get);
return currentValue = cb(get, getComputed);
} else {

@@ -43,16 +78,33 @@ return currentValue;

register: function (computeTree) {
computed = Object.keys(computeTree).reduce(function (computed, key) {
computed[key] = createMapper(key, computeTree[key]);
return computed;
}, {});
var path = [];
var traverse = function (tree, level) {
return Object.keys(tree).reduce(function (computed, key) {
if (typeof tree[key] === 'function') {
computed[key] = createMapper(key, tree[key]);
} else {
computed[key] = traverse(tree[key], {});
}
return computed;
}, level);
};
computed = traverse(computeTree, {});
},
getComputedValue: function (name) {
if (!computed) {
return;
}
var compute = computed[name];
return compute ? compute() : undefined;
},
getComputedValue: getComputedValue,
getComputedPaths: function () {
return Object.keys(computed || {});
var path = [];
var paths = [];
var traverse = function (tree) {
return Object.keys(tree).forEach(function (key) {
path.push(key);
if (typeof tree[key] === 'function') {
paths.push(path.join('.'));
} else {
traverse(tree[key]);
}
path.pop();
return paths;
});
};
traverse(computed, []);
return paths;
}

@@ -59,0 +111,0 @@ };

@@ -5,2 +5,3 @@ var utils = require('./utils.js');

var currentSeek = 0;
var currentRecording = null;

@@ -18,12 +19,25 @@ var lastSignal = null;

var isCatchingUp = false;
var currentSeek = 0;
var startSeek = 0;
var catchup = null;
// Runs the signal synchronously
var triggerSignal = function (signal) {
var signalName = signal.name.split('.');
var signalMethodPath = signalMethods;
while (signalName.length) {
signalMethodPath = signalMethodPath[signalName.shift()];
}
signalMethodPath.call(null, signal.input, signal.branches);
};
return {
seek: function (seek, startPlaying) {
seek: function (seek) {
startSeek = seek;
clearTimeout(durationTimer);
playbackTimers.forEach(clearTimeout);
controller.emit('seek', seek, !!startPlaying, currentRecording);
controller.emit('seek', startSeek, currentRecording);

@@ -34,16 +48,5 @@ if (signalStore.isRemembering()) {

// Runs the signal synchronously
var triggerSignal = function (signal) {
var signalName = signal.name.split('.');
var signalMethodPath = signalMethods;
while (signalName.length) {
signalMethodPath = signalMethodPath[signalName.shift()];
}
signalMethodPath.call(null, signal.input, signal.branches);
};
// Optimize with FOR loop
var catchup = currentRecording.signals.filter(function (signal) {
return signal.start - currentRecording.start < seek;
catchup = currentRecording.signals.filter(function (signal) {
return signal.start - currentRecording.start < startSeek;
});

@@ -54,23 +57,2 @@ isCatchingUp = true;

if (startPlaying) {
this.createTimer();
var signalsCount = currentRecording.signals.length;
var startIndex = catchup.length;
for (var x = startIndex; x < signalsCount; x++) {
var signal = currentRecording.signals[x];
var durationTarget = signal.start - currentRecording.start - seek;
playbackTimers.push(setTimeout(triggerSignal.bind(null, signal), durationTarget));
}
isPlaying = true;
started = Date.now();
}
playbackTimers.push(setTimeout(function () {
isPlaying = false;
controller.emit('change');
}, currentRecording.end - currentRecording.start - seek ));
controller.emit('change');
},

@@ -94,2 +76,27 @@

play: function () {
if (isPlaying || isRecording) {
throw new Error('CEREBRAL Recorder - You can not play while already playing or recording');
}
this.createTimer();
var signalsCount = currentRecording.signals.length;
var startIndex = catchup.length;
for (var x = startIndex; x < signalsCount; x++) {
var signal = currentRecording.signals[x];
var durationTarget = signal.start - currentRecording.start - startSeek;
playbackTimers.push(setTimeout(triggerSignal.bind(null, signal), durationTarget));
}
isPlaying = true;
started = Date.now();
playbackTimers.push(setTimeout(function () {
isPlaying = false;
controller.emit('change');
}, currentRecording.end - currentRecording.start - startSeek ));
},
record: function () {

@@ -115,4 +122,2 @@

controller.emit('change');
},

@@ -137,4 +142,2 @@

controller.emit('change');
},

@@ -157,5 +160,4 @@

playbackTimers.forEach(clearTimeout);
isPlaying = false;
controller.emit('change');
},

@@ -162,0 +164,0 @@

@@ -8,3 +8,3 @@ var CreateSignalFactory = require('./CreateSignalFactory.js');

module.exports = function (Model, services) {
module.exports = function (Model, services, computed) {

@@ -24,2 +24,6 @@ var controller = new EventEmitter();

if (computed) {
compute.register(computed);
}
var recorder = CreateRecorder(signalStore, signals, controller, model);

@@ -48,3 +52,2 @@ var signalFactory = CreateSignalFactory(signalStore, recorder, devtools, controller, model, services);

controller.devtools = devtools;
controller.compute = compute.register;
controller.getComputedValue = compute.getComputedValue;

@@ -51,0 +54,0 @@ controller.getComputedPaths = compute.getComputedPaths;

@@ -47,8 +47,2 @@ var Controller = require('./../src/index.js');

exports['should have a computation method'] = function (test) {
var controller = Controller(Model());
test.ok(controller.compute);
test.done();
};
exports['should pass get function to grab state from state store'] = function (test) {

@@ -58,4 +52,3 @@ var model = Model({

});
var controller = Controller(model);
controller.compute({
var computed = {
foo: function (get) {

@@ -65,5 +58,26 @@ test.ok(typeof get === 'function');

}
};
var controller = Controller(model, {}, computed);
test.expect(2);
controller.getComputedValue(['foo']);
test.done();
};
exports['should allow nested computed'] = function (test) {
var model = Model({
foo: 'bar'
});
var computed = {
foo: {
bar: function (get) {
test.ok(typeof get === 'function');
test.equal(get(['foo']), 'bar');
}
}
};
var controller = Controller(model, {}, computed);
test.expect(2);
controller.getComputedValue('foo');
controller.getComputedValue(['foo', 'bar']);
test.done();

@@ -77,10 +91,10 @@ };

});
var controller = Controller(model);
controller.compute({
var computed = {
foo: function (get, value) {
test.equal(get(['test']), 'hest');
}
});
}
var controller = Controller(model, {}, computed);
test.expect(1);
controller.getComputedValue('foo');
controller.getComputedValue(['foo']);
test.done();

@@ -94,11 +108,11 @@ };

});
var controller = Controller(model);
controller.compute({
var computed = {
foo: function (get, value) {
test.equal(get(['test']), 'hest');
}
});
};
var controller = Controller(model, {}, computed);
test.expect(1);
controller.getComputedValue('foo');
controller.getComputedValue('foo');
controller.getComputedValue(['foo']);
controller.getComputedValue(['foo']);
test.done();

@@ -113,4 +127,3 @@ };

var run = 0;
var controller = Controller(model);
controller.compute({
var computed = {
foo: function (get) {

@@ -124,5 +137,6 @@ run++;

}
});
};
var controller = Controller(model, {}, computed);
test.expect(2);
controller.getComputedValue('foo');
controller.getComputedValue(['foo']);
var signal = [

@@ -136,3 +150,3 @@ function (input, state) {

controller.once('signalEnd', function () {
controller.getComputedValue('foo');
controller.getComputedValue(['foo']);
test.done();

@@ -149,4 +163,3 @@ });

var run = 0;
var controller = Controller(model);
controller.compute({
var computed = {
foo: function (get) {

@@ -160,5 +173,6 @@ run++;

}
});
};
var controller = Controller(model, {}, computed);
test.expect(2);
controller.getComputedValue('foo');
controller.getComputedValue(['foo']);
var signal = [

@@ -172,4 +186,4 @@ function (input, state) {

controller.once('signalEnd', function () {
controller.getComputedValue('foo');
controller.getComputedValue('foo');
controller.getComputedValue(['foo']);
controller.getComputedValue(['foo']);
test.done();

@@ -190,5 +204,3 @@ });

var controller = Controller(model);
controller.compute({
var computed = {
displayedMessages: function (get) {

@@ -205,6 +217,7 @@ return get(['lists', 'displayedMessagesIds']).map(function (id) { return get(['data', 'messages', id])});

}
});
};
var controller = Controller(model, {}, computed);
test.deepEqual(controller.getComputedValue('displayedMessages'), []);
test.deepEqual(controller.getComputedValue('likedMessages'), []);
test.deepEqual(controller.getComputedValue(['displayedMessages']), []);
test.deepEqual(controller.getComputedValue(['likedMessages']), []);

@@ -227,7 +240,7 @@ var signal = [

test.deepEqual(controller.getComputedValue('displayedMessages'), [{
test.deepEqual(controller.getComputedValue(['displayedMessages']), [{
title: 'test',
liked: true
}]);
test.equal(controller.getComputedValue('likedMessages').length, 2);
test.equal(controller.getComputedValue(['likedMessages']).length, 2);
test.done();

@@ -240,1 +253,20 @@

};
exports['should allow use of other computed'] = function (test) {
var model = Model({
foo: 'bar'
});
var computed = {
foo: function (get, getComputed) {
test.equal(getComputed(['bar']), 'foo');
},
bar: function () {
return 'foo';
}
};
var controller = Controller(model, {}, computed);
test.expect(1);
controller.getComputedValue(['foo']);
test.done();
};

@@ -57,3 +57,3 @@ var Controller = require('./../src/index.js');

return function (controller) {
controller.on('seek', function (seek, startPlaying, currentRecording) {
controller.on('seek', function (seek, currentRecording) {
state = currentRecording.initialState;

@@ -95,3 +95,4 @@ });

setTimeout(function () {
ctrl.recorder.seek(0, true);
ctrl.recorder.seek(0);
ctrl.recorder.play();
test.deepEqual(state, {});

@@ -115,3 +116,3 @@ setTimeout(function () {

return function (controller) {
controller.on('seek', function (seek, startPlaying, currentRecording) {
controller.on('seek', function (seek, currentRecording) {
state = currentRecording.initialState;

@@ -152,2 +153,3 @@ });

ctrl.recorder.seek(150);
ctrl.recorder.play();
test.deepEqual(state, {foo: 'bar'});

@@ -168,3 +170,3 @@ test.done();

return function (controller) {
controller.on('seek', function (seek, startPlaying, currentRecording) {
controller.on('seek', function (seek, currentRecording) {
state = currentRecording.initialState;

@@ -210,3 +212,4 @@ });

setTimeout(function () {
ctrl.recorder.seek(0, true);
ctrl.recorder.seek(0);
ctrl.recorder.play();
test.deepEqual(state, {});

@@ -233,3 +236,3 @@ setTimeout(function () {

return function (controller) {
controller.on('seek', function (seek, startPlaying, currentRecording) {
controller.on('seek', function (seek, currentRecording) {
state = currentRecording.initialState;

@@ -258,3 +261,3 @@ });

];
ctrl.signal('test', signal);

@@ -276,3 +279,4 @@ ctrl.recorder.record(state);

setTimeout(function () {
ctrl.recorder.seek(0, true);
ctrl.recorder.seek(0);
ctrl.recorder.play();
test.deepEqual(state, {});

@@ -284,3 +288,4 @@ setTimeout(function () {

setTimeout(function () {
ctrl.recorder.seek(ctrl.recorder.getCurrentSeek(), true);
ctrl.recorder.seek(ctrl.recorder.getCurrentSeek());
ctrl.recorder.play();
setTimeout(function () {

@@ -287,0 +292,0 @@ test.deepEqual(state, {foo: 'bar2'});

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc