├── .circleci └── config.yml ├── .editorconfig ├── .github ├── labeler.yml ├── main.workflow └── workflows │ └── labeler.yaml ├── .gitignore ├── LICENSE ├── README.md ├── bench ├── bench.js ├── benchmark.js ├── mock.js ├── perf.js ├── printResults.js └── suite.js ├── dist ├── cjs │ ├── action │ │ ├── apiFactory.js │ │ ├── apiFactory.js.map │ │ ├── createAction.h.js │ │ ├── createAction.h.js.map │ │ ├── createAction.js │ │ ├── createAction.js.map │ │ ├── index.js │ │ └── index.js.map │ ├── index.js │ ├── index.js.map │ └── state │ │ ├── BaseReducer.js │ │ ├── BaseReducer.js.map │ │ ├── CombinedReducer.js │ │ ├── CombinedReducer.js.map │ │ ├── helpers.js │ │ ├── helpers.js.map │ │ ├── index.js │ │ ├── index.js.map │ │ ├── reducer.h.js │ │ └── reducer.h.js.map ├── lib │ ├── action │ │ ├── apiFactory.js │ │ ├── apiFactory.js.map │ │ ├── createAction.h.js │ │ ├── createAction.h.js.map │ │ ├── createAction.js │ │ ├── createAction.js.map │ │ ├── index.js │ │ └── index.js.map │ ├── index.js │ ├── index.js.map │ └── state │ │ ├── BaseReducer.js │ │ ├── BaseReducer.js.map │ │ ├── CombinedReducer.js │ │ ├── CombinedReducer.js.map │ │ ├── helpers.js │ │ ├── helpers.js.map │ │ ├── index.js │ │ ├── index.js.map │ │ ├── reducer.h.js │ │ └── reducer.h.js.map └── types │ ├── action │ ├── apiFactory.d.ts │ ├── createAction.d.ts │ ├── createAction.h.d.ts │ └── index.d.ts │ ├── index.d.ts │ └── state │ ├── BaseReducer.d.ts │ ├── CombinedReducer.d.ts │ ├── helpers.d.ts │ ├── index.d.ts │ └── reducer.h.d.ts ├── package.json ├── rfc.md ├── rollup.config.ts ├── src ├── action │ ├── apiFactory.ts │ ├── createAction.h.ts │ ├── createAction.ts │ └── index.ts ├── index.ts └── state │ ├── BaseReducer.ts │ ├── CombinedReducer.ts │ ├── helpers.ts │ ├── index.ts │ └── reducer.h.ts ├── test ├── restate.test.ts └── store.test.tsx ├── tools ├── gh-pages-publish.ts └── semantic-release-prepare.ts ├── tsconfig.json ├── tslint.json └── yarn.lock /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | docker: 5 | - image: circleci/node:6.14 6 | working_directory: ~/repo 7 | 8 | steps: 9 | - checkout 10 | - restore_cache: 11 | keys: 12 | - v1-dependencies-{{ checksum "package.json" }} 13 | - v1-dependencies- 14 | 15 | - run: yarn install 16 | 17 | - save_cache: 18 | paths: 19 | - node_modules 20 | key: v1-dependencies-{{ checksum "package.json" }} 21 | 22 | - run: yarn test 23 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | #root = true 2 | 3 | [*] 4 | indent_style = space 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | max_line_length = 100 10 | indent_size = 2 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | drahobrat: 2 | - any: ['**'] 3 | -------------------------------------------------------------------------------- /.github/main.workflow: -------------------------------------------------------------------------------- 1 | workflow "Build, Test, and Publish" { 2 | on = "push" 3 | resolves = ["Publish"] 4 | } 5 | 6 | action "Build" { 7 | uses = "actions/npm@master" 8 | args = "install" 9 | } 10 | 11 | action "Test" { 12 | needs = "Build" 13 | uses = "actions/npm@master" 14 | args = "test" 15 | } 16 | 17 | # Filter for a new tag 18 | action "Tag" { 19 | needs = "Test" 20 | uses = "actions/bin/filter@master" 21 | args = "tag" 22 | } 23 | 24 | action "Publish" { 25 | needs = "Tag" 26 | uses = "actions/npm@master" 27 | args = "publish --access public" 28 | secrets = ["NPM_AUTH_TOKEN"] 29 | } 30 | -------------------------------------------------------------------------------- /.github/workflows/labeler.yaml: -------------------------------------------------------------------------------- 1 | name: "Pull Request Labeler" 2 | on: 3 | - pull_request_target 4 | 5 | jobs: 6 | triage: 7 | permissions: 8 | contents: read 9 | pull-requests: write 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/labeler@v4 13 | with: 14 | dot: true 15 | sync-labels: true 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | .nyc_output 4 | .DS_Store 5 | *.log 6 | .vscode 7 | .idea 8 | compiled 9 | .awcache 10 | .rpt2_cache 11 | .rpt2_cache 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2017 Dima Zherebko 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Okdux 👌 2 | 3 | [![CircleCI](https://circleci.com/gh/zhDmitry/restate.svg?style=svg)](https://circleci.com/gh/zhDmitry/okdux) 4 | [![NPM Downloads](https://img.shields.io/npm/dm/okdux.svg?style=flat)](https://www.npmjs.com/package/okdux) 5 | 6 | This lib was created for reducing pain from redux boilerplate. 7 | 8 | --- 9 | 10 | ## Installation 11 | 12 | ```bash 13 | npm install --save okdux 14 | ``` 15 | 16 | or 17 | 18 | ```bash 19 | yarn add okdux 20 | ``` 21 | 22 | ## Usage 23 | 24 | ```js 25 | import { createStore } from "redux"; 26 | import { connect } from "react-redux"; 27 | 28 | 29 | import { createActions, createState, build } from "okdux"; 30 | 31 | 32 | const actions = createActions({ 33 | inc: build.action() 34 | }); 35 | 36 | const counterState = createState(0); 37 | // different types of counters 38 | const state = createState({ counter: countersState }); 39 | 40 | counterState.on(actions.inc, (state, p) => { 41 | return state + 1; 42 | }); 43 | 44 | //[optional]auto bind all actions to redux 45 | //store is redux store 46 | state.createStore((reducer)=> createStore(reducer, {})); 47 | // or 48 | const store = createStore(state.reducer, {}); 49 | state.use(store.dispatch); 50 | 51 | countersState.select(store.getState()); // will return state from root 52 | countersState.select(store.getState()); // will return state from root 53 | 54 | // select only counter from root state 55 | // this component will be reuseable and you won't care about where your reducer are placed 56 | // also you will get types suggestions 57 | const enhancer = connect(countersState.select(counter=>({ counter }))) 58 | 59 | 60 | // dispatch actions 61 | // all actions are autobinded to store after using .use action 62 | // you can assign one action to multiple stores 63 | // to access plain action call inc.raw(); 64 | // actions are autobinded in case of 65 | inc(1); 66 | inc(2); 67 | inc(2); 68 | inc(3); 69 | inc(8); 70 | ``` 71 | 72 | ## API 73 | 74 | ### `createState({ //plain obj or different state }) => StateBuilder` 75 | 76 | create state from plain object or compose from different state 77 | 78 | ```js 79 | const counter = createState(0); 80 | 81 | const state = createState({ counter }); 82 | ``` 83 | 84 | ALERT: YOU CAN PASS to createState either plain obj or map of states 85 | 86 | this is ok 87 | 88 | ```js 89 | const counter = createState(0); 90 | const counter2 = createState(0); 91 | 92 | const state = createState({ counter, counter2 }); 93 | ``` 94 | 95 | this is not ok 96 | 97 | ```js 98 | const counter = createState(0); 99 | const counter2 = createState(0); 100 | 101 | const state = createState({ counter, counter2, name: "6" /* not ok*/ }); 102 | const state = createState({ counter, counter2, name: createState("name") }); // this is ok 103 | ``` 104 | 105 | ### StateBuilder 106 | 107 | ### `StateBuilder.on(Action:Action, handler:(substate: any, ActionPayload)=>new substate)` 108 | 109 | Add handler to substate 110 | It's like building reducer but with using `.on` instead of switch cases 111 | in handler as second argument you will get action payload and you have to return new state 112 | 113 | ### `StateBuilder.select(RootStateObject)=> state` 114 | 115 | selects state related to your state builder 116 | 117 | ### `StateBuilder.select((subState)=>mappedState)=> mappedState` 118 | 119 | state with map is equivalent to mapFn(StateBuilder.select({})); 120 | 121 | it will return substate related to some stateBuilder 122 | Example: 123 | 124 | ```js 125 | // somewhere in state file; 126 | const counterState = createState(0); 127 | 128 | //somewhere in component 129 | // now you can select your counter state and don't care about counter placement in store 130 | const enhancer = connect(countersState.select(counter => ({ counter }))); 131 | ``` 132 | 133 | ALERT: you can have only one stateBuilder mounded to root state 134 | 135 | ```js 136 | const st = createState(2); 137 | const rootSTate = createState({ 138 | st, 139 | st2: st 140 | }); // not ok 141 | const makeSt = () => createState(2); 142 | const rootSTate = createState({ 143 | st: makeSt(), 144 | st2: makeSt() 145 | }); // ok 146 | ``` 147 | 148 | ### `StateBuilder.reducer: PlainReducer` 149 | 150 | reducer property it's encapsulated reducer inside state builder 151 | 152 | ### `StateBuilder.use(dispatchFn): void` 153 | 154 | makes all actions binded using `on` handler autobinded to this function 155 | so you won't have to use mapDispatchToProps 156 | 157 | ### `StateBuilder.createState(createStoreFn): store` 158 | 159 | same as use 160 | 161 | example 162 | 163 | ```js 164 | const state = createState(0); 165 | state.createStore(reducer => createStore(reducer, {})); 166 | // or simpler 167 | state.createStore(createStore); 168 | ``` 169 | 170 | ### `StateBuilder.reset(action): StateBuilder` 171 | 172 | reset reducer value to default 173 | same as `state.on(action, ()=>initialValue)` 174 | 175 | ### createActions({ [string]: ActionFactory }) 176 | 177 | examples 178 | 179 | ```js 180 | import { build, createState, createApi } from "okdux"; 181 | const counter = createState(0); 182 | 183 | const actions = createApi(counter, { 184 | increment(state, payload) { 185 | return { ...state, payload }; 186 | }, 187 | decrement(state, payload) { 188 | return { ...state, payload }; 189 | } 190 | }); 191 | ``` 192 | -------------------------------------------------------------------------------- /bench/bench.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | 3 | const { test, beforeAll, afterAll } = require("./benchmark"); 4 | 5 | beforeAll(() => { 6 | const { Record, Repeat } = require("immutable"); 7 | const { default: produce, setAutoFreeze, setUseProxies } = require("immer"); 8 | }); 9 | 10 | afterAll(results => { 11 | const { printResults } = require("./printResults"); 12 | printResults(results); 13 | }); 14 | 15 | // describe('performance', () => { 16 | // beforeEach(() => { 17 | // draft = cloneDeep(baseState) 18 | // memoryBefore = process.memoryUsage() 19 | // }) 20 | // afterEach(() => { 21 | // const memoryAfter = process.memoryUsage() 22 | // console.log(memoryBefore) 23 | // console.log(memoryAfter) 24 | // }) 25 | const MAX = 100000; 26 | const MODIFY_FACTOR = 0.1; 27 | 28 | function getItem(any, i) { 29 | return { 30 | todo: `todo_${i}`, 31 | done: false, 32 | someThingCompletelyIrrelevant: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] 33 | }; 34 | } 35 | function generateDraft() { 36 | const draft = []; 37 | for (let i = 0; i < MAX; i++) { 38 | draft.push(getItem(undefined, i)); 39 | } 40 | return draft; 41 | } 42 | module.exports.generateDraft = generateDraft; 43 | // Produce the frozen bazeState 44 | // frozenBazeState = deepFreeze(cloneDeep(baseState)) 45 | 46 | // generate immutalbeJS base state 47 | 48 | test("immutableJS", prepared => { 49 | const { Record, Repeat } = require("immutable"); 50 | const todoRecord = Record({ 51 | todo: "", 52 | done: false, 53 | someThingCompletelyIrrelevant: [] 54 | }); 55 | const draft = Repeat(undefined, MAX) 56 | .map((_, i) => todoRecord(getItem(_, i))) 57 | .toList(); 58 | prepared(); 59 | const result = draft.withMutations(state => { 60 | for (let i = 0; i < MAX * MODIFY_FACTOR; i++) { 61 | state.setIn([i, "done"], true); 62 | } 63 | }); 64 | return result; 65 | }); 66 | 67 | // test('just mutate, freeze', () => { 68 | // for (let i = 0; i < MAX * MODIFY_FACTOR; i++) { 69 | // draft[i].done = true 70 | // } 71 | // deepFreeze(draft) 72 | // }) 73 | 74 | // test('deepclone, then mutate', () => { 75 | // const draft = cloneDeep(baseState) 76 | // for (let i = 0; i < MAX * MODIFY_FACTOR; i++) { 77 | // draft[i].done = true 78 | // } 79 | // }) 80 | 81 | // test('deepclone, then mutate, then freeze', () => { 82 | // const draft = cloneDeep(baseState) 83 | // for (let i = 0; i < MAX * MODIFY_FACTOR; i++) { 84 | // draft[i].done = true 85 | // } 86 | // deepFreeze(draft) 87 | // }) 88 | 89 | // test('handcrafted reducer (no freeze)', () => { 90 | // const nextState = [ 91 | // ...baseState.slice(0, MAX * MODIFY_FACTOR).map(todo => ({ 92 | // ...todo, 93 | // done: true, 94 | // })), 95 | // ...baseState.slice(MAX * MODIFY_FACTOR), 96 | // ] 97 | // }) 98 | 99 | // test('handcrafted reducer (with freeze)', () => { 100 | // const nextState = freeze([ 101 | // ...baseState.slice(0, MAX * MODIFY_FACTOR).map(todo => 102 | // freeze({ 103 | // ...todo, 104 | // done: true, 105 | // }), 106 | // ), 107 | // ...baseState.slice(MAX * MODIFY_FACTOR), 108 | // ]) 109 | // }) 110 | 111 | // test('naive handcrafted reducer (without freeze)', () => { 112 | // const nextState = baseState.map((todo, index) => { 113 | // if (index < MAX * MODIFY_FACTOR) 114 | // return { 115 | // ...todo, 116 | // done: true, 117 | // } 118 | // else return todo 119 | // }) 120 | // }) 121 | 122 | // test('naive handcrafted reducer (with freeze)', () => { 123 | // const nextState = deepFreeze( 124 | // baseState.map((todo, index) => { 125 | // if (index < MAX * MODIFY_FACTOR) 126 | // return { 127 | // ...todo, 128 | // done: true, 129 | // } 130 | // else return todo 131 | // }), 132 | // ) 133 | // }) 134 | 135 | // test('immutableJS + toJS', () => { 136 | // const state = immutableJsBaseState 137 | // .withMutations(state => { 138 | // for (let i = 0; i < MAX * MODIFY_FACTOR; i++) { 139 | // state.setIn([i, 'done'], true) 140 | // } 141 | // }) 142 | // .toJS() 143 | // }) 144 | 145 | test("immer (proxy) - without autofreeze", prepared => { 146 | //$off 147 | const { default: produce, setAutoFreeze, setUseProxies } = require("immer"); 148 | const draft = generateDraft(); 149 | prepared(); 150 | 151 | setUseProxies(true); 152 | setAutoFreeze(false); 153 | produce(draft, draft => { 154 | for (let i = 0; i < MAX * MODIFY_FACTOR; i++) { 155 | draft[i].done = true; 156 | } 157 | }); 158 | return draft; 159 | }); 160 | 161 | test("mobx", prepared => { 162 | //$off 163 | const { observable } = require("mobx"); 164 | const data = observable(generateDraft()); 165 | prepared(); 166 | 167 | const mutate = draft => { 168 | for (let i = 0; i < MAX * MODIFY_FACTOR; i++) { 169 | draft[i].done = true; 170 | } 171 | }; 172 | mutate(data); 173 | return data; 174 | }); 175 | 176 | // test('effector (mutable inner update)', prepared => { 177 | // //$off 178 | // const {createEvent, createStore} = require('../npm/effector/effector.cjs.js') 179 | // const updateEvent = createEvent('update') 180 | // const effectorStore = createStore(generateDraft()).on(updateEvent, draft => { 181 | // const newDraft = draft.concat([]) 182 | // for (let i = 0; i < MAX * MODIFY_FACTOR; i++) { 183 | // newDraft[i].done = true 184 | // } 185 | // return newDraft 186 | // }) 187 | // prepared() 188 | // updateEvent() 189 | // return effectorStore.getState() 190 | // }) 191 | 192 | test("restate x", prepared => { 193 | //$off 194 | const { createAction, createState, local } = require("../dist/lib/"); 195 | 196 | const updateEvent = createAction("update"); 197 | const effectorStore = createState(generateDraft()).on(updateEvent, draft => { 198 | const newDraft = draft.concat([]); 199 | for (let i = 0; i < MAX * MODIFY_FACTOR; i++) { 200 | newDraft[i] = Object.assign({}, newDraft[i], { done: true }); 201 | } 202 | return newDraft; 203 | }); 204 | 205 | effectorStore.map(el => el[0], true); 206 | 207 | effectorStore.subscribe(data => {}); 208 | const store = effectorStore.use(local); 209 | prepared(); 210 | 211 | updateEvent(); 212 | return effectorStore.getState(); 213 | }); 214 | 215 | test("restate x (only redux helpers)", prepared => { 216 | //$off 217 | const { createState } = require("../dist/lib/createReducer"); 218 | const { createAction } = require("../dist/lib/createAction"); 219 | 220 | const updateEvent = createAction("update"); 221 | const restateStore = createState(generateDraft()).on(updateEvent, draft => { 222 | const newDraft = draft.concat([]); 223 | for (let i = 0; i < MAX * MODIFY_FACTOR; i++) { 224 | newDraft[i] = Object.assign({}, newDraft[i], { done: true }); 225 | } 226 | return newDraft; 227 | }); 228 | 229 | const store = redux.createStore(restateStore.reducer); 230 | store.subscribe(() => {}); 231 | prepared(); 232 | 233 | prepared(); 234 | 235 | store.dispatch(updateEvent.raw()); 236 | 237 | return store.getState(); 238 | }); 239 | 240 | const { proxyState, proxyEqual, proxyShallow } = require("proxyequal"); 241 | 242 | // wrap the original state 243 | const state = () => ({ a: generateDraft(), b: generateDraft(), c: generateDraft() }); 244 | test("proxy", () => { 245 | const trapped = proxyState(state()); 246 | }); 247 | const redux = require("redux"); 248 | test("redux", prepared => { 249 | const reducer = (draft = generateDraft()) => { 250 | const newDraft = draft.concat([]); 251 | for (let i = 0; i < MAX * MODIFY_FACTOR; i++) { 252 | newDraft[i] = Object.assign({}, newDraft[i], { done: true }); 253 | } 254 | return newDraft; 255 | }; 256 | const store = redux.createStore(reducer); 257 | store.subscribe(() => {}); 258 | prepared(); 259 | store.dispatch({ type: "init" }); 260 | }); 261 | 262 | // test('immer (es5) - without autofreeze', () => { 263 | // setUseProxies(false) 264 | // setAutoFreeze(false) 265 | // produce(baseState, draft => { 266 | // for (let i = 0; i < MAX * MODIFY_FACTOR; i++) { 267 | // draft[i].done = true 268 | // } 269 | // }) 270 | // }) 271 | 272 | // test('immer (es5) - with autofreeze', () => { 273 | // setUseProxies(false) 274 | // setAutoFreeze(true) 275 | // produce(frozenBazeState, draft => { 276 | // for (let i = 0; i < MAX * MODIFY_FACTOR; i++) { 277 | // draft[i].done = true 278 | // } 279 | // }) 280 | // }) 281 | // }) 282 | 283 | test("just mutate", prepared => { 284 | const draft = generateDraft(); 285 | prepared(); 286 | for (let i = 0; i < MAX * MODIFY_FACTOR; i++) { 287 | draft[i].done = true; 288 | } 289 | return draft; 290 | }); 291 | -------------------------------------------------------------------------------- /bench/benchmark.js: -------------------------------------------------------------------------------- 1 | 2 | //@flow 3 | const delay = require("util").promisify(setTimeout); 4 | 5 | const testResults = new Map(); 6 | const tests = []; 7 | const beforeTests = []; 8 | const afterTests = []; 9 | 10 | function run(desc, fn) { 11 | const startTime = process.hrtime(); 12 | const before = process.memoryUsage(); 13 | let prepareTime, prepareStart; 14 | fn(() => { 15 | prepareTime = process.hrtime(startTime); 16 | prepareStart = process.hrtime(); 17 | }); 18 | 19 | const time = process.hrtime(prepareStart); 20 | const after = process.memoryUsage(); 21 | const result = { 22 | name: desc, 23 | rss: after.rss - before.rss, 24 | heapTotal: after.heapTotal - before.heapTotal, 25 | heapUsed: after.heapUsed - before.heapUsed, 26 | external: after.external - before.external, 27 | time: { 28 | prepareTime, 29 | time 30 | } 31 | }; 32 | testResults.set(desc, result); 33 | } 34 | function test(desc /*: string*/, fn /*: (prepared: () => void) => any*/) { 35 | tests.push({ desc, fn }); 36 | if (pending) return; 37 | begin(); 38 | } 39 | 40 | function beforeAll(fn /*: () => any*/) { 41 | beforeTests.push(fn); 42 | } 43 | 44 | function afterAll(fn /*: (testResults: Map) => any*/) { 45 | afterTests.push(fn); 46 | } 47 | 48 | let pending = false; 49 | async function begin() { 50 | pending = true; 51 | await delay(100); 52 | for (const fn of beforeTests) { 53 | fn(); 54 | } 55 | while (tests.length) { 56 | const { desc, fn } = tests.shift(); 57 | global.gc(true); 58 | await delay(100); 59 | run(desc, fn); 60 | } 61 | for (const fn of afterTests) { 62 | fn(testResults); 63 | } 64 | } 65 | 66 | module.exports = { 67 | test, 68 | beforeAll, 69 | afterAll 70 | }; 71 | -------------------------------------------------------------------------------- /bench/mock.js: -------------------------------------------------------------------------------- 1 | const MAX = 1000; 2 | const MODIFY_FACTOR = 0.1; 3 | 4 | function getItem(any, i) { 5 | return { 6 | todo: `todo_${i}`, 7 | done: false, 8 | someThingCompletelyIrrelevant: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] 9 | }; 10 | } 11 | function generateDraft() { 12 | const draft = []; 13 | for (let i = 0; i < MAX; i++) { 14 | draft.push(getItem(undefined, i)); 15 | } 16 | return draft; 17 | } 18 | 19 | module.exports.generateDraft = generateDraft; 20 | -------------------------------------------------------------------------------- /bench/perf.js: -------------------------------------------------------------------------------- 1 | var Benchmark = require("benchmark"); 2 | var suite = new Benchmark.Suite(); 3 | 4 | var fn = () => 5; 5 | var proxy = data => { 6 | return new Proxy(data, { 7 | set(target, key) { 8 | fn(); 9 | return target[key]; 10 | } 11 | }); 12 | }; 13 | 14 | const data2 = () => ({ 15 | ui: { a: { b: 5 } }, 16 | password: { hash: "", data: "" }, 17 | name: "", 18 | ke: { a: 5 }, 19 | d: 6, 20 | name2: "", 21 | ke3: { a: 5 }, 22 | d5: 6, 23 | name62: "", 24 | ke35: { a: 5 }, 25 | d54: 6, 26 | name626: "", 27 | ke385: { a: 5 }, 28 | d548: 6 29 | }); 30 | 31 | const data3 = () => { 32 | return new Array(10).fill(0).reduce((acc, _, el) => { 33 | acc[el] = {}; 34 | return acc; 35 | }, {}); 36 | }; 37 | console.log(data3()); 38 | const getters = obj => { 39 | for (let i in obj) { 40 | const value = obj[i]; 41 | Object.defineProperty(obj, i, { 42 | set() { 43 | fn(); 44 | return value; 45 | } 46 | }); 47 | } 48 | return obj; 49 | }; 50 | const proxyObj = proxy(data2()); 51 | const gettersObj = getters(data2()); 52 | 53 | // add tests 54 | suite 55 | .add("access proxy", function() { 56 | const t = proxyObj.a; 57 | return { t }; 58 | }) 59 | .add("access getters", function() { 60 | const t = gettersObj.a; 61 | return { t }; 62 | }) 63 | .add("create proxy and access", function() { 64 | const data = proxy(data2()); 65 | return data.ui; 66 | }) 67 | .add("wrap by getters and access", function() { 68 | const data = getters(data2()); 69 | return data.ui; 70 | }) 71 | .on("cycle", function(event) { 72 | console.log(String(event.target)); 73 | }) 74 | .on("complete", function() { 75 | console.log("Fastest is " + this.filter("fastest").map("name")); 76 | }) 77 | .run(); 78 | -------------------------------------------------------------------------------- /bench/printResults.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | 3 | const doDiffWithFloor = { 4 | external: false, 5 | total: false, 6 | used: false, 7 | rss: true 8 | }; 9 | 10 | function memoryText(size) { 11 | return `${(size / 1000 / 1000).toFixed(1)} Mb`; 12 | } 13 | module.exports.printResults = function printResults(testResults /*: Map*/) { 14 | //$off 15 | const prettyHrtime = require("pretty-hrtime"); 16 | const floor = testResults.get("just mutate"); 17 | if (!floor) return; 18 | testResults.delete("just mutate"); 19 | console.log(`* ${floor.name} [FLOOR] 20 | create: ${prettyHrtime(floor.time.prepareTime)} 21 | update: ${prettyHrtime(floor.time.time)} 22 | heap: 23 | total ${memoryText(floor.heapTotal)} 24 | used ${memoryText(floor.heapUsed)} 25 | rss: ${memoryText(floor.rss)} 26 | `); 27 | for (const result of testResults.values()) { 28 | const total = doDiffWithFloor.total ? result.heapTotal - floor.heapTotal : result.heapTotal; 29 | const used = doDiffWithFloor.used ? result.heapUsed - floor.heapUsed : result.heapUsed; 30 | const rss = doDiffWithFloor.rss ? result.rss - floor.rss : result.rss; 31 | const external = doDiffWithFloor.external ? result.external - floor.external : result.external; 32 | 33 | console.log(`* ${result.name} 34 | create: ${prettyHrtime(result.time.prepareTime)} 35 | update: ${prettyHrtime(result.time.time)} 36 | heap: 37 | total ${memoryText(total)} 38 | used ${memoryText(used)} 39 | rss: ${memoryText(rss)} 40 | `); 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /bench/suite.js: -------------------------------------------------------------------------------- 1 | const { createAction, createState, local } = require("../"); 2 | const { generateDraft } = require("./mock"); 3 | const { observable } = require("mobx"); 4 | const { createStore, combineReducers } = require("redux"); 5 | const { createStore: efStore, createEvent: efAction } = require("effector"); 6 | 7 | const MAX = 1000; 8 | const MODIFY_FACTOR = 0.5; 9 | 10 | const reducer = (draft = generateDraft()) => { 11 | const newDraft = draft.concat([]); 12 | for (let i = 0; i < MAX * MODIFY_FACTOR; i++) { 13 | newDraft[i] = Object.assign({}, newDraft[i], { done: Math.random() }); 14 | } 15 | return newDraft; 16 | }; 17 | 18 | suite("restate", function() { 19 | bench("create", function() { 20 | const toggle = createAction(""); 21 | const state = createState(generateDraft()); 22 | state.on(toggle, (_, p) => p); 23 | state.use(local); 24 | }); 25 | 26 | const toggle = createAction(""); 27 | const state = createState(generateDraft()); 28 | state.on(toggle, reducer); 29 | state.use(local); 30 | 31 | bench("modify", function() { 32 | state.subscribe(e => e); 33 | toggle(); 34 | }); 35 | }); 36 | 37 | function makeRecReducer(i) { 38 | if (i === 20) { 39 | return (d = 2) => 2; 40 | } 41 | return combineReducers({ 42 | [i]: makeRecReducer(i + 1) 43 | }); 44 | } 45 | suite("redux", function() { 46 | bench("create", function() { 47 | const store = createStore((d = null) => d, generateDraft()); 48 | store.dispatch({ type: "any" }); 49 | }); 50 | 51 | const reducerMap = {}; 52 | for (let i = 0; i < 300; i++) { 53 | reducerMap[i] = (d = 4) => 2; 54 | } 55 | const rootReducer = combineReducers({ 56 | a: combineReducers({ 57 | b: combineReducers({ 58 | c: combineReducers(reducerMap) 59 | }) 60 | }) 61 | }); 62 | let store; 63 | 64 | bench("modify complex reducer", function() { 65 | store = createStore(rootReducer); 66 | store.subscribe(() => {}); 67 | store.dispatch({ type: "init" }); 68 | }); 69 | 70 | bench("modify complex reducer rec", function() { 71 | store = createStore(makeRecReducer(0)); 72 | store.subscribe(() => {}); 73 | store.dispatch({ type: "init" }); 74 | }); 75 | 76 | bench("modify simple", function() { 77 | store = createStore((d = 2) => 2); 78 | store.subscribe(() => {}); 79 | store.dispatch({ type: "init" }); 80 | }); 81 | }); 82 | 83 | suite("mobx", function() { 84 | bench("create", function() { 85 | const data = observable.array(generateDraft()); 86 | }); 87 | 88 | bench("shallow wrap", function() { 89 | const data = observable.array(generateDraft(), { deep: false }); 90 | }); 91 | const data = observable(generateDraft()); 92 | 93 | bench("modify", function() { 94 | const mutate = draft => { 95 | for (let i = 0; i < MAX * MODIFY_FACTOR; i++) { 96 | draft[i].done = Math.random(); 97 | } 98 | }; 99 | mutate(data); 100 | }); 101 | }); 102 | 103 | suite("effector", function() { 104 | bench("create", function() { 105 | const toggle = efAction(""); 106 | const state = efStore(generateDraft()); 107 | state.on(toggle, (_, p) => p); 108 | }); 109 | 110 | const toggle = efAction(""); 111 | const state = efStore(generateDraft()); 112 | state.on(toggle, reducer); 113 | 114 | bench("modify", function() { 115 | toggle(); 116 | }); 117 | }); 118 | -------------------------------------------------------------------------------- /dist/cjs/action/apiFactory.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __assign = (this && this.__assign) || Object.assign || function(t) { 3 | for (var s, i = 1, n = arguments.length; i < n; i++) { 4 | s = arguments[i]; 5 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) 6 | t[p] = s[p]; 7 | } 8 | return t; 9 | }; 10 | Object.defineProperty(exports, "__esModule", { value: true }); 11 | var createAction_1 = require("./createAction"); 12 | function createApi(state, actionsDecl) { 13 | var update = createAction_1.createAction(Symbol("update")); 14 | state.on(update, function (s, p) { return (__assign({}, state, p)); }); 15 | var actions = { update: update }; 16 | for (var actionKey in actionsDecl) { 17 | var handler = actionsDecl[actionKey]; 18 | var act = createAction_1.createAction(Symbol(actionKey)); 19 | state.on(act, handler); 20 | actions[actionKey] = act; 21 | } 22 | return actions; 23 | } 24 | exports.createApi = createApi; 25 | //# sourceMappingURL=apiFactory.js.map -------------------------------------------------------------------------------- /dist/cjs/action/apiFactory.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"apiFactory.js","sourceRoot":"","sources":["../../../src/action/apiFactory.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,+CAA8C;AAoB9C,mBAA0B,KAAK,EAAE,WAAW;IAC1C,IAAM,MAAM,GAAG,2BAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC9C,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,UAAC,CAAC,EAAE,CAAC,IAAK,OAAA,cAAM,KAAK,EAAK,CAAC,EAAG,EAApB,CAAoB,CAAC,CAAC;IACjD,IAAM,OAAO,GAAG,EAAE,MAAM,QAAA,EAAE,CAAC;IAE3B,KAAK,IAAI,SAAS,IAAI,WAAW,EAAE;QACjC,IAAM,OAAO,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;QACvC,IAAM,GAAG,GAAG,2BAAY,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;QAC5C,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACvB,OAAO,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC;KAC1B;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAZD,8BAYC"} -------------------------------------------------------------------------------- /dist/cjs/action/createAction.h.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | //# sourceMappingURL=createAction.h.js.map -------------------------------------------------------------------------------- /dist/cjs/action/createAction.h.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"createAction.h.js","sourceRoot":"","sources":["../../../src/action/createAction.h.ts"],"names":[],"mappings":""} -------------------------------------------------------------------------------- /dist/cjs/action/createAction.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | var mutator = function (defaultValue) { return function (name) { 4 | if (name === void 0) { name = Symbol(); } 5 | var dispatch = null; 6 | var actionRaw = function (data) { 7 | if (data === void 0) { data = defaultValue; } 8 | return { type: name, payload: data }; 9 | }; 10 | var action = function (data) { 11 | if (data === void 0) { data = defaultValue; } 12 | var action = actionRaw(data); 13 | dispatch && dispatch(action); 14 | return action; 15 | }; 16 | var actionMeta = { 17 | getType: function () { return name; }, 18 | defaultValue: defaultValue, 19 | setDispatch: function (d) { 20 | dispatch = d; 21 | }, 22 | getDispatch: function () { return dispatch; }, 23 | raw: actionRaw 24 | }; 25 | return Object.assign(action, actionMeta); 26 | }; }; 27 | var createAction = mutator(null); 28 | exports.createAction = createAction; 29 | function createAsyncAction(name) { 30 | return createActions({ 31 | failure: build.action(), 32 | success: build.action(), 33 | request: build.action() 34 | }, name + "_"); 35 | } 36 | var build = { 37 | plain: createAction, 38 | action: function () { 39 | return function (name) { return createAction(name); }; 40 | }, 41 | mutator: mutator, 42 | async: function () { return function (name) { 43 | return createAsyncAction(name); 44 | }; } 45 | }; 46 | exports.build = build; 47 | function createActions(actions, prefix) { 48 | if (prefix === void 0) { prefix = "@"; } 49 | return Object.keys(actions).reduce(function (acc, el) { 50 | acc[el] = actions[el](prefix + "/" + el); 51 | return acc; 52 | }, {}); 53 | } 54 | exports.createActions = createActions; 55 | var t = createActions({ 56 | act: build.async() 57 | }); 58 | var createEffects = createActions; 59 | exports.createEffects = createEffects; 60 | //# sourceMappingURL=createAction.js.map -------------------------------------------------------------------------------- /dist/cjs/action/createAction.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"createAction.js","sourceRoot":"","sources":["../../../src/action/createAction.ts"],"names":[],"mappings":";;AAEA,IAAM,OAAO,GAAG,UAAI,YAAe,IAAK,OAAA,UACtC,IAAgC;IAAhC,qBAAA,EAAA,OAAwB,MAAM,EAAE;IAEhC,IAAI,QAAQ,GAAG,IAAI,CAAC;IAEpB,IAAM,SAAS,GAAG,UAAC,IAAmB;QAAnB,qBAAA,EAAA,mBAAmB;QACpC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACvC,CAAC,CAAC;IACF,IAAM,MAAM,GAAQ,UAAC,IAAmB;QAAnB,qBAAA,EAAA,mBAAmB;QACtC,IAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC/B,QAAQ,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC7B,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;IACF,IAAM,UAAU,GAAG;QACjB,OAAO,EAAE,cAAM,OAAA,IAAI,EAAJ,CAAI;QACnB,YAAY,cAAA;QACZ,WAAW,YAAC,CAAC;YACX,QAAQ,GAAG,CAAC,CAAC;QACf,CAAC;QACD,WAAW,EAAE,cAAM,OAAA,QAAQ,EAAR,CAAQ;QAC3B,GAAG,EAAE,SAAS;KACf,CAAC;IAEF,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAC3C,CAAC,EAxBuC,CAwBvC,CAAC;AAEF,IAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAyC1B,oCAAY;AAvCrB,2BAAoC,IAAY;IAC9C,OAAO,aAAa,CAClB;QACE,OAAO,EAAE,KAAK,CAAC,MAAM,EAAK;QAC1B,OAAO,EAAE,KAAK,CAAC,MAAM,EAAK;QAC1B,OAAO,EAAE,KAAK,CAAC,MAAM,EAAK;KAC3B,EACD,IAAI,GAAG,GAAG,CACX,CAAC;AACJ,CAAC;AAED,IAAM,KAAK,GAAG;IACZ,KAAK,EAAE,YAAY;IACnB,MAAM,EAAN;QACE,OAAO,UAAC,IAAY,IAAK,OAAA,YAAY,CAAI,IAAI,CAAC,EAArB,CAAqB,CAAC;IACjD,CAAC;IACD,OAAO,EAAE,OAAO;IAChB,KAAK,EAAE,cAA4B,OAAA,UAAA,IAAI;QACrC,OAAO,iBAAiB,CAAU,IAAI,CAAC,CAAC;IAC1C,CAAC,EAFkC,CAElC;CACF,CAAC;AAmBqB,sBAAK;AAjB5B,uBACE,OAAU,EACV,MAAoB;IAApB,uBAAA,EAAA,YAAoB;IAEpB,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,CAChC,UAAC,GAAG,EAAE,EAAE;QACN,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,CAAC;QACzC,OAAO,GAAG,CAAC;IACb,CAAC,EACD,EAAwB,CACzB,CAAC;AACJ,CAAC;AAM6B,sCAAa;AAL3C,IAAM,CAAC,GAAG,aAAa,CAAC;IACtB,GAAG,EAAE,KAAK,CAAC,KAAK,EAAE;CACnB,CAAC,CAAC;AAEH,IAAM,aAAa,GAAG,aAAa,CAAC;AACS,sCAAa"} -------------------------------------------------------------------------------- /dist/cjs/action/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | function __export(m) { 3 | for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; 4 | } 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | __export(require("./createAction")); 7 | __export(require("./apiFactory")); 8 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /dist/cjs/action/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/action/index.ts"],"names":[],"mappings":";;;;;AAAA,oCAA+B;AAE/B,kCAA6B"} -------------------------------------------------------------------------------- /dist/cjs/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __values = (this && this.__values) || function (o) { 3 | var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; 4 | if (m) return m.call(o); 5 | return { 6 | next: function () { 7 | if (o && i >= o.length) o = void 0; 8 | return { value: o && o[i++], done: !o }; 9 | } 10 | }; 11 | }; 12 | function __export(m) { 13 | for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; 14 | } 15 | Object.defineProperty(exports, "__esModule", { value: true }); 16 | var state_1 = require("./state"); 17 | function createState(initialState) { 18 | if (initialState === undefined) { 19 | throw new Error("initial state cannot be undefined"); 20 | } 21 | var state; 22 | if (initialState && typeof initialState === "object") { 23 | var firstKey = Object.keys(initialState)[0]; 24 | if (initialState[firstKey] && 25 | (initialState[firstKey].reducer || 26 | initialState[firstKey].getType || 27 | typeof initialState[firstKey] === "function")) { 28 | // @ts-ignore 29 | state = new state_1.CombinedReducer(initialState); 30 | } 31 | else { 32 | state = new state_1.BaseReducerBuilder(initialState); 33 | } 34 | } 35 | else { 36 | state = new state_1.BaseReducerBuilder(initialState); 37 | } 38 | state.use = function (d, gs) { return use(state, d, gs); }; 39 | state.createStore = function (fn) { 40 | var store = fn(state.reducer, state); 41 | if (!store) { 42 | throw new Error("you must return store from createStore method"); 43 | } 44 | use(state, store.dispatch); 45 | }; 46 | return state; 47 | } 48 | exports.createState = createState; 49 | function forEachStore(stores, fn) { 50 | for (var item in stores) { 51 | if (stores[item]) { 52 | fn(stores[item]); 53 | if (stores[item].stores) { 54 | forEachStore(stores[item].stores, fn); 55 | } 56 | } 57 | } 58 | } 59 | function forEachAction(store, fn) { 60 | for (var item in store.handlers) { 61 | fn(store.handlers[item]); 62 | } 63 | try { 64 | for (var _a = __values(Object.getOwnPropertySymbols(store.handlers)), _b = _a.next(); !_b.done; _b = _a.next()) { 65 | var item = _b.value; 66 | fn(store.handlers[item]); 67 | } 68 | } 69 | catch (e_1_1) { e_1 = { error: e_1_1 }; } 70 | finally { 71 | try { 72 | if (_b && !_b.done && (_c = _a.return)) _c.call(_a); 73 | } 74 | finally { if (e_1) throw e_1.error; } 75 | } 76 | var e_1, _c; 77 | } 78 | function use(store, dispatch, getState) { 79 | if (getState === void 0) { getState = null; } 80 | var setDispatch = function (data) { 81 | data.action.setDispatch(dispatch); 82 | }; 83 | forEachAction(store, setDispatch); 84 | store[state_1.getRootStateSymbol] = getState; 85 | forEachStore(store.stores, function (el) { 86 | el[state_1.getRootStateSymbol] = getState; 87 | forEachAction(el, setDispatch); 88 | }); 89 | } 90 | __export(require("./action")); 91 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /dist/cjs/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/cjs/state/BaseReducer.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | var helpers_1 = require("./helpers"); 4 | exports.reducerSymbol = Symbol(); 5 | exports.getRootStateSymbol = Symbol(); 6 | function get(object, keys) { 7 | keys = Array.isArray(keys) ? keys : keys.split("."); 8 | object = object[keys[0]]; 9 | if (object && keys.length > 1) { 10 | return get(object, keys.slice(1)); 11 | } 12 | return object; 13 | } 14 | function isReducer(reducer) { 15 | return reducer && reducer[exports.reducerSymbol]; 16 | } 17 | exports.isReducer = isReducer; 18 | var BaseReducerBuilder = /** @class */ (function () { 19 | function BaseReducerBuilder(initialState) { 20 | var _this = this; 21 | this.initialState = initialState; 22 | this.handlers = {}; 23 | this[_a] = null; 24 | this[_b] = {}; 25 | this.getState = function () { 26 | if (!_this[exports.getRootStateSymbol]) { 27 | throw new Error("please set getState to root reducer"); 28 | } 29 | return _this.select(_this[exports.getRootStateSymbol]()); 30 | }; 31 | this.on = function (action, handler) { 32 | if (action === undefined || action === null || !action.getType) { 33 | throw new Error("action should be an action type, got " + action); 34 | } 35 | _this.handlers[action.getType()] = { 36 | handler: handler, 37 | action: action 38 | }; 39 | return _this; 40 | }; 41 | this.select = function (rs) { 42 | if (typeof rs === "function") { 43 | return _this.mapState(rs); 44 | } 45 | var path = _this.getPath(); 46 | return path.length ? get(rs, _this.getPath()) : rs; 47 | }; 48 | this.mapState = function (fn) { 49 | if (fn === void 0) { fn = helpers_1.identity; } 50 | return function (state, props) { return fn(_this.select(state), props, state); }; 51 | }; 52 | this.reset = function (action) { 53 | _this.on(action, function (state) { return _this.initialState; }); 54 | return _this; 55 | }; 56 | this.reducer = function (state, action) { 57 | if (state === void 0) { state = _this.initialState; } 58 | if (!action) { 59 | return state; 60 | } 61 | var type = action.type, payload = action.payload; 62 | var handlerObj = _this.handlers[type]; 63 | if (handlerObj && handlerObj.handler) { 64 | var handler = _this.handlers[type].handler; 65 | state = handler(state, payload, action); 66 | } 67 | return state; 68 | }; 69 | this.mixin = function (fn) { return Object.assign(_this, fn(_this)); }; 70 | this.pipe = function (fn) { return fn(_this); }; 71 | if (typeof initialState === "undefined") { 72 | throw new Error("initial state should not be undefined"); 73 | } 74 | this.reducer = this.reducer.bind(this); 75 | } 76 | BaseReducerBuilder.prototype.setPath = function (path) { 77 | this.path = path; 78 | }; 79 | BaseReducerBuilder.prototype.getPath = function () { 80 | if (this.parent) { 81 | return this.parent.getPath().concat(this.path); 82 | } 83 | else { 84 | return this.path ? [this.path] : []; 85 | } 86 | }; 87 | return BaseReducerBuilder; 88 | }()); 89 | _a = exports.getRootStateSymbol, _b = exports.reducerSymbol; 90 | exports.BaseReducerBuilder = BaseReducerBuilder; 91 | var _a, _b; 92 | //# sourceMappingURL=BaseReducer.js.map -------------------------------------------------------------------------------- /dist/cjs/state/BaseReducer.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"BaseReducer.js","sourceRoot":"","sources":["../../../src/state/BaseReducer.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/cjs/state/CombinedReducer.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __extends = (this && this.__extends) || (function () { 3 | var extendStatics = Object.setPrototypeOf || 4 | ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 5 | function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; 6 | return function (d, b) { 7 | extendStatics(d, b); 8 | function __() { this.constructor = d; } 9 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 10 | }; 11 | })(); 12 | Object.defineProperty(exports, "__esModule", { value: true }); 13 | var redux_1 = require("redux"); 14 | var helpers_1 = require("./helpers"); 15 | var BaseReducer_1 = require("./BaseReducer"); 16 | var CombinedReducer = /** @class */ (function (_super) { 17 | __extends(CombinedReducer, _super); 18 | function CombinedReducer(storesToParse) { 19 | var _this = _super.call(this, {}) || this; 20 | var parent = { getPath: _this.getPath.bind(_this) }; 21 | var stores = {}; 22 | var reducersMap = {}; 23 | _this.stores = stores; 24 | Object.keys(storesToParse).forEach(function (el) { 25 | var storeCandidate = storesToParse[el]; 26 | if (storeCandidate && storeCandidate.getType) { 27 | // store candidate is action with default value so we transform it to reducer 28 | storeCandidate = storeCandidate; 29 | storeCandidate = new BaseReducer_1.BaseReducerBuilder(storeCandidate.defaultValue).on(storeCandidate, helpers_1.identity2); 30 | } 31 | else if (typeof storeCandidate === "function") { 32 | // store candidate is regular reducer so we just wrap it 33 | var tmpReducer = new BaseReducer_1.BaseReducerBuilder(null); 34 | tmpReducer.reducer = storeCandidate; 35 | storeCandidate = tmpReducer; 36 | } 37 | stores[el] = storeCandidate; 38 | stores[el].setPath(el); 39 | stores[el].parent = parent; 40 | reducersMap[el] = stores[el].reducer; 41 | }); 42 | var nestedReducer = redux_1.combineReducers(reducersMap); 43 | var plainReducer = _this.reducer; 44 | _this.reducer = function (state, action) { 45 | //@ts-ignore 46 | return plainReducer(nestedReducer(state, action), action); 47 | }; 48 | return _this; 49 | } 50 | return CombinedReducer; 51 | }(BaseReducer_1.BaseReducerBuilder)); 52 | exports.CombinedReducer = CombinedReducer; 53 | //# sourceMappingURL=CombinedReducer.js.map -------------------------------------------------------------------------------- /dist/cjs/state/CombinedReducer.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"CombinedReducer.js","sourceRoot":"","sources":["../../../src/state/CombinedReducer.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,+BAAwC;AAGxC,qCAAiD;AACjD,6CAA8D;AAG9D;IAAqE,mCAAwB;IAE3F,yBAAY,aAAgB;QAA5B,YACE,kBAAM,EAAS,CAAC,SAmCjB;QAjCC,IAAM,MAAM,GAAG,EAAE,OAAO,EAAE,KAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAI,CAAC,EAAE,CAAC;QACpD,IAAM,MAAM,GAAG,EAAE,CAAC;QAClB,IAAM,WAAW,GAAG,EAAE,CAAC;QACvB,KAAI,CAAC,MAAM,GAAG,MAAa,CAAC;QAC5B,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,UAAA,EAAE;YACnC,IAAI,cAAc,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC;YAEvC,IAAI,cAAc,IAAK,cAAsC,CAAC,OAAO,EAAE;gBACrE,6EAA6E;gBAC7E,cAAc,GAAG,cAAqC,CAAC;gBACvD,cAAc,GAAG,IAAI,gCAAkB,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,EAAE,CACrE,cAAc,EACd,mBAAS,CACV,CAAC;aACH;iBAAM,IAAI,OAAO,cAAc,KAAK,UAAU,EAAE;gBAC/C,wDAAwD;gBACxD,IAAM,UAAU,GAAG,IAAI,gCAAkB,CAAC,IAAI,CAAC,CAAC;gBAChD,UAAU,CAAC,OAAO,GAAG,cAAc,CAAC;gBACpC,cAAc,GAAG,UAAU,CAAC;aAC7B;YAED,MAAM,CAAC,EAAE,CAAC,GAAG,cAAyC,CAAC;YACvD,MAAM,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACvB,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,GAAG,MAAM,CAAC;YAC3B,WAAW,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,IAAM,aAAa,GAAG,uBAAe,CAAC,WAAW,CAAC,CAAC;QACnD,IAAM,YAAY,GAAG,KAAI,CAAC,OAAO,CAAC;QAClC,KAAI,CAAC,OAAO,GAAG,UAAC,KAAK,EAAE,MAAM;YAC3B,YAAY;YACZ,OAAO,YAAY,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;QAC5D,CAAC,CAAC;;IACJ,CAAC;IACH,sBAAC;AAAD,CAAC,AAvCD,CAAqE,gCAAkB,GAuCtF;AAvCY,0CAAe"} -------------------------------------------------------------------------------- /dist/cjs/state/helpers.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.identity = function (d) { 4 | var _ = []; 5 | for (var _i = 1; _i < arguments.length; _i++) { 6 | _[_i - 1] = arguments[_i]; 7 | } 8 | return d; 9 | }; 10 | exports.didentity = function (defaultV) { return function (d) { 11 | if (d === void 0) { d = defaultV; } 12 | var _ = []; 13 | for (var _i = 1; _i < arguments.length; _i++) { 14 | _[_i - 1] = arguments[_i]; 15 | } 16 | return d; 17 | }; }; 18 | exports.identity2 = function (_, d) { return d; }; 19 | //# sourceMappingURL=helpers.js.map -------------------------------------------------------------------------------- /dist/cjs/state/helpers.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../src/state/helpers.ts"],"names":[],"mappings":";;AAAa,QAAA,QAAQ,GAAG,UAAI,CAAI;IAAE,WAAW;SAAX,UAAW,EAAX,qBAAW,EAAX,IAAW;QAAX,0BAAW;;IAAQ,OAAA,CAAC;AAAD,CAAC,CAAC;AAC1C,QAAA,SAAS,GAAG,UAAI,QAAW,IAAK,OAAA,UAAC,CAAe;IAAf,kBAAA,EAAA,YAAe;IAAE,WAAW;SAAX,UAAW,EAAX,qBAAW,EAAX,IAAW;QAAX,0BAAW;;IAAQ,OAAA,CAAC;AAAD,CAAC,EAAtC,CAAsC,CAAC;AAEvE,QAAA,SAAS,GAAG,UAAI,CAAC,EAAE,CAAI,IAAQ,OAAA,CAAC,EAAD,CAAC,CAAC"} -------------------------------------------------------------------------------- /dist/cjs/state/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | function __export(m) { 3 | for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; 4 | } 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | __export(require("./BaseReducer")); 7 | __export(require("./CombinedReducer")); 8 | __export(require("./helpers")); 9 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /dist/cjs/state/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/state/index.ts"],"names":[],"mappings":";;;;;AAAA,mCAA8B;AAC9B,uCAAkC;AAClC,+BAA0B"} -------------------------------------------------------------------------------- /dist/cjs/state/reducer.h.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | //# sourceMappingURL=reducer.h.js.map -------------------------------------------------------------------------------- /dist/cjs/state/reducer.h.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"reducer.h.js","sourceRoot":"","sources":["../../../src/state/reducer.h.ts"],"names":[],"mappings":""} -------------------------------------------------------------------------------- /dist/lib/action/apiFactory.js: -------------------------------------------------------------------------------- 1 | var __assign = (this && this.__assign) || Object.assign || function(t) { 2 | for (var s, i = 1, n = arguments.length; i < n; i++) { 3 | s = arguments[i]; 4 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) 5 | t[p] = s[p]; 6 | } 7 | return t; 8 | }; 9 | import { createAction } from "./createAction"; 10 | export function createApi(state, actionsDecl) { 11 | var update = createAction(Symbol("update")); 12 | state.on(update, function (s, p) { return (__assign({}, state, p)); }); 13 | var actions = { update: update }; 14 | for (var actionKey in actionsDecl) { 15 | var handler = actionsDecl[actionKey]; 16 | var act = createAction(Symbol(actionKey)); 17 | state.on(act, handler); 18 | actions[actionKey] = act; 19 | } 20 | return actions; 21 | } 22 | //# sourceMappingURL=apiFactory.js.map -------------------------------------------------------------------------------- /dist/lib/action/apiFactory.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"apiFactory.js","sourceRoot":"","sources":["../../../src/action/apiFactory.ts"],"names":[],"mappings":";;;;;;;;AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAoB9C,MAAM,oBAAoB,KAAK,EAAE,WAAW;IAC1C,IAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC9C,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,UAAC,CAAC,EAAE,CAAC,IAAK,OAAA,cAAM,KAAK,EAAK,CAAC,EAAG,EAApB,CAAoB,CAAC,CAAC;IACjD,IAAM,OAAO,GAAG,EAAE,MAAM,QAAA,EAAE,CAAC;IAE3B,KAAK,IAAI,SAAS,IAAI,WAAW,EAAE;QACjC,IAAM,OAAO,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;QACvC,IAAM,GAAG,GAAG,YAAY,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;QAC5C,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACvB,OAAO,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC;KAC1B;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"} -------------------------------------------------------------------------------- /dist/lib/action/createAction.h.js: -------------------------------------------------------------------------------- 1 | //# sourceMappingURL=createAction.h.js.map -------------------------------------------------------------------------------- /dist/lib/action/createAction.h.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"createAction.h.js","sourceRoot":"","sources":["../../../src/action/createAction.h.ts"],"names":[],"mappings":""} -------------------------------------------------------------------------------- /dist/lib/action/createAction.js: -------------------------------------------------------------------------------- 1 | var mutator = function (defaultValue) { return function (name) { 2 | if (name === void 0) { name = Symbol(); } 3 | var dispatch = null; 4 | var actionRaw = function (data) { 5 | if (data === void 0) { data = defaultValue; } 6 | return { type: name, payload: data }; 7 | }; 8 | var action = function (data) { 9 | if (data === void 0) { data = defaultValue; } 10 | var action = actionRaw(data); 11 | dispatch && dispatch(action); 12 | return action; 13 | }; 14 | var actionMeta = { 15 | getType: function () { return name; }, 16 | defaultValue: defaultValue, 17 | setDispatch: function (d) { 18 | dispatch = d; 19 | }, 20 | getDispatch: function () { return dispatch; }, 21 | raw: actionRaw 22 | }; 23 | return Object.assign(action, actionMeta); 24 | }; }; 25 | var createAction = mutator(null); 26 | function createAsyncAction(name) { 27 | return createActions({ 28 | failure: build.action(), 29 | success: build.action(), 30 | request: build.action() 31 | }, name + "_"); 32 | } 33 | var build = { 34 | plain: createAction, 35 | action: function () { 36 | return function (name) { return createAction(name); }; 37 | }, 38 | mutator: mutator, 39 | async: function () { return function (name) { 40 | return createAsyncAction(name); 41 | }; } 42 | }; 43 | function createActions(actions, prefix) { 44 | if (prefix === void 0) { prefix = "@"; } 45 | return Object.keys(actions).reduce(function (acc, el) { 46 | acc[el] = actions[el](prefix + "/" + el); 47 | return acc; 48 | }, {}); 49 | } 50 | var t = createActions({ 51 | act: build.async() 52 | }); 53 | var createEffects = createActions; 54 | export { createAction, build, createActions, createEffects }; 55 | //# sourceMappingURL=createAction.js.map -------------------------------------------------------------------------------- /dist/lib/action/createAction.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"createAction.js","sourceRoot":"","sources":["../../../src/action/createAction.ts"],"names":[],"mappings":"AAEA,IAAM,OAAO,GAAG,UAAI,YAAe,IAAK,OAAA,UACtC,IAAgC;IAAhC,qBAAA,EAAA,OAAwB,MAAM,EAAE;IAEhC,IAAI,QAAQ,GAAG,IAAI,CAAC;IAEpB,IAAM,SAAS,GAAG,UAAC,IAAmB;QAAnB,qBAAA,EAAA,mBAAmB;QACpC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACvC,CAAC,CAAC;IACF,IAAM,MAAM,GAAQ,UAAC,IAAmB;QAAnB,qBAAA,EAAA,mBAAmB;QACtC,IAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC/B,QAAQ,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC7B,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;IACF,IAAM,UAAU,GAAG;QACjB,OAAO,EAAE,cAAM,OAAA,IAAI,EAAJ,CAAI;QACnB,YAAY,cAAA;QACZ,WAAW,YAAC,CAAC;YACX,QAAQ,GAAG,CAAC,CAAC;QACf,CAAC;QACD,WAAW,EAAE,cAAM,OAAA,QAAQ,EAAR,CAAQ;QAC3B,GAAG,EAAE,SAAS;KACf,CAAC;IAEF,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAC3C,CAAC,EAxBuC,CAwBvC,CAAC;AAEF,IAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnC,2BAAoC,IAAY;IAC9C,OAAO,aAAa,CAClB;QACE,OAAO,EAAE,KAAK,CAAC,MAAM,EAAK;QAC1B,OAAO,EAAE,KAAK,CAAC,MAAM,EAAK;QAC1B,OAAO,EAAE,KAAK,CAAC,MAAM,EAAK;KAC3B,EACD,IAAI,GAAG,GAAG,CACX,CAAC;AACJ,CAAC;AAED,IAAM,KAAK,GAAG;IACZ,KAAK,EAAE,YAAY;IACnB,MAAM,EAAN;QACE,OAAO,UAAC,IAAY,IAAK,OAAA,YAAY,CAAI,IAAI,CAAC,EAArB,CAAqB,CAAC;IACjD,CAAC;IACD,OAAO,EAAE,OAAO;IAChB,KAAK,EAAE,cAA4B,OAAA,UAAA,IAAI;QACrC,OAAO,iBAAiB,CAAU,IAAI,CAAC,CAAC;IAC1C,CAAC,EAFkC,CAElC;CACF,CAAC;AAEF,uBACE,OAAU,EACV,MAAoB;IAApB,uBAAA,EAAA,YAAoB;IAEpB,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,CAChC,UAAC,GAAG,EAAE,EAAE;QACN,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,CAAC;QACzC,OAAO,GAAG,CAAC;IACb,CAAC,EACD,EAAwB,CACzB,CAAC;AACJ,CAAC;AACD,IAAM,CAAC,GAAG,aAAa,CAAC;IACtB,GAAG,EAAE,KAAK,CAAC,KAAK,EAAE;CACnB,CAAC,CAAC;AAEH,IAAM,aAAa,GAAG,aAAa,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC"} -------------------------------------------------------------------------------- /dist/lib/action/index.js: -------------------------------------------------------------------------------- 1 | export * from "./createAction"; 2 | export * from "./apiFactory"; 3 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /dist/lib/action/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/action/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAE/B,cAAc,cAAc,CAAC"} -------------------------------------------------------------------------------- /dist/lib/index.js: -------------------------------------------------------------------------------- 1 | var __values = (this && this.__values) || function (o) { 2 | var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; 3 | if (m) return m.call(o); 4 | return { 5 | next: function () { 6 | if (o && i >= o.length) o = void 0; 7 | return { value: o && o[i++], done: !o }; 8 | } 9 | }; 10 | }; 11 | import { CombinedReducer, BaseReducerBuilder, getRootStateSymbol } from "./state"; 12 | export function createState(initialState) { 13 | if (initialState === undefined) { 14 | throw new Error("initial state cannot be undefined"); 15 | } 16 | var state; 17 | if (initialState && typeof initialState === "object") { 18 | var firstKey = Object.keys(initialState)[0]; 19 | if (initialState[firstKey] && 20 | (initialState[firstKey].reducer || 21 | initialState[firstKey].getType || 22 | typeof initialState[firstKey] === "function")) { 23 | // @ts-ignore 24 | state = new CombinedReducer(initialState); 25 | } 26 | else { 27 | state = new BaseReducerBuilder(initialState); 28 | } 29 | } 30 | else { 31 | state = new BaseReducerBuilder(initialState); 32 | } 33 | state.use = function (d, gs) { return use(state, d, gs); }; 34 | state.createStore = function (fn) { 35 | var store = fn(state.reducer, state); 36 | if (!store) { 37 | throw new Error("you must return store from createStore method"); 38 | } 39 | use(state, store.dispatch); 40 | }; 41 | return state; 42 | } 43 | function forEachStore(stores, fn) { 44 | for (var item in stores) { 45 | if (stores[item]) { 46 | fn(stores[item]); 47 | if (stores[item].stores) { 48 | forEachStore(stores[item].stores, fn); 49 | } 50 | } 51 | } 52 | } 53 | function forEachAction(store, fn) { 54 | for (var item in store.handlers) { 55 | fn(store.handlers[item]); 56 | } 57 | try { 58 | for (var _a = __values(Object.getOwnPropertySymbols(store.handlers)), _b = _a.next(); !_b.done; _b = _a.next()) { 59 | var item = _b.value; 60 | fn(store.handlers[item]); 61 | } 62 | } 63 | catch (e_1_1) { e_1 = { error: e_1_1 }; } 64 | finally { 65 | try { 66 | if (_b && !_b.done && (_c = _a.return)) _c.call(_a); 67 | } 68 | finally { if (e_1) throw e_1.error; } 69 | } 70 | var e_1, _c; 71 | } 72 | function use(store, dispatch, getState) { 73 | if (getState === void 0) { getState = null; } 74 | var setDispatch = function (data) { 75 | data.action.setDispatch(dispatch); 76 | }; 77 | forEachAction(store, setDispatch); 78 | store[getRootStateSymbol] = getState; 79 | forEachStore(store.stores, function (el) { 80 | el[getRootStateSymbol] = getState; 81 | forEachAction(el, setDispatch); 82 | }); 83 | } 84 | export * from "./action"; 85 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /dist/lib/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/lib/state/BaseReducer.js: -------------------------------------------------------------------------------- 1 | import { identity } from "./helpers"; 2 | export var reducerSymbol = Symbol(); 3 | export var getRootStateSymbol = Symbol(); 4 | function get(object, keys) { 5 | keys = Array.isArray(keys) ? keys : keys.split("."); 6 | object = object[keys[0]]; 7 | if (object && keys.length > 1) { 8 | return get(object, keys.slice(1)); 9 | } 10 | return object; 11 | } 12 | export function isReducer(reducer) { 13 | return reducer && reducer[reducerSymbol]; 14 | } 15 | var BaseReducerBuilder = /** @class */ (function () { 16 | function BaseReducerBuilder(initialState) { 17 | var _this = this; 18 | this.initialState = initialState; 19 | this.handlers = {}; 20 | this[_a] = null; 21 | this[_b] = {}; 22 | this.getState = function () { 23 | if (!_this[getRootStateSymbol]) { 24 | throw new Error("please set getState to root reducer"); 25 | } 26 | return _this.select(_this[getRootStateSymbol]()); 27 | }; 28 | this.on = function (action, handler) { 29 | if (action === undefined || action === null || !action.getType) { 30 | throw new Error("action should be an action type, got " + action); 31 | } 32 | _this.handlers[action.getType()] = { 33 | handler: handler, 34 | action: action 35 | }; 36 | return _this; 37 | }; 38 | this.select = function (rs) { 39 | if (typeof rs === "function") { 40 | return _this.mapState(rs); 41 | } 42 | var path = _this.getPath(); 43 | return path.length ? get(rs, _this.getPath()) : rs; 44 | }; 45 | this.mapState = function (fn) { 46 | if (fn === void 0) { fn = identity; } 47 | return function (state, props) { return fn(_this.select(state), props, state); }; 48 | }; 49 | this.reset = function (action) { 50 | _this.on(action, function (state) { return _this.initialState; }); 51 | return _this; 52 | }; 53 | this.reducer = function (state, action) { 54 | if (state === void 0) { state = _this.initialState; } 55 | if (!action) { 56 | return state; 57 | } 58 | var type = action.type, payload = action.payload; 59 | var handlerObj = _this.handlers[type]; 60 | if (handlerObj && handlerObj.handler) { 61 | var handler = _this.handlers[type].handler; 62 | state = handler(state, payload, action); 63 | } 64 | return state; 65 | }; 66 | this.mixin = function (fn) { return Object.assign(_this, fn(_this)); }; 67 | this.pipe = function (fn) { return fn(_this); }; 68 | if (typeof initialState === "undefined") { 69 | throw new Error("initial state should not be undefined"); 70 | } 71 | this.reducer = this.reducer.bind(this); 72 | } 73 | BaseReducerBuilder.prototype.setPath = function (path) { 74 | this.path = path; 75 | }; 76 | BaseReducerBuilder.prototype.getPath = function () { 77 | if (this.parent) { 78 | return this.parent.getPath().concat(this.path); 79 | } 80 | else { 81 | return this.path ? [this.path] : []; 82 | } 83 | }; 84 | return BaseReducerBuilder; 85 | }()); 86 | export { BaseReducerBuilder }; 87 | _a = getRootStateSymbol, _b = reducerSymbol; 88 | var _a, _b; 89 | //# sourceMappingURL=BaseReducer.js.map -------------------------------------------------------------------------------- /dist/lib/state/BaseReducer.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"BaseReducer.js","sourceRoot":"","sources":["../../../src/state/BaseReducer.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/lib/state/CombinedReducer.js: -------------------------------------------------------------------------------- 1 | var __extends = (this && this.__extends) || (function () { 2 | var extendStatics = Object.setPrototypeOf || 3 | ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 4 | function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; 5 | return function (d, b) { 6 | extendStatics(d, b); 7 | function __() { this.constructor = d; } 8 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 9 | }; 10 | })(); 11 | import { combineReducers } from "redux"; 12 | import { identity2 } from "./helpers"; 13 | import { BaseReducerBuilder } from "./BaseReducer"; 14 | var CombinedReducer = /** @class */ (function (_super) { 15 | __extends(CombinedReducer, _super); 16 | function CombinedReducer(storesToParse) { 17 | var _this = _super.call(this, {}) || this; 18 | var parent = { getPath: _this.getPath.bind(_this) }; 19 | var stores = {}; 20 | var reducersMap = {}; 21 | _this.stores = stores; 22 | Object.keys(storesToParse).forEach(function (el) { 23 | var storeCandidate = storesToParse[el]; 24 | if (storeCandidate && storeCandidate.getType) { 25 | // store candidate is action with default value so we transform it to reducer 26 | storeCandidate = storeCandidate; 27 | storeCandidate = new BaseReducerBuilder(storeCandidate.defaultValue).on(storeCandidate, identity2); 28 | } 29 | else if (typeof storeCandidate === "function") { 30 | // store candidate is regular reducer so we just wrap it 31 | var tmpReducer = new BaseReducerBuilder(null); 32 | tmpReducer.reducer = storeCandidate; 33 | storeCandidate = tmpReducer; 34 | } 35 | stores[el] = storeCandidate; 36 | stores[el].setPath(el); 37 | stores[el].parent = parent; 38 | reducersMap[el] = stores[el].reducer; 39 | }); 40 | var nestedReducer = combineReducers(reducersMap); 41 | var plainReducer = _this.reducer; 42 | _this.reducer = function (state, action) { 43 | //@ts-ignore 44 | return plainReducer(nestedReducer(state, action), action); 45 | }; 46 | return _this; 47 | } 48 | return CombinedReducer; 49 | }(BaseReducerBuilder)); 50 | export { CombinedReducer }; 51 | //# sourceMappingURL=CombinedReducer.js.map -------------------------------------------------------------------------------- /dist/lib/state/CombinedReducer.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"CombinedReducer.js","sourceRoot":"","sources":["../../../src/state/CombinedReducer.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAGxC,OAAO,EAAa,SAAS,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAa,MAAM,eAAe,CAAC;AAG9D;IAAqE,mCAAwB;IAE3F,yBAAY,aAAgB;QAA5B,YACE,kBAAM,EAAS,CAAC,SAmCjB;QAjCC,IAAM,MAAM,GAAG,EAAE,OAAO,EAAE,KAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAI,CAAC,EAAE,CAAC;QACpD,IAAM,MAAM,GAAG,EAAE,CAAC;QAClB,IAAM,WAAW,GAAG,EAAE,CAAC;QACvB,KAAI,CAAC,MAAM,GAAG,MAAa,CAAC;QAC5B,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,UAAA,EAAE;YACnC,IAAI,cAAc,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC;YAEvC,IAAI,cAAc,IAAK,cAAsC,CAAC,OAAO,EAAE;gBACrE,6EAA6E;gBAC7E,cAAc,GAAG,cAAqC,CAAC;gBACvD,cAAc,GAAG,IAAI,kBAAkB,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,EAAE,CACrE,cAAc,EACd,SAAS,CACV,CAAC;aACH;iBAAM,IAAI,OAAO,cAAc,KAAK,UAAU,EAAE;gBAC/C,wDAAwD;gBACxD,IAAM,UAAU,GAAG,IAAI,kBAAkB,CAAC,IAAI,CAAC,CAAC;gBAChD,UAAU,CAAC,OAAO,GAAG,cAAc,CAAC;gBACpC,cAAc,GAAG,UAAU,CAAC;aAC7B;YAED,MAAM,CAAC,EAAE,CAAC,GAAG,cAAyC,CAAC;YACvD,MAAM,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACvB,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,GAAG,MAAM,CAAC;YAC3B,WAAW,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,IAAM,aAAa,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;QACnD,IAAM,YAAY,GAAG,KAAI,CAAC,OAAO,CAAC;QAClC,KAAI,CAAC,OAAO,GAAG,UAAC,KAAK,EAAE,MAAM;YAC3B,YAAY;YACZ,OAAO,YAAY,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;QAC5D,CAAC,CAAC;;IACJ,CAAC;IACH,sBAAC;AAAD,CAAC,AAvCD,CAAqE,kBAAkB,GAuCtF"} -------------------------------------------------------------------------------- /dist/lib/state/helpers.js: -------------------------------------------------------------------------------- 1 | export var identity = function (d) { 2 | var _ = []; 3 | for (var _i = 1; _i < arguments.length; _i++) { 4 | _[_i - 1] = arguments[_i]; 5 | } 6 | return d; 7 | }; 8 | export var didentity = function (defaultV) { return function (d) { 9 | if (d === void 0) { d = defaultV; } 10 | var _ = []; 11 | for (var _i = 1; _i < arguments.length; _i++) { 12 | _[_i - 1] = arguments[_i]; 13 | } 14 | return d; 15 | }; }; 16 | export var identity2 = function (_, d) { return d; }; 17 | //# sourceMappingURL=helpers.js.map -------------------------------------------------------------------------------- /dist/lib/state/helpers.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../src/state/helpers.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,IAAM,QAAQ,GAAG,UAAI,CAAI;IAAE,WAAW;SAAX,UAAW,EAAX,qBAAW,EAAX,IAAW;QAAX,0BAAW;;IAAQ,OAAA,CAAC;AAAD,CAAC,CAAC;AACvD,MAAM,CAAC,IAAM,SAAS,GAAG,UAAI,QAAW,IAAK,OAAA,UAAC,CAAe;IAAf,kBAAA,EAAA,YAAe;IAAE,WAAW;SAAX,UAAW,EAAX,qBAAW,EAAX,IAAW;QAAX,0BAAW;;IAAQ,OAAA,CAAC;AAAD,CAAC,EAAtC,CAAsC,CAAC;AAEpF,MAAM,CAAC,IAAM,SAAS,GAAG,UAAI,CAAC,EAAE,CAAI,IAAQ,OAAA,CAAC,EAAD,CAAC,CAAC"} -------------------------------------------------------------------------------- /dist/lib/state/index.js: -------------------------------------------------------------------------------- 1 | export * from "./BaseReducer"; 2 | export * from "./CombinedReducer"; 3 | export * from "./helpers"; 4 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /dist/lib/state/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/state/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC"} -------------------------------------------------------------------------------- /dist/lib/state/reducer.h.js: -------------------------------------------------------------------------------- 1 | //# sourceMappingURL=reducer.h.js.map -------------------------------------------------------------------------------- /dist/lib/state/reducer.h.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"reducer.h.js","sourceRoot":"","sources":["../../../src/state/reducer.h.ts"],"names":[],"mappings":""} -------------------------------------------------------------------------------- /dist/types/action/apiFactory.d.ts: -------------------------------------------------------------------------------- 1 | import { IReducerBuilder } from "../state"; 2 | import { StandardAction } from "./createAction.h"; 3 | export declare type EventHandler = (s: S, p: P) => S; 4 | export declare type IStateApi = { 5 | [P in keyof T]: T[P] extends EventHandler ? EventHandler : null; 6 | }; 7 | export declare type IApiActions = { 8 | [P in keyof T]: T[P] extends EventHandler ? StandardAction : StandardAction; 9 | }; 10 | export declare function createApi>(istate: IReducerBuilder, actionDecl: Model): IApiActions & { 11 | update: (state: S, payload: Partial) => S; 12 | }; 13 | -------------------------------------------------------------------------------- /dist/types/action/createAction.d.ts: -------------------------------------------------------------------------------- 1 | import { StandardAction, FunctionMap, CallFunctionMap } from "./createAction.h"; 2 | declare const createAction: (name?: string | Symbol) => StandardAction; 3 | declare const build: { 4 | plain: (name?: string | Symbol) => StandardAction; 5 | action(): (name: string) => StandardAction; 6 | mutator: (defaultValue: T) => (name?: string | Symbol) => StandardAction; 7 | async: () => (name: any) => CallFunctionMap<{ 8 | failure: (name: string) => StandardAction; 9 | success: (name: string) => StandardAction; 10 | request: (name: string) => StandardAction; 11 | }>; 12 | }; 13 | declare function createActions>(actions: T, prefix?: string): CallFunctionMap; 14 | declare const createEffects: typeof createActions; 15 | export { createAction, build, createActions, createEffects }; 16 | -------------------------------------------------------------------------------- /dist/types/action/createAction.h.d.ts: -------------------------------------------------------------------------------- 1 | export declare type FunctionMap = { 2 | [M in keyof T]: (...args: any[]) => any; 3 | }; 4 | export declare type CallFunctionMap> = { 5 | [M in keyof T]: ReturnType; 6 | }; 7 | export declare type StandardActionPayload = { 8 | type: string; 9 | payload: T; 10 | }; 11 | export declare type StandardAction = { 12 | defaultValue?: T; 13 | (payload?: T): StandardActionPayload; 14 | getType(): string; 15 | }; 16 | export declare type AsyncActions = { 17 | request: StandardAction; 18 | success: StandardAction; 19 | failure: StandardAction; 20 | }; 21 | -------------------------------------------------------------------------------- /dist/types/action/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from "./createAction"; 2 | export * from "./createAction.h"; 3 | export * from "./apiFactory"; 4 | -------------------------------------------------------------------------------- /dist/types/index.d.ts: -------------------------------------------------------------------------------- 1 | import { IReducerBuilder, R } from "./state"; 2 | export declare function createState(initialState: T): IReducerBuilder>; 3 | export * from "./action"; 4 | export * from "./state/reducer.h"; 5 | -------------------------------------------------------------------------------- /dist/types/state/BaseReducer.d.ts: -------------------------------------------------------------------------------- 1 | import { StandardAction, StandardActionPayload } from "../action"; 2 | export declare const reducerSymbol: unique symbol; 3 | export declare const getRootStateSymbol: unique symbol; 4 | export declare function isReducer(reducer: any): any; 5 | export declare class BaseReducerBuilder { 6 | initialState: T; 7 | handlers: {}; 8 | parent: any; 9 | path: any; 10 | [getRootStateSymbol]: () => any; 11 | private [reducerSymbol]; 12 | constructor(initialState: T); 13 | setPath(path: any): void; 14 | getPath(): any; 15 | getState: () => any; 16 | on: (action: StandardAction, handler: any) => this; 17 | select: (rs: R) => any; 18 | mapState: (fn?: (d: T, ..._: any[]) => T) => (state: any, props: any) => any; 19 | reset: (action: any) => this; 20 | reducer:

