saga-toolkit 2.0.4 → 2.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.babelrc ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "presets": [
3
+ [
4
+ "@babel/preset-env",
5
+ {
6
+ "targets": {
7
+ "node": "current"
8
+ }
9
+ }
10
+ ]
11
+ ]
12
+ }
package/example/.env ADDED
@@ -0,0 +1 @@
1
+ SKIP_PREFLIGHT_CHECK=true
@@ -17,17 +17,24 @@
17
17
  "react-scripts": "4.0.3",
18
18
  "redux": "^4.1.1",
19
19
  "redux-saga": "^1.1.3",
20
- "redux-toolkit": "^1.1.2",
21
20
  "saga-toolkit": "file:..",
22
21
  "web-vitals": "^1.0.1"
23
22
  }
24
23
  },
25
24
  "..": {
26
- "version": "1.2.3",
25
+ "version": "2.0.4",
27
26
  "license": "ISC",
28
- "dependencies": {
27
+ "devDependencies": {
28
+ "@babel/cli": "^7.16.8",
29
+ "@babel/core": "^7.16.12",
30
+ "@babel/node": "^7.16.8",
31
+ "@babel/preset-env": "^7.16.11",
32
+ "@reduxjs/toolkit": "^1.7.2",
33
+ "babel-jest": "^27.4.6",
34
+ "jest": "^27.4.7",
35
+ "redux": "^4.1.2",
29
36
  "redux-saga": "^1.1.3",
30
- "redux-toolkit": "^1.1.2"
37
+ "redux-saga-test-plan": "^4.0.4"
31
38
  }
32
39
  },
33
40
  "node_modules/@babel/code-frame": {
@@ -8136,14 +8143,6 @@
8136
8143
  "readable-stream": "^2.3.6"
8137
8144
  }
8138
8145
  },
8139
- "node_modules/flux-standard-action": {
8140
- "version": "0.6.1",
8141
- "resolved": "https://registry.npmjs.org/flux-standard-action/-/flux-standard-action-0.6.1.tgz",
8142
- "integrity": "sha1-bzQhG5SDTqHDzDD056+tPQ+/caI=",
8143
- "dependencies": {
8144
- "lodash.isplainobject": "^3.2.0"
8145
- }
8146
- },
8147
8146
  "node_modules/follow-redirects": {
8148
8147
  "version": "1.13.2",
8149
8148
  "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.2.tgz",
@@ -9325,14 +9324,6 @@
9325
9324
  "node": ">= 0.4"
9326
9325
  }
9327
9326
  },
9328
- "node_modules/invariant": {
9329
- "version": "2.2.4",
9330
- "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
9331
- "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
9332
- "dependencies": {
9333
- "loose-envify": "^1.0.0"
9334
- }
9335
- },
9336
9327
  "node_modules/ip": {
9337
9328
  "version": "1.1.5",
9338
9329
  "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
@@ -10898,50 +10889,16 @@
10898
10889
  "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
10899
10890
  "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
10900
10891
  },
10901
- "node_modules/lodash._basefor": {
10902
- "version": "3.0.3",
10903
- "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz",
10904
- "integrity": "sha1-dVC06SGO8J+tJDQ7YSAhx5tMIMI="
10905
- },
10906
10892
  "node_modules/lodash._reinterpolate": {
10907
10893
  "version": "3.0.0",
10908
10894
  "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
10909
10895
  "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0="
10910
10896
  },
10911
- "node_modules/lodash.isarguments": {
10912
- "version": "3.1.0",
10913
- "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
10914
- "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo="
10915
- },
10916
- "node_modules/lodash.isarray": {
10917
- "version": "3.0.4",
10918
- "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
10919
- "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U="
10920
- },
10921
10897
  "node_modules/lodash.isequalwith": {
10922
10898
  "version": "4.4.0",
10923
10899
  "resolved": "https://registry.npmjs.org/lodash.isequalwith/-/lodash.isequalwith-4.4.0.tgz",
10924
10900
  "integrity": "sha1-Jmcm3dUo+FTyH06pigZWBuD7xrA="
10925
10901
  },
