Skip to content

Instantly share code, notes, and snippets.

@shellsong
Created October 10, 2015 10:29
Show Gist options
  • Save shellsong/c766bbefd61375c86985 to your computer and use it in GitHub Desktop.
Save shellsong/c766bbefd61375c86985 to your computer and use it in GitHub Desktop.
effector
'use strict'
import {
EventEmitter
} from 'events'
const keyRegExp = /\{(\w+)\}/g
const sep = '.'
function resolveParam(keyPath, payload){
return keyPath
.replace(
keyRegExp
, (_,$1) => payload[$1]
)
.split(sep)
}
function walk(cur, tiers, lvl = 0){
if(tiers.length === 0){
return cur
}
let prop = cur[tiers[0]]
let tails = tiers.slice(1)
if(tails.length === 0){
return prop
}else if(prop === undefined || prop === null){
throw new Error(` {lvl} `)
}else{
return walk(prop, tails, lvl + 1)
}
}
const evName = 'change'
function deepMerge(tiers, source, patch){
//FIXME Immutable!
let target = source
let locationTiers = tiers.slice(0,tiers.length - 1)
let patchKey = tiers[tiers.length - 1]
walk(target, locationTiers)[patchKey] = patch
return target
}
export default function Effector(initialState = {}){
let currentState = initialState
let broadcastMap = {}
const emitter = new EventEmitter()
const getState = () => currentState
const subscribe = (fn) => {
let cb = (nextState) => fn(nextState)
emitter.addListener(evName, cb)
return () => emitter.removeListener(evName, cb)
}
const createAction = (keyPath, fn, deps = []) => {
let action = (payload, options = {}) => {
let tiers = resolveParam(keyPath, payload)
let source = walk(currentState, tiers)
let args = [payload, source].concat(deps.map((dp) => {
return walk(currentState, resolveParam(dp, payload))
}))
args.push(function resolve(target){
currentState = deepMerge(tiers, currentState, target)
Object.keys(broadcastMap).forEach((path) => {
if(keyPath.indexOf(path) > 0){
broadcastMap[path].forEach((subcriber) => {
subcriber(payload, {trigger:false})
})
}
})
if(options.trigger !== false){
emitter.emit(evName, currentState)
}
})
return fn.apply(null, args)
}
action.listenTo = (path) => {
var subcribers;
if(!broadcastMap[path]){
subcribers = broadcastMap[path] = [action]
}else{
subcribers = broadcastMap[path]
}
return action
}
return action
}
return {
createAction,
subscribe,
getState
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment