New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

microcosm

Package Overview
Dependencies
Maintainers
1
Versions
233
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

microcosm - npm Package Compare versions

Comparing version 1.1.0 to 1.2.0

example/src/__tests__/App-test.js

5

CHANGELOG.md
# Changelog
### 1.2.0
- All stores can implement a `serialize` method which allows them to
shape how app state is serialized to JSON.
### 1.1.0

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

2

dist/Microcosm.js

@@ -1,2 +0,2 @@

module.exports=function(t){function n(e){if(r[e])return r[e].exports;var o=r[e]={exports:{},id:e,loaded:!1};return t[e].call(o.exports,o,o.exports,n),o.loaded=!0,o.exports}var r={};return n.m=t,n.c=r,n.p="",n(0)}([function(t,n,r){"use strict";n.__esModule=!0;var e=r(3);n.tag=e,n["default"]=r(2)},function(t){"use strict";var n=function(t,n){if(!(t instanceof n))throw new TypeError("Cannot call a class as a function")},r=function(){function t(){n(this,t),this._callbacks=[]}return t.prototype.ignore=function(t){this._callbacks=this._callbacks.filter(function(n){return n!==t})},t.prototype.listen=function(t){this._callbacks=this._callbacks.concat(t)},t.prototype.pump=function(){for(var t=0;t<this._callbacks.length;t++)this._callbacks[t]()},t}();t.exports=r},function(t,n,r){"use strict";var e=function(t){return t&&t.__esModule?t["default"]:t},o=Object.assign||function(t){for(var n=1;n<arguments.length;n++){var r=arguments[n];for(var e in r)Object.prototype.hasOwnProperty.call(r,e)&&(t[e]=r[e])}return t},i=function(t,n){if("function"!=typeof n&&null!==n)throw new TypeError("Super expression must either be null or a function, not "+typeof n);t.prototype=Object.create(n&&n.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),n&&(t.__proto__=n)},s=function(t,n){if(!(t instanceof n))throw new TypeError("Cannot call a class as a function")},u=e(r(1)),a=e(r(5)),c=function(t){function n(){s(this,n),t.call(this),this._stores=[],this._state=this.getInitialState()}return i(n,t),n.prototype.shouldUpdate=function(t,n){return 0==a(t,n)},n.prototype.getInitialState=function(){return{}},n.prototype.seed=function(t){var n=this._stores.filter(function(n){return t[n]});n.forEach(function(n){this.set(n,n.getInitialState(t[n]))},this)},n.prototype.set=function(t,n){this._state=o({},this._state,function(){var r={};return r[t]=n,r}())},n.prototype.has=function(t){return this._stores.indexOf(t)>-1},n.prototype.get=function(t,n){return this._state[t]||t.getInitialState(n)},n.prototype.send=function(t){for(var n=this,r=arguments.length,e=Array(r>1?r-1:0),o=1;r>o;o++)e[o-1]=arguments[o];if(e.length<t.length)return this.send.bind(this,t);var i=t.apply(void 0,e);return i instanceof Promise?i.then(function(r){return n.dispatch(t,r)}):this.dispatch(t,i)},n.prototype.dispatch=function(t,n){var r=this,e=this._stores.reduce(function(e,o){return t in o&&(e[o]=o[t](r.get(o),n)),e},o({},this._state));return this.shouldUpdate(this._state,e)&&(this._state=e,this.pump()),n},n.prototype.addStore=function(){for(var t=arguments.length,n=Array(t),r=0;t>r;r++)n[r]=arguments[r];this._stores=this._stores.concat(n)},n.prototype.toJSON=function(){return this.serialize()},n.prototype.serialize=function(){var t=this;return this._stores.reduce(function(n,r){return n[r]=t.get(r),n},{})},n}(u);t.exports=c},function(t,n,r){"use strict";var e=function(t){return t&&t.__esModule?t["default"]:t};n.__esModule=!0;var o=e(r(4)),i=0,s=function(t){var n=t.bind(null),r="_microcosm-"+i++;return n.toString=function(){return r},n};n.infuse=s,n["default"]=function(t){return o(t,s)}},function(t){"use strict";t.exports=function(t,n){var r=void 0===arguments[0]?{}:arguments[0],e=void 0===arguments[2]?{}:arguments[2],o=Object.keys(r);return o.reduce(function(t,e){return t[e]=n(r[e],e),t},e)}},function(t,n,r){/*!
module.exports=function(t){function n(e){if(r[e])return r[e].exports;var o=r[e]={exports:{},id:e,loaded:!1};return t[e].call(o.exports,o,o.exports,n),o.loaded=!0,o.exports}var r={};return n.m=t,n.c=r,n.p="",n(0)}([function(t,n,r){"use strict";n.__esModule=!0;var e=r(3);n.tag=e,n["default"]=r(2)},function(t){"use strict";var n=function(t,n){if(!(t instanceof n))throw new TypeError("Cannot call a class as a function")},r=function(){function t(){n(this,t),this._callbacks=[]}return t.prototype.ignore=function(t){this._callbacks=this._callbacks.filter(function(n){return n!==t})},t.prototype.listen=function(t){this._callbacks=this._callbacks.concat(t)},t.prototype.pump=function(){for(var t=0;t<this._callbacks.length;t++)this._callbacks[t]()},t}();t.exports=r},function(t,n,r){"use strict";var e=function(t){return t&&t.__esModule?t["default"]:t},o=Object.assign||function(t){for(var n=1;n<arguments.length;n++){var r=arguments[n];for(var e in r)Object.prototype.hasOwnProperty.call(r,e)&&(t[e]=r[e])}return t},i=function(t,n){if("function"!=typeof n&&null!==n)throw new TypeError("Super expression must either be null or a function, not "+typeof n);t.prototype=Object.create(n&&n.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),n&&(t.__proto__=n)},s=function(t,n){if(!(t instanceof n))throw new TypeError("Cannot call a class as a function")},u=e(r(1)),a=e(r(5)),c=function(t){function n(){s(this,n),t.call(this),this._stores=[],this._state=this.getInitialState()}return i(n,t),n.prototype.shouldUpdate=function(t,n){return 0==a(t,n)},n.prototype.getInitialState=function(){return{}},n.prototype.seed=function(t){var n=this._stores.filter(function(n){return t[n]});n.forEach(function(n){this.set(n,n.getInitialState(t[n]))},this)},n.prototype.set=function(t,n){this._state=o({},this._state,function(){var r={};return r[t]=n,r}())},n.prototype.has=function(t){return this._stores.indexOf(t)>-1},n.prototype.get=function(t,n){return this._state[t]||t.getInitialState(n)},n.prototype.send=function(t){for(var n=this,r=arguments.length,e=Array(r>1?r-1:0),o=1;r>o;o++)e[o-1]=arguments[o];if(e.length<t.length)return this.send.bind(this,t);var i=t.apply(void 0,e);return i instanceof Promise?i.then(function(r){return n.dispatch(t,r)}):this.dispatch(t,i)},n.prototype.dispatch=function(t,n){var r=this,e=this._stores.reduce(function(e,o){return t in o&&(e[o]=o[t](r.get(o),n)),e},o({},this._state));return this.shouldUpdate(this._state,e)&&(this._state=e,this.pump()),n},n.prototype.addStore=function(){for(var t=arguments.length,n=Array(t),r=0;t>r;r++)n[r]=arguments[r];this._stores=this._stores.concat(n)},n.prototype.serialize=function(){var t=this;return this._stores.reduce(function(n,r){var e=t.get(r);return"serialize"in r&&(e=r.serialize(e)),n[r]=e,n},{})},n.prototype.toJSON=function(){return this.serialize(this.state)},n}(u);t.exports=c},function(t,n,r){"use strict";var e=function(t){return t&&t.__esModule?t["default"]:t};n.__esModule=!0;var o=e(r(4)),i=0,s=function(t){var n=t.bind(null),r="_microcosm-"+i++;return n.toString=function(){return r},n};n.infuse=s,n["default"]=function(t){return o(t,s)}},function(t){"use strict";t.exports=function(t,n){var r=void 0===arguments[2]?{}:arguments[2],e=Object.keys(t);return e.reduce(function(r,e){return r[e]=n(t[e],e),r},r)}},function(t,n,r){/*!
* is-equal-shallow <https://github.com/jonschlinkert/is-equal-shallow>

@@ -3,0 +3,0 @@ *

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

import Route from 'stores/Route'
import Items from 'stores/Items'
import Lists from 'stores/Lists'
import Route from './stores/Route'
import Items from './stores/Items'
import Lists from './stores/Lists'
import Microcosm from 'Microcosm'

@@ -5,0 +5,0 @@

@@ -10,14 +10,20 @@ /**

let routes = {
'/' : require('../components/layouts/Home'),
'/list/:id' : require('../components/layouts/Show')
}
let routes = [
{ path: '/', handler: require('../components/layouts/Home') },
{ path: '/list/:id', handler: require('../components/layouts/Show') }
]
export default {
install(flux) {
Object.keys(routes).forEach(route => {
page(route, function({ params }) {
flux.send(Route.set, { handler: routes[route], params })
})
install(app) {
let action = app.send(Route.set)
// Create a callback for each route that pushes the event
// into the app's dispatcher
//
// TODO: Ideally, we'd detect that the route changed and
// reduce down to a route/handler within the associated
// store or action
routes.forEach(({ path, handler }) => {
page(path, ({ params }) => action({ handler, params }))
})

@@ -24,0 +30,0 @@

@@ -1,3 +0,3 @@

import Lists from 'actions/lists'
import contrast from 'contrast'
import Lists from '../actions/lists'
import contrast from '../../lib/contrast'
import uid from 'uid'

@@ -4,0 +4,0 @@

@@ -18,7 +18,9 @@ var Webpack = require('webpack')

files: [
'src/**/__tests__/*.js*'
'src/**/__tests__/*.js*',
'example/src/**/__tests__/*.js*'
],
preprocessors: {
'src/**/__tests__/*.js*': [ 'webpack', 'sourcemap' ]
'src/**/__tests__/*.js*' : [ 'webpack', 'sourcemap' ],
'example/src/**/__tests__/*.js*' : [ 'webpack', 'sourcemap' ]
},

@@ -25,0 +27,0 @@

{
"name": "microcosm",
"version": "1.1.0",
"version": "1.2.0",
"description": "An experimental flux implimentation",
"main": "dist/Microcosm.js",
"scripts": {
"coveralls": "CONTINUOUS_INTEGRATION=true npm test && coveralls < coverage/report-lcov/lcov.info",
"prepublish": "NODE_ENV=production webpack -p",
"test": "NODE_ENV=test karma start",
"coveralls": "CONTINUOUS_INTEGRATION=true npm test && coveralls < coverage/report-lcov/lcov.info",
"example": "node example/server"
"start": "node example/server",
"test": "NODE_ENV=test karma start"
},

@@ -12,0 +12,0 @@ "repository": {

@@ -28,3 +28,3 @@ Important! This is largely an exploratory repo, used to vet some ideas

Microcosm injects a couple of opinions regarding the Flux
Microcosm injects a a couple of opinions regarding the Flux
architecture:

@@ -38,11 +38,137 @@

updated by returning a new value.
3. All Actions that return promises will wait to resolve before
3. Stores do not contain data, they _shape_ it. See the section on
stores below.
4. All Actions that return promises will wait to resolve before
dispatching.
4. It should be easily to embed in libraries. Additional features
5. It should be easily to embed in libraries. Additional features such
should be able to layer on top.
6. It should utilize language features over implementation details as
much as possible.
## Design
Without getting too lofty, this is roughly the ideal scenario for a
Microcosm:
```
|--> [Store] ---|
[app.send] ------> [Action] ------> [Dispatcher] ---+--> [Store] ---+--> [app.shouldUpdate?]
^ |--> [Store] ---| |
| |
| v
[External Services] <--------------------------------------------------------- [YES]
|- User Interface
|- Router
|- Firebase sync
```
## Writing a Microcosm
A new app starts out as an extension of the `Microcosm` class:
```javascript
import Microcosm from 'microcosm'
class MyApp extends Microcosm {
// Great things await
}
```
A microcosm is solely responsible for managing a global state
object. This value is assigned initially through `getInitialState`,
much like a react component:
```javascript
import Microcosm from 'microcosm'
class MyApp extends Microcosm {
// This is actually the default implementation
getInitialState() {
return {}
}
}
```
Although a microcosm is exclusively responsible for managing its own
state, `stores` shape how that data is changed:
```javascript
import Microcosm from 'microcosm'
let Messages = {
getInitialState() {
return []
},
toString() {
return 'messages'
}
}
class MyApp extends Microcosm {
constructor() {
super()
this.addStore(Messages)
}
getInitialState() {
return {}
}
}
```
Now the `Messages` store will be responsible for shaping the data kept
within the `messages` key of this app's state.
Requests to change this data can be handled with `Actions`. An action
is simply a function that has been tagged with a unique
identifier. The `tag` module included with `Microcosm` can do just
that:
```javascript
import Microcosm, { tag } from 'microcosm'
let Actions = {
createMessage(options) {
// Here, we are simply returning options. However this
// gives you an opportunity to modify parameters before they
// are sent to stores
return options
}
}
let Messages = {
getInitialState() {
return []
},
[Actions.createMessage](oldState, parameters) {
return oldState.concat(parameters)
},
toString() {
return 'messages'
}
}
class MyApp extends Microcosm {
constructor() {
super()
this.addStore(Messages)
}
getInitialState() {
return {}
}
}
```
`MyApp` is now setup to accept actions, filtering them through the
`Messages` store before saving them. More information on how to
trigger actions and retrieve state follows.
## How Actions work
Actions are simple objects that have been tagged with unique identifiers:
Actions are simply functions. They must implement a `toString` method
so that stores can know when to respond to them. For those familiar
with traditional flux, this `toString` method replaces the need to
maintain constants for each action type.
Fortunately, the `tag` function makes this quite mangeable:
``` javascript

@@ -52,7 +178,5 @@ import tag from 'microcosm/tag'

let Messages = tag({
create(message) {
return { message, time: new Date() }
}
})

@@ -66,4 +190,7 @@ ```

You can fire them like:
Microcosms implement a `send` method. This will run execute a given
action with an arbitrary number of arguments (following the first).
This works like:
```javascript

@@ -73,6 +200,23 @@ app.send(Messages.create, 'This property will be passed to the dispatcher')

### Currying actions
`send` automatically curries invocations that do not include the
expected number of arguments. To repeat the previous example with currying:
```javascript
let create = app.send(Messages.create)
create('This property will be passed to the dispatcher')
```
Technically, this is even possible (but you didn't hear it from me):
```javascript
let sum = (a, b) => a + b
app.send(sum)(2, 3) // => 5
```
## How Stores work
Stores are plain objects. They must implement a `getInitialState` and
`toString()` method. They listen to actions by providing methods at
`toString` method. They listen to actions by providing methods at
the unique signature of an Action, like:

@@ -98,10 +242,14 @@

Each Store instance manages a subset of a global state object owned by an
individual Microcosm instance. By returning a new state object within responses
to actions, they modify state.
Each store manages a subset of a global state object owned by an
individual Microcosm instance. By returning a new state object within
responses to actions, they modify state.
Microcosm will use `getInitialState` to produce the initial value for the subset
a store manages.
Microcosm will use `getInitialState` to produce the initial value for
the subset a store manages.
Unlike actions, stores must be registered with the system. There are two reason for this. First: to tell Microcosm what Stores should be responsible for managing state. Second: to dictate the priority of dispatcher multicasting (similar to `waitFor` in the standard Flux dispatcher)
Unlike actions, stores must be registered with the system. There are
two reason for this. First: to tell Microcosm what Stores should be
responsible for managing state. Second: to dictate the priority of
dispatcher multicasting (similar to `waitFor` in the standard Flux
dispatcher)

@@ -113,3 +261,7 @@ ```javascript

// Called first:
this.addStore(Messages)
// Called second:
this.addStore(OtherStoreThatDependsOnMessages)
}

@@ -119,2 +271,34 @@ }

### Getting the value out of a store
Similar to a `Map`, microcosms implement a `get` and `set`
method. `set` should never be called directly, however it is exposed
should you wish to define your own method of assignment. As for `get`:
```javascript
app.get(Store)
```
This works because the app accesses the internal state object
(returned initially from `app.getInitialState`) using `Store` as a
key. Since the store implements a `toString` method, it coerces into
the proper key and returns the expected value.
## Listening to changes
All Microcosm instances are event emitters. They emit a single change event that you can subscribe to like:
```javascript
let app = new Microcosm()
// Add a callback
app.listen(callback)
// Remove a callback
app.ignore(callback)
// Force an emission
app.pump()
```
## Additional Notes

@@ -121,0 +305,0 @@

@@ -23,3 +23,3 @@ import Action from './fixtures/Action'

it ('can serialize', function() {
it ('can serialize to JSON', function() {
let m = new Microcosm()

@@ -31,2 +31,21 @@

it ('runs through serialize methods on stores', function() {
let m = new Microcosm()
m.addStore({
getInitialState() {
return 'this will not display'
},
serialize(state) {
state.should.equal(this.getInitialState())
return 'this is a test'
},
toString() {
return 'serialize-test'
}
})
m.toJSON().should.have.property('serialize-test', 'this is a test')
})
it ('passes seed data to stores', function() {

@@ -33,0 +52,0 @@ let seed = { fiz: 'buz' }

@@ -78,16 +78,23 @@ /**

addStore(...store) {
this._stores = this._stores.concat(store)
addStore(...stores) {
this._stores = this._stores.concat(stores)
}
toJSON() {
return this.serialize()
}
serialize(state) {
return this._stores.reduce((memo, store) => {
let state = this.get(store)
serialize() {
return this._stores.reduce((memo, store) => {
memo[store] = this.get(store)
if ('serialize' in store) {
state = store.serialize(state)
}
memo[store] = state
return memo
}, {})
}
toJSON() {
return this.serialize(this.state)
}
}

@@ -11,3 +11,3 @@ /**

export default (entity={}, fn, initial={}) => {
export default (entity, fn, initial={}) => {
let keys = Object.keys(entity)

@@ -14,0 +14,0 @@

Sorry, the diff of this file is not supported yet

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