10926
- "node_modules/lodash.isplainobject": {
10927
- "version": "3.2.0",
10928
- "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz",
10929
- "integrity": "sha1-moI4rhayAEMpYM1zRlEtASP79MU=",
10930
- "dependencies": {
10931
- "lodash._basefor": "^3.0.0",
10932
- "lodash.isarguments": "^3.0.0",
10933
- "lodash.keysin": "^3.0.0"
10934
- }
10935
- },
10936
- "node_modules/lodash.keysin": {
10937
- "version": "3.0.8",
10938
- "resolved": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz",
10939
- "integrity": "sha1-IsRJPrvtsUJ5YqVLRFssinZ/tH8=",
10940
- "dependencies": {
10941
- "lodash.isarguments": "^3.0.0",
10942
- "lodash.isarray": "^3.0.0"
10943
- }
10944
- },
10945
10902
  "node_modules/lodash.memoize": {
10946
10903
  "version": "4.1.2",
10947
10904
  "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@@ -14661,35 +14618,6 @@
14661
14618
  "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz",
14662
14619
  "integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw=="
14663
14620
  },
14664
- "node_modules/redux-toolkit": {
14665
- "version": "1.1.2",
14666
- "resolved": "https://registry.npmjs.org/redux-toolkit/-/redux-toolkit-1.1.2.tgz",
14667
- "integrity": "sha1-99yID+oTtIBChLT+AHLvDnpVUv8=",
14668
- "dependencies": {
14669
- "debug": "^2.2.0",
14670
- "flux-standard-action": "^0.6.0",
14671
- "invariant": "^2.1.1",
14672
- "lodash": "^3.10.1"
14673
- }
14674
- },
14675
- "node_modules/redux-toolkit/node_modules/debug": {
14676
- "version": "2.6.9",
14677
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
14678
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
14679
- "dependencies": {
14680
- "ms": "2.0.0"
14681
- }
14682
- },
14683
- "node_modules/redux-toolkit/node_modules/lodash": {
14684
- "version": "3.10.1",
14685
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
14686
- "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y="
14687
- },
14688
- "node_modules/redux-toolkit/node_modules/ms": {
14689
- "version": "2.0.0",
14690
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
14691
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
14692
- },
14693
14621
  "node_modules/regenerate": {
14694
14622
  "version": "1.4.2",
14695
14623
  "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -25225,14 +25153,6 @@
25225
25153
  "readable-stream": "^2.3.6"
25226
25154
  }
25227
25155
  },
25228
- "flux-standard-action": {
25229
- "version": "0.6.1",
25230
- "resolved": "https://registry.npmjs.org/flux-standard-action/-/flux-standard-action-0.6.1.tgz",
25231
- "integrity": "sha1-bzQhG5SDTqHDzDD056+tPQ+/caI=",
25232
- "requires": {
25233
- "lodash.isplainobject": "^3.2.0"
25234
- }
25235
- },
25236
25156
  "follow-redirects": {
25237
25157
  "version": "1.13.2",
25238
25158
  "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.2.tgz",
@@ -26147,14 +26067,6 @@
26147
26067
  "side-channel": "^1.0.4"
26148
26068
  }
26149
26069
  },
26150
- "invariant": {
26151
- "version": "2.2.4",
26152
- "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
26153
- "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
26154
- "requires": {
26155
- "loose-envify": "^1.0.0"
26156
- }
26157
- },
26158
26070
  "ip": {
26159
26071
  "version": "1.1.5",
26160
26072
  "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
@@ -27332,50 +27244,16 @@
27332
27244
  "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
27333
27245
  "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
27334
27246
  },
27335
- "lodash._basefor": {
27336
- "version": "3.0.3",
27337
- "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz",
27338
- "integrity": "sha1-dVC06SGO8J+tJDQ7YSAhx5tMIMI="
27339
- },
27340
27247
  "lodash._reinterpolate": {
27341
27248
  "version": "3.0.0",
27342
27249
  "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
27343
27250
  "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0="
27344
27251
  },
