Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions docs/api/domains.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,39 @@ const Planets = {
}
}
```

### `addDomain(key, config)`

Add a sub-domain that lives under the key of the parent domain. Sub-domains:

1. Resolve actions after the parent
2. Operate on a nested key

In all other ways, they are identical to regular domains, and can have
sub-domains for themselves.

```javascript
import Domain from 'microcosm/domain'

class Nodes {
getInitialState() { return [] }
}

class Edges {
getInitialState() { return [] }
}

class Network extends Domain {
setup () {
this.addDomain('nodes', Nodes)
this.addDomain('edges', Edges)
}
}

const repo = new Microcosm()

repo.addDomain('network', Network)

console.log(repo.state.network.edges) // []
console.log(repo.state.network.nodes) // []
```
13 changes: 13 additions & 0 deletions src/domain.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,17 @@ export default class Domain {
return next
}


/**
* Add a sub-domain. This domain will be relative to the parent
*
* TODO: Could there be a time in the future when Domains are just
* Microcosms?
*/
addDomain (key, config) {
this._realm.add([this._key].concat(key), config)

return this
}

}
9 changes: 6 additions & 3 deletions src/getDomainHandlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ function getHandler (key, domain, type) {
const registrations = domain.register(type)

if (process.env.NODE_ENV !== 'production') {
if (registrations.hasOwnProperty(type) && registrations[type] === undefined) {
console.warn('A domain handler for "%s" registered an undefined handler for `%s`. ' +
'Check the register method for this domain.', key, format(type))
if (registrations.hasOwnProperty(type) && typeof registrations[type] !== 'function') {
console.warn('Unable to register `%s` at domain path `["%s"]`. Handlers ' +
'must be functions, instead got `%s`. Check the register ' +
'method for this domain.',
format(type), key.join('", "'), typeof registrations[type])
return null
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/microcosm.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ export default class Microcosm extends Emitter {
* @return {Microcosm} self
*/
addDomain () {
this.realm.add.apply(this.realm, arguments)
this.realm.add(...arguments)

return this.rebase()
}
Expand Down
8 changes: 6 additions & 2 deletions src/realm.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default class Realm {
// to support IE9, which has an odd way of referencing
// arguments
config = key
key = null
key = []
}

let domain = null
Expand All @@ -39,11 +39,15 @@ export default class Realm {
domain = merge({}, config)
}

// Assign the domain to a given realm and key to allow for nesting
domain._key = [].concat(key)
domain._realm = this

// Allow for simple classes and object primitives. Make sure
// they implement the key Domain methods.
Domain.ensure(domain)

this.domains[this.domains.length] = [ key, domain ]
this.domains[this.domains.length] = [ domain._key, domain ]

// Reset the registry
this.registry = {}
Expand Down
54 changes: 21 additions & 33 deletions src/update.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,30 @@
/**
* Retrieve a value from an object. If no key is provided, just
* return the object.
*
* @example
* get({ foo: 'bar' }, 'foo') // 'bar'
* get({ foo: 'bar' }, undefined) // { foo: 'bar' }
*
* @param {Object} object - The target object
* @param {String} key - The key to access
* @return {Any} A retrieved value
* Non-destructive data operations
* Taken from Sprout:
* https://github.com/herrstucki/sprout/blob/master/src/util.js
*/
function get (object, key) {
return key == null ? object : object[key]
}

/**
* Immutabily assign a value to a provided object at a given key. If
* the value is the same, don't do anything. Otherwise return a new
* object.
*
* @example
* set({ foo: 'bar' }, 'baz', 'bip') // { foo: 'bar', baz: 'bip' }
*
* @param {Object} object - The target object
* @param {String} key - The key to set
* @param {Any} value - The value to assign
* @return {Any} A copy of the object with the new assignment.
*/
function set (object, key, value) {
// If the key path is null, there's no need to traverse the
// object. Just return the value.
if (key == null) {
return value
import merge from './merge'

function get (target, keys) {
for (var i = 0, len = keys.length; target && i < len; i++) {
target = target[keys[i]]
}

object[key] = value
return target
}

function set (target, keys, value) {
if (keys.length) {
let head = keys[0]
let clone = merge({}, target)

clone[head] = keys.length > 1 ? set(clone[head] || {}, keys.slice(1), value) : value

return object
return clone
} else {
return value
}
}

export default { get, set }
63 changes: 62 additions & 1 deletion test/domain.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ describe('::commit', function() {

})


describe('Creation modes', function () {

test('object - primitive', function () {
Expand Down Expand Up @@ -188,3 +187,65 @@ describe('Action registration', function() {
})

})

describe('Sub-domains', function () {

test('a domain can add nested child domains within its setup method', function () {
class Node {
getInitialState() { return [] }
}

class Edge {
getInitialState() { return [] }
}

class Network {
setup (repo) {
this.addDomain('nodes', Node)
this.addDomain('edges', Edge)
}
}

const repo = new Microcosm()

repo.addDomain('network', Network)

expect(repo.state.network.edges).toEqual([])
expect(repo.state.network.nodes).toEqual([])
})

test('sub-domains respond to actions after their parents', function () {
let action = n => n

class Node {
getInitialState() {
return []
}

register () {
return {
[action] : () => true
}
}
}

class Network {
setup (repo) {
this.addDomain('nodes', Node)
}
register () {
return {
[action] : (a, b) => ({ ...a, parent: true })
}
}
}

const repo = new Microcosm()

repo.addDomain('network', Network)
repo.push(action)

expect(repo.state.network.parent).toEqual(true)
expect(repo.state.network.nodes).toEqual(true)
})
})