(state: T, action: StandardActionPayload

(state: T = this.initialState, action: StandardActionPayload

): T => { 81 | if (!action) { 82 | return state; 83 | } 84 | const { type, payload } = action; 85 | const handlerObj = this.handlers[type]; 86 | if (handlerObj && handlerObj.handler) { 87 | const handler = this.handlers[type].handler; 88 | state = handler(state, payload, action); 89 | } 90 | 91 | return state; 92 | }; 93 | 94 | mixin = fn => Object.assign(this, fn(this)); 95 | pipe = fn => fn(this); 96 | } 97 | -------------------------------------------------------------------------------- /src/state/CombinedReducer.ts: -------------------------------------------------------------------------------- 1 | import { combineReducers } from "redux"; 2 | 3 | import { StandardAction } from "../action"; 4 | import { didentity, identity2 } from "./helpers"; 5 | import { BaseReducerBuilder, isReducer } from "./BaseReducer"; 6 | import { R } from "./reducer.h"; 7 | 8 | export class CombinedReducer extends BaseReducerBuilder> { 9 | stores: any; 10 | constructor(storesToParse: T) { 11 | super({} as any); 12 | 13 | const parent = { getPath: this.getPath.bind(this) }; 14 | const stores = {}; 15 | const reducersMap = {}; 16 | this.stores = stores as any; 17 | Object.keys(storesToParse).forEach(el => { 18 | let storeCandidate = storesToParse[el]; 19 | 20 | if (storeCandidate && (storeCandidate as StandardAction).getType) { 21 | // store candidate is action with default value so we transform it to reducer 22 | storeCandidate = storeCandidate as StandardAction; 23 | storeCandidate = new BaseReducerBuilder(storeCandidate.defaultValue).on( 24 | storeCandidate, 25 | identity2 26 | ); 27 | } else if (typeof storeCandidate === "function") { 28 | // store candidate is regular reducer so we just wrap it 29 | const tmpReducer = new BaseReducerBuilder(null); 30 | tmpReducer.reducer = storeCandidate; 31 | storeCandidate = tmpReducer; 32 | } 33 | 34 | stores[el] = storeCandidate as BaseReducerBuilder; 35 | stores[el].setPath(el); 36 | stores[el].parent = parent; 37 | reducersMap[el] = stores[el].reducer; 38 | }); 39 | 40 | const nestedReducer = combineReducers(reducersMap); 41 | const plainReducer = this.reducer; 42 | this.reducer = (state, action) => { 43 | //@ts-ignore 44 | return plainReducer(nestedReducer(state, action), action); 45 | }; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/state/helpers.ts: -------------------------------------------------------------------------------- 1 | export const identity = (d: T, ..._: any[]): T => d; 2 | export const didentity = (defaultV: T) => (d: T = defaultV, ..._: any[]): T => d; 3 | 4 | export const identity2 = (_, d: T): T => d; 5 | -------------------------------------------------------------------------------- /src/state/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./BaseReducer"; 2 | export * from "./CombinedReducer"; 3 | export * from "./helpers"; 4 | export * from "./reducer.h"; 5 | -------------------------------------------------------------------------------- /src/state/reducer.h.ts: -------------------------------------------------------------------------------- 1 | import { StandardAction } from "../action"; 2 | 3 | export interface IReducerBuilder { 4 | stores: WrappedValues; 5 | select(fn: (state: T, props?: P) => R): (root: any, props) => R; 6 | select(rootState: RootState): T; 7 | getState(): T; 8 | on(event: StandardAction, handler: (state: T, payload: E) => T): IReducerBuilder; 9 | reset(event: StandardAction): IReducerBuilder; 10 | mixin(fn: (A: IReducerBuilder) => R): IReducerBuilder & R; 11 | pipe(fn: (A: IReducerBuilder) => R): R; 12 | } 13 | 14 | export type Unpacked = T extends IReducerBuilder 15 | ? U 16 | : T extends StandardAction ? P : T extends (...args: any[]) => infer R ? R : T; 17 | 18 | export type R = { [P in keyof T]: Unpacked }; 19 | 20 | export type WrappedValues = { [P in keyof T]: IReducerBuilder }; 21 | -------------------------------------------------------------------------------- /test/restate.test.ts: -------------------------------------------------------------------------------- 1 | import { createState, createAction, build } from "../src"; 2 | 3 | describe("restate", () => { 4 | let a; 5 | let b; 6 | let c; 7 | let d; 8 | let rootReducer; 9 | let toggle; 10 | let testState = { c: { a: "aa", b: false } }; 11 | beforeEach(() => { 12 | toggle = createAction("toggle"); 13 | a = createState("a"); 14 | b = createState(true); 15 | c = createState({ a, b }); 16 | d = createState({ c }); 17 | rootReducer = d.reducer; 18 | }); 19 | it("works basic", () => { 20 | let toggle = build.mutator(true)("toggle"); 21 | let a = createState("a"); 22 | expect(() => createState()).toThrowError(Error); 23 | expect(a.reducer()).toBe("a"); 24 | let b = createState({ a, toggle }); 25 | 26 | expect(b.reducer()).toEqual({ a: "a", toggle: true }); 27 | }); 28 | it("selectors work ok", () => { 29 | expect(a.select(testState)).toEqual("aa"); 30 | expect(b.select(testState)).toEqual(false); 31 | expect(c.select(testState)).toEqual(testState.c); 32 | expect(d.mapState()(testState)).toEqual(testState); 33 | }); 34 | 35 | it("works ok with reducer", () => { 36 | expect(rootReducer({}, {})).toEqual({ c: { a: "a", b: true } }); 37 | }); 38 | 39 | it("works ok with reducer and actions", () => { 40 | b.on(toggle, (_, p) => { 41 | return p; 42 | }); 43 | const state = rootReducer({}, toggle(false)); 44 | expect(b.select(state)).toEqual(false); 45 | const state2 = rootReducer(state, toggle(false)); 46 | expect(b.select(state2)).toEqual(false); 47 | }); 48 | it("works with nested objects", () => { 49 | c = createState({ f: { d: { a: "q" } }, foo: "qwer" }); 50 | const reducer = c.reducer; 51 | expect(reducer()).toEqual({ f: { d: { a: "q" } }, foo: "qwer" }); 52 | }); 53 | it("handles errors", () => { 54 | expect(() => createState.on(undefined)).toThrow(); 55 | expect(() => createState.on(null, () => {})).toThrow(); 56 | }); 57 | 58 | it("works with subpath", () => { 59 | a = createState("a"); 60 | b = createState(true); 61 | c = createState({ a, b }); 62 | c.setPath("name"); 63 | const reducer = c.reducer; 64 | expect(a.select({ name: { a: "a" } })).toBe("a"); 65 | }); 66 | }); 67 | -------------------------------------------------------------------------------- /test/store.test.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { createStore } from "redux"; 3 | import { createState, createAction, StandardAction, createApi } from "../src"; 4 | import Render from "react-test-renderer"; 5 | let mockedData; 6 | let changedKeys; 7 | beforeAll(() => { 8 | mockedData = { 9 | ui: { a: { b: 5 } }, 10 | users: { password: { hash: "", data: "" }, name: "" }, 11 | ke: { a: 5 }, 12 | d: 6 13 | }; 14 | 15 | changedKeys = ["ui.a", "users"]; 16 | }); 17 | describe("restate", () => { 18 | it("works with use dispatch", () => { 19 | const state = createState(0); 20 | const action = createAction("a"); 21 | const resetAct = createAction("reset"); 22 | 23 | state.on(action, () => 5).reset(resetAct); 24 | const store = createStore(state.reducer); 25 | action(0); 26 | expect(store.getState()).toBe(0); 27 | state.use(store.dispatch); 28 | action(0); 29 | expect(store.getState()).toBe(5); 30 | resetAct(); 31 | expect(store.getState()).toBe(0); 32 | }); 33 | 34 | it("should work with plain reducers", () => { 35 | const st2 = createState(0); 36 | const st1 = createState("a"); 37 | 38 | const reducer = (state = "qwer", action) => state; 39 | const storeWithReducer = createState({ 40 | nested: reducer 41 | }); 42 | const composed = createState({ 43 | st1, 44 | st2, 45 | reducerKey: storeWithReducer 46 | }); 47 | expect(composed.reducer({}, null)).toEqual({ 48 | reducerKey: { nested: "qwer" }, 49 | st1: "a", 50 | st2: 0 51 | }); 52 | expect(storeWithReducer.stores.nested.getPath()).toEqual(["reducerKey", "nested"]); 53 | }); 54 | it("should work with null reducer", () => { 55 | const state = createState(null); 56 | 57 | expect(state.reducer()).toEqual(null); 58 | expect(state.reducer(null, {})).toEqual(null); 59 | expect(state.reducer({}, {})).toEqual({}); 60 | }); 61 | it("should work with get state", () => { 62 | const state = createState(1); 63 | const d = jest.fn(); 64 | const gt = jest.fn().mockImplementation(el => 2); 65 | state.use(d, gt); 66 | 67 | const s = state.getState(); 68 | expect(gt).toBeCalled(); 69 | expect(s).toBe(2); 70 | }); 71 | 72 | it("should work with createApi", () => { 73 | const state = createState(1); 74 | const d = jest.fn(); 75 | const gt = jest.fn().mockImplementation(el => 2); 76 | const api = createApi(state, { 77 | increment(state, payload: number) { 78 | return state + payload; 79 | } 80 | }); 81 | state.use(d, gt); 82 | 83 | api.increment(5); 84 | const s = state.getState(); 85 | expect(gt).toBeCalled(); 86 | expect(d.mock.calls[0][0].type).toBe(api.increment.getType()); 87 | }); 88 | }); 89 | -------------------------------------------------------------------------------- /tools/gh-pages-publish.ts: -------------------------------------------------------------------------------- 1 | const { cd, exec, echo, touch } = require("shelljs") 2 | const { readFileSync } = require("fs") 3 | const url = require("url") 4 | 5 | let repoUrl 6 | let pkg = JSON.parse(readFileSync("package.json") as any) 7 | if (typeof pkg.repository === "object") { 8 | if (!pkg.repository.hasOwnProperty("url")) { 9 | throw new Error("URL does not exist in repository section") 10 | } 11 | repoUrl = pkg.repository.url 12 | } else { 13 | repoUrl = pkg.repository 14 | } 15 | 16 | let parsedUrl = url.parse(repoUrl) 17 | let repository = (parsedUrl.host || "") + (parsedUrl.path || "") 18 | let ghToken = process.env.GH_TOKEN 19 | 20 | echo("Deploying docs!!!") 21 | cd("docs") 22 | touch(".nojekyll") 23 | exec("git init") 24 | exec("git add .") 25 | exec('git config user.name "Dima Zherebko"') 26 | exec('git config user.email "kraken@live.ru"') 27 | exec('git commit -m "docs(docs): update gh-pages"') 28 | exec( 29 | `git push --force --quiet "https://${ghToken}@${repository}" master:gh-pages` 30 | ) 31 | echo("Docs deployed!!") 32 | -------------------------------------------------------------------------------- /tools/semantic-release-prepare.ts: -------------------------------------------------------------------------------- 1 | const path = require("path") 2 | const { fork } = require("child_process") 3 | const colors = require("colors") 4 | 5 | const { readFileSync, writeFileSync } = require("fs") 6 | const pkg = JSON.parse( 7 | readFileSync(path.resolve(__dirname, "..", "package.json")) 8 | ) 9 | 10 | pkg.scripts.prepush = "npm run test:prod && npm run build" 11 | pkg.scripts.commitmsg = "validate-commit-msg" 12 | 13 | writeFileSync( 14 | path.resolve(__dirname, "..", "package.json"), 15 | JSON.stringify(pkg, null, 2) 16 | ) 17 | 18 | // Call husky to set up the hooks 19 | fork(path.resolve(__dirname, "..", "node_modules", "husky", "bin", "install")) 20 | 21 | console.log() 22 | console.log(colors.green("Done!!")) 23 | console.log() 24 | 25 | if (pkg.repository.url.trim()) { 26 | console.log(colors.cyan("Now run:")) 27 | console.log(colors.cyan(" npm install -g semantic-release-cli")) 28 | console.log(colors.cyan(" semantic-release-cli setup")) 29 | console.log() 30 | console.log( 31 | colors.cyan('Important! Answer NO to "Generate travis.yml" question') 32 | ) 33 | console.log() 34 | console.log( 35 | colors.gray( 36 | 'Note: Make sure "repository.url" in your package.json is correct before' 37 | ) 38 | ) 39 | } else { 40 | console.log( 41 | colors.red( 42 | 'First you need to set the "repository.url" property in package.json' 43 | ) 44 | ) 45 | console.log(colors.cyan("Then run:")) 46 | console.log(colors.cyan(" npm install -g semantic-release-cli")) 47 | console.log(colors.cyan(" semantic-release-cli setup")) 48 | console.log() 49 | console.log( 50 | colors.cyan('Important! Answer NO to "Generate travis.yml" question') 51 | ) 52 | } 53 | 54 | console.log() 55 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "target": "es5", 5 | "module": "commonjs", 6 | "jsx": "react", 7 | "downlevelIteration": true, 8 | "lib": ["es2015", "es2016", "es2017", "dom"], 9 | "sourceMap": true, 10 | "declaration": true, 11 | "allowSyntheticDefaultImports": true, 12 | "experimentalDecorators": true, 13 | "emitDecoratorMetadata": true, 14 | "declarationDir": "dist/types", 15 | "outDir": "dist/lib", 16 | "typeRoots": ["node_modules/@types"] 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "tslint-config-standard", 4 | "tslint-config-prettier" 5 | ] 6 | } --------------------------------------------------------------------------------

) => T; 21 | mixin: (fn: any) => any; 22 | pipe: (fn: any) => any; 23 | } 24 | -------------------------------------------------------------------------------- /dist/types/state/CombinedReducer.d.ts: -------------------------------------------------------------------------------- 1 | import { BaseReducerBuilder } from "./BaseReducer"; 2 | import { R } from "./reducer.h"; 3 | export declare class CombinedReducer extends BaseReducerBuilder> { 6 | stores: any; 7 | constructor(storesToParse: T); 8 | } 9 | -------------------------------------------------------------------------------- /dist/types/state/helpers.d.ts: -------------------------------------------------------------------------------- 1 | export declare const identity: (d: T, ..._: any[]) => T; 2 | export declare const didentity: (defaultV: T) => (d?: T, ..._: any[]) => T; 3 | export declare const identity2: (_: any, d: T) => T; 4 | -------------------------------------------------------------------------------- /dist/types/state/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from "./BaseReducer"; 2 | export * from "./CombinedReducer"; 3 | export * from "./helpers"; 4 | export * from "./reducer.h"; 5 | -------------------------------------------------------------------------------- /dist/types/state/reducer.h.d.ts: -------------------------------------------------------------------------------- 1 | import { StandardAction } from "../action"; 2 | export interface IReducerBuilder { 3 | stores: WrappedValues; 4 | select(fn: (state: T, props?: P) => R): (root: any, props) => R; 5 | select(rootState: RootState): T; 6 | getState(): T; 7 | on(event: StandardAction, handler: (state: T, payload: E) => T): IReducerBuilder; 8 | reset(event: StandardAction): IReducerBuilder; 9 | mixin(fn: (A: IReducerBuilder) => R): IReducerBuilder & R; 10 | pipe(fn: (A: IReducerBuilder) => R): R; 11 | } 12 | export declare type Unpacked = T extends IReducerBuilder ? U : T extends StandardAction ? P : T extends (...args: any[]) => infer R ? R : T; 13 | export declare type R = { 14 | [P in keyof T]: Unpacked; 15 | }; 16 | export declare type WrappedValues = { 17 | [P in keyof T]: IReducerBuilder; 18 | }; 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "okdux", 3 | "version": "3.12.0", 4 | "description": "redux made ok", 5 | "keywords": [], 6 | "main": "dist/cjs/index.js", 7 | "module": "dist/lib/index.js", 8 | "typings": "dist/types/index.d.ts", 9 | "author": "Dima Zherebko ", 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/zhDmitry/okdux.git" 13 | }, 14 | "license": "MIT", 15 | "scripts": { 16 | "lint": "tslint -t codeFrame 'src/**/*.ts' 'test/**/*.ts'", 17 | "prebuild": "rimraf dist", 18 | "build": "tsc --module commonjs --outDir ./dist/cjs && tsc --module es2015 ", 19 | "start": "rollup -c rollup.config.ts -w", 20 | "test": "jest", 21 | "test:watch": "jest --watch", 22 | "test:prod": "npm run lint && npm run test -- --coverage --no-cache", 23 | "deploy-docs": "ts-node tools/gh-pages-publish", 24 | "report-coverage": "cat ./coverage/lcov.info | coveralls", 25 | "commit": "git-cz", 26 | "semantic-release": "semantic-release", 27 | "semantic-release-prepare": "ts-node tools/semantic-release-prepare", 28 | "precommit": "lint-staged", 29 | "bench": "node --experimental-modules --expose-gc bench/bench.js", 30 | "bench2": "matcha ./bench/suite.js" 31 | }, 32 | "lint-staged": { 33 | "{src,test}/**/*.tsx?": [ 34 | "prettier --write --no-semi --single-quote", 35 | "git add" 36 | ] 37 | }, 38 | "config": { 39 | "commitizen": { 40 | "path": "node_modules/cz-conventional-changelog" 41 | }, 42 | "validate-commit-msg": { 43 | "types": "conventional-commit-types", 44 | "helpMessage": "Use \"npm run commit\" instead, we use conventional-changelog format :) (https://github.com/commitizen/cz-cli)" 45 | } 46 | }, 47 | "jest": { 48 | "transform": { 49 | ".(ts|tsx)": "/node_modules/ts-jest/preprocessor.js" 50 | }, 51 | "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$", 52 | "moduleFileExtensions": [ 53 | "ts", 54 | "tsx", 55 | "js" 56 | ], 57 | "coveragePathIgnorePatterns": [ 58 | "/node_modules/", 59 | "/test/" 60 | ], 61 | "coverageThreshold": { 62 | "global": { 63 | "branches": 40, 64 | "functions": 40, 65 | "lines": 40, 66 | "statements": 40 67 | } 68 | }, 69 | "collectCoverage": true 70 | }, 71 | "devDependencies": { 72 | "@types/expect": "^1.20.3", 73 | "@types/jest": "^22.2.3", 74 | "@types/node": "^9.3.0", 75 | "@types/redux": "^3.6.0", 76 | "benchmark": "^2.1.4", 77 | "colors": "^1.1.2", 78 | "commitizen": "^2.9.6", 79 | "coveralls": "^3.0.0", 80 | "cross-env": "^5.0.1", 81 | "cz-conventional-changelog": "^2.0.0", 82 | "immer": "latest", 83 | "immutable": "latest", 84 | "jest": "^24.1.0", 85 | "lint-staged": "^7.0.0", 86 | "lodash": "latest", 87 | "lodash.camelcase": "^4.3.0", 88 | "prettier": "^1.4.4", 89 | "pretty-hrtime": "1.0.3", 90 | "prompt": "^1.0.0", 91 | "proxyequal": "^1.5.2", 92 | "react": "16.3.2", 93 | "react-test-renderer": "^16.3.2", 94 | "redux": "latest", 95 | "redux-mock-store": "^1.5.1", 96 | "replace-in-file": "^3.0.0-beta.2", 97 | "rimraf": "^2.6.1", 98 | "rollup": "^0.57.0", 99 | "rollup-plugin-commonjs": "^9.0.0", 100 | "rollup-plugin-json": "^2.3.0", 101 | "rollup-plugin-node-resolve": "^3.0.0", 102 | "rollup-plugin-sourcemaps": "^0.4.2", 103 | "rollup-plugin-typescript2": "^0.13.0", 104 | "ts-jest": "^22.0.0", 105 | "ts-node": "^6.0.0", 106 | "tslint": "^5.9.1", 107 | "tslint-config-prettier": "^1.1.0", 108 | "tslint-config-standard": "^7.0.0", 109 | "typescript": "^2.8.3", 110 | "validate-commit-msg": "^2.12.2" 111 | }, 112 | "peerDependencies": { 113 | "redux": "*" 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /rfc.md: -------------------------------------------------------------------------------- 1 | async api 2 | 3 | ```tsx 4 | const asyncApiMap = { 5 | async list(ctx, payload) { 6 | const rules = await api.list(); 7 | return actions.addRules({ 8 | list: rules 9 | }); 10 | }, 11 | async create(ctx, payload) { 12 | const res = await api.put(payload); 13 | return actions.addRule(res) 14 | }, 15 | async update(ctx, payload) { 16 | const res = await api.patch(rule); 17 | actions.updateItem(res); 18 | }, 19 | delete(ctx, payload) { 20 | const res = await api.del(rule); 21 | actions.deleteItem(res); 22 | } 23 | }; 24 | 25 | const asyncApiHooks = { 26 | onError(actionType, error) { 27 | notification.error({ message: error.message }); 28 | }, 29 | onSuccess(actionType) { 30 | notification.open({ message: getNotificationText(actionType) }); 31 | }, 32 | onStart(event, args) { 33 | console.log("event, args: ", event, args); 34 | startLoading(event); 35 | }, 36 | onDone(event) { 37 | stopLoading(event); 38 | } 39 | }; 40 | const effects = createAsyncApi(state, asyncApiMap, asyncApiHooks); 41 | ``` 42 | -------------------------------------------------------------------------------- /rollup.config.ts: -------------------------------------------------------------------------------- 1 | import resolve from "rollup-plugin-node-resolve"; 2 | import commonjs from "rollup-plugin-commonjs"; 3 | import sourceMaps from "rollup-plugin-sourcemaps"; 4 | import camelCase from "lodash.camelcase"; 5 | import typescript from "rollup-plugin-typescript2"; 6 | import json from "rollup-plugin-json"; 7 | 8 | const pkg = require("./package.json"); 9 | 10 | const libraryName = "restate"; 11 | 12 | export default { 13 | input: `src/index.ts`, 14 | output: [ 15 | { file: pkg.main, name: camelCase(libraryName), format: "umd" }, 16 | { file: pkg.module, format: "es" } 17 | ], 18 | sourcemap: true, 19 | // Indicate here external modules you don't wanna include in your bundle (i.e.: 'lodash') 20 | external: ["redux", "lodash", "react", "create-subscription", "react-redux"], 21 | watch: { 22 | include: "src/**" 23 | }, 24 | plugins: [ 25 | // Allow json resolution 26 | json(), 27 | // Compile TypeScript files 28 | typescript({ useTsconfigDeclarationDir: true }), 29 | // Allow bundling cjs modules (unlike webpack, rollup doesn't understand cjs) 30 | commonjs(), 31 | // Allow node_modules resolution, so you can use 'external' to control 32 | // which external modules to include in the bundle 33 | // https://github.com/rollup/rollup-plugin-node-resolve#usage 34 | resolve(), 35 | 36 | // Resolve source maps to the original source 37 | sourceMaps() 38 | ] 39 | }; 40 | -------------------------------------------------------------------------------- /src/action/apiFactory.ts: -------------------------------------------------------------------------------- 1 | import { createAction } from "./createAction"; 2 | import { IReducerBuilder } from "../state"; 3 | import { StandardAction } from "./createAction.h"; 4 | 5 | export type EventHandler = (s: S, p: P) => S; 6 | 7 | export type IStateApi = { 8 | [P in keyof T]: T[P] extends EventHandler ? EventHandler : null 9 | }; 10 | export type IApiActions = { 11 | [P in keyof T]: T[P] extends EventHandler 12 | ? StandardAction 13 | : StandardAction 14 | }; 15 | 16 | export function createApi>( 17 | istate: IReducerBuilder, 18 | actionDecl: Model 19 | ): IApiActions & { update: (state: S, payload: Partial) => S }; 20 | 21 | export function createApi(state, actionsDecl) { 22 | const update = createAction(Symbol("update")); 23 | state.on(update, (s, p) => ({ ...state, ...p })); 24 | const actions = { update }; 25 | 26 | for (let actionKey in actionsDecl) { 27 | const handler = actionsDecl[actionKey]; 28 | const act = createAction(Symbol(actionKey)); 29 | state.on(act, handler); 30 | actions[actionKey] = act; 31 | } 32 | return actions; 33 | } 34 | -------------------------------------------------------------------------------- /src/action/createAction.h.ts: -------------------------------------------------------------------------------- 1 | export type FunctionMap = { [M in keyof T]: (...args: any[]) => any }; 2 | export type CallFunctionMap> = { [M in keyof T]: ReturnType }; 3 | 4 | export type StandardActionPayload = { type: string; payload: T }; 5 | export type StandardAction = { 6 | defaultValue?: T; 7 | (payload?: T): StandardActionPayload; 8 | getType(): string; 9 | }; 10 | 11 | export type AsyncActions = { 12 | request: StandardAction; 13 | success: StandardAction; 14 | failure: StandardAction; 15 | }; 16 | -------------------------------------------------------------------------------- /src/action/createAction.ts: -------------------------------------------------------------------------------- 1 | import { StandardAction, FunctionMap, CallFunctionMap } from "./createAction.h"; 2 | 3 | const mutator = (defaultValue: T) => ( 4 | name: string | Symbol = Symbol() 5 | ): StandardAction => { 6 | let dispatch = null; 7 | 8 | const actionRaw = (data = defaultValue) => { 9 | return { type: name, payload: data }; 10 | }; 11 | const action: any = (data = defaultValue) => { 12 | const action = actionRaw(data); 13 | dispatch && dispatch(action); 14 | return action; 15 | }; 16 | const actionMeta = { 17 | getType: () => name, 18 | defaultValue, 19 | setDispatch(d) { 20 | dispatch = d; 21 | }, 22 | getDispatch: () => dispatch, 23 | raw: actionRaw 24 | }; 25 | 26 | return Object.assign(action, actionMeta); 27 | }; 28 | 29 | const createAction = mutator(null); 30 | 31 | function createAsyncAction(name: string) { 32 | return createActions( 33 | { 34 | failure: build.action(), 35 | success: build.action(), 36 | request: build.action() 37 | }, 38 | name + "_" 39 | ); 40 | } 41 | 42 | const build = { 43 | plain: createAction, 44 | action() { 45 | return (name: string) => createAction(name); 46 | }, 47 | mutator: mutator, 48 | async: () => name => { 49 | return createAsyncAction(name); 50 | } 51 | }; 52 | 53 | function createActions>( 54 | actions: T, 55 | prefix: string = "@" 56 | ): CallFunctionMap { 57 | return Object.keys(actions).reduce>( 58 | (acc, el) => { 59 | acc[el] = actions[el](prefix + "/" + el); 60 | return acc; 61 | }, 62 | {} as CallFunctionMap 63 | ); 64 | } 65 | const t = createActions({ 66 | act: build.async() 67 | }); 68 | 69 | const createEffects = createActions; 70 | export { createAction, build, createActions, createEffects }; 71 | -------------------------------------------------------------------------------- /src/action/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./createAction"; 2 | export * from "./createAction.h"; 3 | export * from "./apiFactory"; 4 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | IReducerBuilder, 3 | CombinedReducer, 4 | BaseReducerBuilder, 5 | R, 6 | getRootStateSymbol 7 | } from "./state"; 8 | import { create } from "domain"; 9 | 10 | export function createState(initialState: T): IReducerBuilder> { 11 | if (initialState === undefined) { 12 | throw new Error("initial state cannot be undefined"); 13 | } 14 | let state; 15 | if (initialState && typeof initialState === "object") { 16 | const firstKey = Object.keys(initialState)[0]; 17 | if ( 18 | initialState[firstKey] && 19 | (initialState[firstKey].reducer || 20 | initialState[firstKey].getType || 21 | typeof initialState[firstKey] === "function") 22 | ) { 23 | // @ts-ignore 24 | state = new CombinedReducer(initialState); 25 | } else { 26 | state = new BaseReducerBuilder(initialState); 27 | } 28 | } else { 29 | state = new BaseReducerBuilder(initialState); 30 | } 31 | 32 | state.use = (d, gs) => use(state, d, gs); 33 | state.createStore = fn => { 34 | const store = fn(state.reducer, state); 35 | if (!store) { 36 | throw new Error("you must return store from createStore method"); 37 | } 38 | use(state, store.dispatch); 39 | }; 40 | 41 | return state; 42 | } 43 | 44 | function forEachStore(stores, fn) { 45 | for (let item in stores) { 46 | if (stores[item]) { 47 | fn(stores[item]); 48 | if (stores[item].stores) { 49 | forEachStore(stores[item].stores, fn); 50 | } 51 | } 52 | } 53 | } 54 | 55 | function forEachAction(store, fn) { 56 | for (let item in store.handlers) { 57 | fn(store.handlers[item]); 58 | } 59 | for (let item of Object.getOwnPropertySymbols(store.handlers)) { 60 | fn(store.handlers[item]); 61 | } 62 | } 63 | 64 | function use(store, dispatch, getState = null) { 65 | const setDispatch = data => { 66 | data.action.setDispatch(dispatch); 67 | }; 68 | forEachAction(store, setDispatch); 69 | store[getRootStateSymbol] = getState; 70 | forEachStore(store.stores, el => { 71 | el[getRootStateSymbol] = getState; 72 | forEachAction(el, setDispatch); 73 | }); 74 | } 75 | 76 | export * from "./action"; 77 | export * from "./state/reducer.h"; 78 | -------------------------------------------------------------------------------- /src/state/BaseReducer.ts: -------------------------------------------------------------------------------- 1 | import { StandardAction, StandardActionPayload } from "../action"; 2 | import { identity } from "./helpers"; 3 | 4 | export const reducerSymbol = Symbol(); 5 | export const getRootStateSymbol = Symbol(); 6 | 7 | function get(object, keys) { 8 | keys = Array.isArray(keys) ? keys : keys.split("."); 9 | object = object[keys[0]]; 10 | if (object && keys.length > 1) { 11 | return get(object, keys.slice(1)); 12 | } 13 | return object; 14 | } 15 | 16 | export function isReducer(reducer) { 17 | return reducer && reducer[reducerSymbol]; 18 | } 19 | export class BaseReducerBuilder { 20 | public handlers = {}; 21 | parent; 22 | path; 23 | [getRootStateSymbol]: () => any = null; 24 | private [reducerSymbol] = {}; 25 | constructor(public initialState: T) { 26 | if (typeof initialState === "undefined") { 27 | throw new Error("initial state should not be undefined"); 28 | } 29 | this.reducer = this.reducer.bind(this); 30 | } 31 | 32 | setPath(path) { 33 | this.path = path; 34 | } 35 | 36 | getPath() { 37 | if (this.parent) { 38 | return this.parent.getPath().concat(this.path); 39 | } else { 40 | return this.path ? [this.path] : []; 41 | } 42 | } 43 | 44 | getState = () => { 45 | if (!this[getRootStateSymbol]) { 46 | throw new Error("please set getState to root reducer"); 47 | } 48 | return this.select(this[getRootStateSymbol]()); 49 | }; 50 | 51 | on = (action: StandardAction, handler) => { 52 | if (action === undefined || action === null || !action.getType) { 53 | throw new Error("action should be an action type, got " + action); 54 | } 55 | this.handlers[action.getType()] = { 56 | handler, 57 | action 58 | }; 59 | return this; 60 | }; 61 | 62 | select = (rs: R) => { 63 | if (typeof rs === "function") { 64 | return this.mapState(rs as any); 65 | } 66 | 67 | const path = this.getPath(); 68 | return path.length ? get(rs, this.getPath()) : rs; 69 | }; 70 | 71 | mapState = (fn = identity) => { 72 | return (state, props) => fn(this.select(state), props, state); 73 | }; 74 | 75 | reset = action => { 76 | this.on(action, state => this.initialState); 77 | return this; 78 | }; 79 | 80 | public reducer =