27345
- "lodash.isarguments": {
27346
- "version": "3.1.0",
27347
- "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
27348
- "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo="
27349
- },
27350
- "lodash.isarray": {
27351
- "version": "3.0.4",
27352
- "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
27353
- "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U="
27354
- },
27355
27252
  "lodash.isequalwith": {
27356
27253
  "version": "4.4.0",
27357
27254
  "resolved": "https://registry.npmjs.org/lodash.isequalwith/-/lodash.isequalwith-4.4.0.tgz",
27358
27255
  "integrity": "sha1-Jmcm3dUo+FTyH06pigZWBuD7xrA="
27359
27256
  },
27360
- "lodash.isplainobject": {
27361
- "version": "3.2.0",
27362
- "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz",
27363
- "integrity": "sha1-moI4rhayAEMpYM1zRlEtASP79MU=",
27364
- "requires": {
27365
- "lodash._basefor": "^3.0.0",
27366
- "lodash.isarguments": "^3.0.0",
27367
- "lodash.keysin": "^3.0.0"
27368
- }
27369
- },
27370
- "lodash.keysin": {
27371
- "version": "3.0.8",
27372
- "resolved": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz",
27373
- "integrity": "sha1-IsRJPrvtsUJ5YqVLRFssinZ/tH8=",
27374
- "requires": {
27375
- "lodash.isarguments": "^3.0.0",
27376
- "lodash.isarray": "^3.0.0"
27377
- }
27378
- },
27379
27257
  "lodash.memoize": {
27380
27258
  "version": "4.1.2",
27381
27259
  "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@@ -30286,37 +30164,6 @@
30286
30164
  "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz",
30287
30165
  "integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw=="
30288
30166
  },
30289
- "redux-toolkit": {
30290
- "version": "1.1.2",
30291
- "resolved": "https://registry.npmjs.org/redux-toolkit/-/redux-toolkit-1.1.2.tgz",
30292
- "integrity": "sha1-99yID+oTtIBChLT+AHLvDnpVUv8=",
30293
- "requires": {
30294
- "debug": "^2.2.0",
30295
- "flux-standard-action": "^0.6.0",
30296
- "invariant": "^2.1.1",
30297
- "lodash": "^3.10.1"
30298
- },
30299
- "dependencies": {
30300
- "debug": {
30301
- "version": "2.6.9",
30302
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
30303
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
30304
- "requires": {
30305
- "ms": "2.0.0"
30306
- }
30307
- },
30308
- "lodash": {
30309
- "version": "3.10.1",
30310
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
30311
- "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y="
30312
- },
30313
- "ms": {
30314
- "version": "2.0.0",
30315
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
30316
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
30317
- }
30318
- }
30319
- },
30320
30167
  "regenerate": {
30321
30168
  "version": "1.4.2",
30322
30169
  "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -30846,8 +30693,16 @@
30846
30693
  "saga-toolkit": {
30847
30694
  "version": "file:..",
30848
30695
  "requires": {
30696
+ "@babel/cli": "^7.16.8",
30697
+ "@babel/core": "^7.16.12",
30698
+ "@babel/node": "^7.16.8",
30699
+ "@babel/preset-env": "^7.16.11",
30700
+ "@reduxjs/toolkit": "^1.7.2",
30701
+ "babel-jest": "^27.4.6",
30702
+ "jest": "^27.4.7",
30703
+ "redux": "^4.1.2",
30849
30704
  "redux-saga": "^1.1.3",
30850
- "redux-toolkit": "^1.1.2"
30705
+ "redux-saga-test-plan": "^4.0.4"
30851
30706
  }
30852
30707
  },
30853
30708
  "sane": {
@@ -1,9 +1,10 @@
1
+ import { unwrapResult } from '@reduxjs/toolkit'
1
2
  import { useApp, useAppStart } from './hooks'
2
3
  import logo from './logo.svg';
3
4
  import './App.css';
4
5
 
5
6
  function App() {
6
- const { started, click, fetchThings } = useApp()
7
+ const { started, click, fetchThings, fetchThingsDebounce } = useApp()
7
8
 
8
9
  const handleClick = async () => {
9
10
  try {
@@ -23,6 +24,15 @@ function App() {
23
24
  }
24
25
  }
25
26
 
27
+ const handleFetchThingsDebounce = async () => {
28
+ try {
29
+ const result = unwrapResult(await fetchThingsDebounce(false))
30
+ console.log('fetchThingsDebounce SUCCESS', result)
31
+ } catch (error) {
32
+ console.log('fetchThingsDebounce ERROR', error)
33
+ }
34
+ }
35
+
26
36
  useAppStart()
27
37
 
28
38
  return (
@@ -34,6 +44,7 @@ function App() {
34
44
  </p>
35
45
  <button onClick={handleClick}>click</button>
36
46
  <button onClick={handleFetchThings}>fetchThings</button>
47
+ <button onClick={handleFetchThingsDebounce}>fetchThingsDebounce</button>
37
48
  <a
38
49
  className="App-link"
39
50
  href="https://reactjs.org"
@@ -1,5 +1,5 @@
1
1
  import { createAsyncThunk, unwrapResult } from '@reduxjs/toolkit'
2
- import { put, takeEvery } from '@redux-saga/core/effects'
2
+ import { put, take, fork, takeEvery, cancel } from '@redux-saga/core/effects'
3
3
  import createDeferred from '@redux-saga/deferred'
4
4
 
5
5
  const requests = {}
@@ -49,8 +49,8 @@ const cleanup = requestId => {
49
49
  delete requests[requestId]
50
50
  }
51
51
 
52
- function* getRequest(action) {
53
- const { requestId } = action.meta
52
+ function* getRequest(requestId) {
53
+ // const { requestId } = action.meta
54
54
  const request = requests[requestId]
55
55
 
56
56
  if (!request) {
@@ -64,12 +64,13 @@ function* getRequest(action) {
64
64
 
65
65
  const wrap = saga => function* (action, ...rest) {
66
66
  const { requestId } = action.meta
67
- const request = yield getRequest(action)
67
+ const request = yield getRequest(requestId)
68
68
  const deferred = request.deferred
69
69
 
70
70
  try {
71
71
  deferred.resolve(yield saga(action, ...rest))
72
72
  } catch (error) {
73
+ console.log(error)
73
74
  deferred.reject(error)
74
75
  } finally {
75
76
  cleanup(requestId)
@@ -82,16 +83,22 @@ export function takeEveryAsync(pattern, saga, ...args) {
82
83
 
83
84
  export function takeLatestAsync(pattern, saga, ...args) {
84
85
  let deferred
86
+ const tasks = {}
85
87
 
86
88
  function* wrapper(action, ...rest) {
87
89
  if (deferred) {
88
90
  const lastRequestId = yield deferred.promise
91
+ const request = yield getRequest(lastRequestId)
92
+
93
+ request.abort()
94
+
95
+ const task = yield tasks[lastRequestId].promise
89
96
 
90
- requests[lastRequestId].abort()
97
+ yield cancel(task)
91
98
  }
92
99
 
93
100
  deferred = createDeferred()
94
- const { requestId } = yield getRequest(action)
101
+ const { requestId } = yield getRequest(action.meta.requestId)
95
102
 
96
103
  deferred.resolve(requestId)
97
104
 
@@ -100,6 +107,15 @@ export function takeLatestAsync(pattern, saga, ...args) {
100
107
  deferred = null
101
108
  }
102
109
 
110
+ const takeEvery = (patternOrChannel, saga, ...args) => fork(function* () {
111
+ while (true) {
112
+ const action = yield take(patternOrChannel)
113
+ const { requestId } = action.meta
114
+ tasks[requestId] = createDeferred()
115
+ tasks[requestId].resolve(yield fork(saga, ...args.concat(action)))
116
+ }
117
+ })
118
+
103
119
  return takeEvery(pattern, wrapper, ...args)
104
120
  }
105
121
 
@@ -110,7 +126,7 @@ export function takeAggregateAsync(pattern, saga, ...args) {
110
126
  const { requestId } = action.meta
111
127
 
112
128
  if (deferred) {
113
- const request = yield getRequest(action)
129
+ const request = yield getRequest(requestId)
114
130
  const { resolve, reject } = request.deferred
115
131
  const { promise } = yield deferred.promise
116
132
 
@@ -120,7 +136,7 @@ export function takeAggregateAsync(pattern, saga, ...args) {
120
136
  .catch(() => { })
121
137
  } else {
122
138
  deferred = createDeferred()
123
- const request = yield getRequest(action)
139
+ const request = yield getRequest(requestId)
124
140
  const { promise } = request.deferred
125
141
 
126
142
  yield wrap(saga)(action, ...rest)
@@ -1,4 +1,4 @@
1
- import { call, delay, put, select, takeEvery } from 'redux-saga/effects'
1
+ import { call, cancelled, delay, put, select, takeEvery } from 'redux-saga/effects'
2
2
  import { LOCATION_CHANGE } from 'connected-react-router'
3
3
  import {
4
4
  takeEveryAsync,
@@ -59,6 +59,23 @@ function* fetchThings({ meta }) {
59
59
  return result
60
60
  }
61
61
 
62
+ function* fetchThingsDebounce({ meta }) {
63
+ try {
64
+ yield delay(1000)
65
+
66
+ console.log('STILL RUNNING', meta.requestId)
67
+ } finally {
68
+ if (yield cancelled()) {
69
+ console.log('CANCELLED', meta.requestId)
70
+ }
71
+ }
72
+
73
+ // const result = yield call(() => hyperSuperApi(true))
74
+
75
+ // return result
76
+ return 'shite'
77
+ }
78
+
62
79
  function* click() {
63
80
  try {
64
81
  yield putAsync(actions.fetchThings(false))
@@ -71,6 +88,7 @@ export default [
71
88
  takeEveryAsync(actions.start.pending.toString(), appStart),
72
89
  // takeAggregateAsync(actions.fetchThings.pending.toString(), fetchThings),
73
90
  takeEveryAsync(actions.fetchThings.pending.toString(), fetchThings),
91
+ takeLatestAsync(actions.fetchThingsDebounce.pending.toString(), fetchThingsDebounce),
74
92
  takeEvery(actions.click.type.toString(), click),
75
93
  takeEvery(LOCATION_CHANGE, locationChange),
76
94
  ]
@@ -10,6 +10,7 @@ const initialState = {
10
10
 
11
11
  export const start = createSagaAction(`${name}/start`)
12
12
  export const fetchThings = createSagaAction(`${name}/fetchThings`)
13
+ export const fetchThingsDebounce = createSagaAction(`${name}/fetchThingsDebounce`)
13
14
  export const click = createAction(`${name}/click`)
14
15
 
15
16
  const slice = createSlice({
@@ -15,7 +15,7 @@ const createStore = ({ history }) => {
15
15
  sagaMiddleware,
16
16
  ],
17
17
  // middleware: getDefaultMiddleware => getDefaultMiddleware().concat(sagaMiddleware),
18
- devTools: process.env.NODE_ENV !== 'production',
18
+ devTools: true,
19
19
  })
20
20
 
21
21
  sagaMiddleware.run(function* () {
package/index.js CHANGED
@@ -1,11 +1,13 @@
1
1
  "use strict";
2
2
 
3
- exports.__esModule = true;
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createSagaAction = void 0;
7
+ exports.putAsync = putAsync;
8
+ exports.takeAggregateAsync = takeAggregateAsync;
4
9
  exports.takeEveryAsync = takeEveryAsync;
5
10
  exports.takeLatestAsync = takeLatestAsync;
6
- exports.takeAggregateAsync = takeAggregateAsync;
7
- exports.putAsync = putAsync;
8
- exports.createSagaAction = void 0;
9
11
 
10
12
  var _toolkit = require("@reduxjs/toolkit");
11
13
 
@@ -62,10 +64,8 @@ const cleanup = requestId => {
62
64
  delete requests[requestId];
63
65
  };
64
66
 
65
- function* getRequest(action) {
66
- const {
67
- requestId
68
- } = action.meta;
67
+ function* getRequest(requestId) {
68
+ // const { requestId } = action.meta
69
69
  const request = requests[requestId];
70
70
 
71
71
  if (!request) {
@@ -83,12 +83,13 @@ const wrap = saga => function* (action, ...rest) {
83
83
  const {
84
84
  requestId
85
85
  } = action.meta;
86
- const request = yield getRequest(action);
86
+ const request = yield getRequest(requestId);
87
87
  const deferred = request.deferred;
88
88
 
89
89
  try {
90
90
  deferred.resolve(yield saga(action, ...rest));
91
91
  } catch (error) {
92
+ console.log(error);
92
93
  deferred.reject(error);
93
94
  } finally {
94
95
  cleanup(requestId);
@@ -100,24 +101,39 @@ function takeEveryAsync(pattern, saga, ...args) {
100
101
  }
101
102
 
102
103
  function takeLatestAsync(pattern, saga, ...args) {
104
+ const tasks = {};
103
105
  let deferred;
104
106
 
105
107
  function* wrapper(action, ...rest) {
106
108
  if (deferred) {
107
109
  const lastRequestId = yield deferred.promise;
108
- requests[lastRequestId].abort();
110
+ const request = yield getRequest(lastRequestId);
111
+ request.abort();
112
+ const task = yield tasks[lastRequestId].promise;
113
+ yield (0, _effects.cancel)(task);
109
114
  }
110
115
 
111
116
  deferred = (0, _deferred.default)();
112
117
  const {
113
118
  requestId
114
- } = yield getRequest(action);
119
+ } = yield getRequest(action.meta.requestId);
115
120
  deferred.resolve(requestId);
116
121
  yield wrap(saga)(action, ...rest);
117
122
  deferred = null;
118
123
  }
119
124
 
120
- return (0, _effects.takeEvery)(pattern, wrapper, ...args);
125
+ const takeEvery = (patternOrChannel, saga, ...args) => (0, _effects.fork)(function* () {
126
+ while (true) {
127
+ const action = yield (0, _effects.take)(patternOrChannel);
128
+ const {
129
+ requestId
130
+ } = action.meta;
131
+ tasks[requestId] = (0, _deferred.default)();
132
+ tasks[requestId].resolve(yield (0, _effects.fork)(saga, ...args.concat(action)));
133
+ }
134
+ });
135
+
136
+ return takeEvery(pattern, wrapper, ...args);
121
137
  }
122
138
 
123
139
  function takeAggregateAsync(pattern, saga, ...args) {
@@ -129,7 +145,7 @@ function takeAggregateAsync(pattern, saga, ...args) {
129
145
  } = action.meta;
130
146
 
131
147
  if (deferred) {
132
- const request = yield getRequest(action);
148
+ const request = yield getRequest(requestId);
133
149
  const {
134
150
  resolve,
135
151
  reject
@@ -140,7 +156,7 @@ function takeAggregateAsync(pattern, saga, ...args) {
140
156
  promise.then(resolve, reject).finally(() => cleanup(requestId)).catch(() => {});
141
157
  } else {
142
158
  deferred = (0, _deferred.default)();
143
- const request = yield getRequest(action);
159
+ const request = yield getRequest(requestId);
144
160
  const {
145
161
  promise
146
162
  } = request.deferred;
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "saga-toolkit",
3
- "version": "2.0.4",
3
+ "version": "2.0.5",
4
4
  "description": "An extension for redux-toolkit that allows sagas to resolve async thunk actions.",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
+ "build": "./node_modules/.bin/babel sagaToolkit.js --out-file index.js",
7
8
  "test": "echo \"Error: no test specified\" && exit 1"
8
9
  },
9
10
  "repository": {
@@ -24,8 +25,10 @@
24
25
  "url": "https://github.com/janoist1/saga-toolkit/issues"
25
26
  },
26
27
  "homepage": "https://github.com/janoist1/saga-toolkit#readme",
27
- "dependencies": {
28
- "@reduxjs/toolkit": "^1.6.1",
29
- "redux-saga": "^1.1.3"
28
+ "devDependencies": {
29
+ "@babel/cli": "^7.16.8",
30
+ "@babel/core": "^7.16.12",
31
+ "@babel/node": "^7.16.8",
32
+ "@babel/preset-env": "^7.16.11"
30
33
  }
31
34
  }
package/sagaToolkit.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createAsyncThunk, unwrapResult } from '@reduxjs/toolkit'
2
- import { put, takeEvery } from '@redux-saga/core/effects'
2
+ import { put, take, fork, takeEvery, cancel } from '@redux-saga/core/effects'
3
3
  import createDeferred from '@redux-saga/deferred'
4
4
 
5
5
  const requests = {}
@@ -49,8 +49,8 @@ const cleanup = requestId => {
49
49
  delete requests[requestId]
50
50
  }
51
51
 
52
- function* getRequest(action) {
53
- const { requestId } = action.meta
52
+ function* getRequest(requestId) {
53
+ // const { requestId } = action.meta
54
54
  const request = requests[requestId]
55
55
 
56
56
  if (!request) {
@@ -64,12 +64,13 @@ function* getRequest(action) {
64
64
 
65
65
  const wrap = saga => function* (action, ...rest) {
66
66
  const { requestId } = action.meta
67
- const request = yield getRequest(action)
67
+ const request = yield getRequest(requestId)
68
68
  const deferred = request.deferred
69
69
 
70
70
  try {
71
71
  deferred.resolve(yield saga(action, ...rest))
72
72
  } catch (error) {
73
+ console.log(error)
73
74
  deferred.reject(error)
74
75
  } finally {
75
76
  cleanup(requestId)
@@ -81,17 +82,23 @@ export function takeEveryAsync(pattern, saga, ...args) {
81
82
  }
82
83
 
83
84
  export function takeLatestAsync(pattern, saga, ...args) {
85
+ const tasks = {}
84
86
  let deferred
85
87
 
86
88
  function* wrapper(action, ...rest) {
87
89
  if (deferred) {
88
90
  const lastRequestId = yield deferred.promise
91
+ const request = yield getRequest(lastRequestId)
92
+
93
+ request.abort()
94
+
95
+ const task = yield tasks[lastRequestId].promise
89
96
 
90
- requests[lastRequestId].abort()
97
+ yield cancel(task)
91
98
  }
92
99
 
93
100
  deferred = createDeferred()
94
- const { requestId } = yield getRequest(action)
101
+ const { requestId } = yield getRequest(action.meta.requestId)
95
102
 
96
103
  deferred.resolve(requestId)
97
104
 
@@ -100,6 +107,15 @@ export function takeLatestAsync(pattern, saga, ...args) {
100
107
  deferred = null
101
108
  }
102
109
 
110
+ const takeEvery = (patternOrChannel, saga, ...args) => fork(function* () {
111
+ while (true) {
112
+ const action = yield take(patternOrChannel)
113
+ const { requestId } = action.meta
114
+ tasks[requestId] = createDeferred()
115
+ tasks[requestId].resolve(yield fork(saga, ...args.concat(action)))
116
+ }
117
+ })
118
+
103
119
  return takeEvery(pattern, wrapper, ...args)
104
120
  }
105
121
 
@@ -110,7 +126,7 @@ export function takeAggregateAsync(pattern, saga, ...args) {
110
126
  const { requestId } = action.meta
111
127
 
112
128
  if (deferred) {
113
- const request = yield getRequest(action)
129
+ const request = yield getRequest(requestId)
114
130
  const { resolve, reject } = request.deferred
115
131
  const { promise } = yield deferred.promise
116
132
 
@@ -120,7 +136,7 @@ export function takeAggregateAsync(pattern, saga, ...args) {
120
136
  .catch(() => { })
121
137
  } else {
122
138
  deferred = createDeferred()
123
- const request = yield getRequest(action)
139
+ const request = yield getRequest(requestId)
124
140
  const { promise } = request.deferred
125
141
 
126
142
  yield wrap(saga)(action, ...rest)
@@ -0,0 +1,24 @@
1
+ import { combineReducers } from 'redux'
2
+ import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit'
3
+ import createSagaMiddleware from 'redux-saga'
4
+ import { all } from 'redux-saga/effects'
5
+
6
+ export default ({ initialState, reducers, sagas }) => {
7
+ const sagaMiddleware = createSagaMiddleware()
8
+ const store = configureStore({
9
+ reducer: combineReducers(reducers),
10
+ middleware: [...getDefaultMiddleware(), sagaMiddleware],
11
+ devTools: false,
12
+ })
13
+ // const store = createStore(
14
+ // combineReducers(reducers),
15
+ // initialState,
16
+ // applyMiddleware(sagaMiddleware)
17
+ // )
18
+
19
+ sagaMiddleware.run(function* () {
20
+ yield all(sagas)
21
+ })
22
+
23
+ return store
24
+ }
@@ -0,0 +1,95 @@
1
+ import { put } from 'redux-saga/effects'
2
+ import { createSlice } from '@reduxjs/toolkit'
3
+ import { expectSaga, testSaga } from 'redux-saga-test-plan'
4
+ import createStore from './createStore'
5
+ import { createSagaAction, takeEveryAsync } from '../sagaToolkit'
6
+
7
+ const initialState = {
8
+ test: null,
9
+ testAsync: null,
10
+ error: null,
11
+ }
12
+
13
+ const testAsyncAction = createSagaAction('testSlice/testAsyncAction')
14
+
15
+ const slice = createSlice({
16
+ name: 'testSlice',
17
+ initialState,
18
+ reducers: {
19
+ testAction: (state, action) => ({ test: action.payload }),
20
+ },
21
+ extraReducers: {
22
+ [testAsyncAction.pending]: (state, action) => ({
23
+ ...state,
24
+ test: action.payload,
25
+ }),
26
+ [testAsyncAction.resolved]: (state, action) => ({
27
+ ...state,
28
+ testAsync: 'action.meta.args',
29
+ }),
30
+ [testAsyncAction.rejected]: (state, action) => ({
31
+ ...state,
32
+ test: action.payload,
33
+ }),
34
+ },
35
+ })
36
+
37
+ const { testAction } = slice.actions
38
+
39
+ function* saga() {
40
+ yield put(testAction('testing'))
41
+
42
+ return 'resolved value'
43
+ }
44
+
45
+ test('testing sync', () => {
46
+ const reducers = { slice: slice.reducer }
47
+ const sagas = [takeEveryAsync(testAsyncAction.pending, saga)]
48
+ const store = createStore({ initialState, reducers, sagas })
49
+
50
+ store.dispatch(testAction('testing'))
51
+
52
+ const state = store.getState()
53
+
54
+ expect(state).toEqual({
55
+ slice: { test: 'testing' },
56
+ })
57
+ })
58
+
59
+ test('testing async', () => {
60
+ return expectSaga(saga)
61
+ .withReducer(slice.reducer)
62
+ .hasFinalState({
63
+ test: 'testing',
64
+ testAsync: 'testing async',
65
+ })
66
+ .run()
67
+ })
68
+
69
+ test('testing async 2', () => {
70
+ testSaga(function *() {
71
+ yield takeEveryAsync(testAsyncAction.pending, saga)
72
+ }, 40, 2)
73
+ // advance saga with `next()`
74
+ .next()
75
+
76
+ // assert that the saga yields `take` with `'HELLO'` as type
77
+ // .take('HELLO')
78
+
79
+ // pass back in a value to a saga after it yields
80
+ // .next(action)
81
+
82
+ // assert that the saga yields `put` with the expected action
83
+ .put(testAction('testing'))
84
+
85
+ .next()
86
+
87
+ // assert that the saga yields a `call` to `identity` with
88
+ // the `action` argument
89
+ // .call(identity, action)
90
+
91
+ .next()
92
+
93
+ // assert that the saga is finished
94
+ .isDone();
95
+ })
@@ -1,8 +0,0 @@
1
- import { render, screen } from '@testing-library/react';
2
- import App from './App';
3
-
4
- test('renders learn react link', () => {
5
- render(<App />);
6
- const linkElement = screen.getByText(/learn react/i);
7
- expect(linkElement).toBeInTheDocument();
8
- });