riducers 1.0.0
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/README.md +34 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +169 -0
- package/dist/index.js.map +1 -0
- package/esm/index.d.ts +15 -0
- package/esm/index.js +166 -0
- package/esm/index.js.map +1 -0
- package/package.json +35 -0
- package/src/index.ts +186 -0
package/README.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Dynamic Reducers for id based entities
|
|
2
|
+
|
|
3
|
+
Plug and play reducers to frontend entity based RESTful APIs.
|
|
4
|
+
|
|
5
|
+
These reducers come with insert, delete, replace, clear, and sort action types. Intercept AJAX API calls and dispatch appropriate events to maintain the entity states in redux automagically.
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
### Initializing the reducers
|
|
10
|
+
|
|
11
|
+
```TypeScript
|
|
12
|
+
import { configureStore } from '@reduxjs/toolkit'
|
|
13
|
+
import { reducerBuilder } from 'riducers'
|
|
14
|
+
import { combineReducers } from 'redux'
|
|
15
|
+
|
|
16
|
+
const reducer = {
|
|
17
|
+
users: reducerBuilder('user', {stateType: 'list'}),
|
|
18
|
+
auth: reducerBuilder('auth', {}),
|
|
19
|
+
ui: {
|
|
20
|
+
api: reducerBuilder('ui/api', { stateType: 'map'}),
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const store = configureStore({ reducer })
|
|
25
|
+
|
|
26
|
+
store.dispatch('user/insert', {payload: [{id: 1, name: 'John'}]})
|
|
27
|
+
store.dispatch('user/delete', {payload: [{id: 1}]})
|
|
28
|
+
store.dispatch('user/replace', {payload: [{id: 1, name: 'Foo'}, {id: 2, name: 'Bar'}]})
|
|
29
|
+
store.dispatch('user/sort', {})
|
|
30
|
+
store.dispatch('user/clear', {})
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
See the Jest tests (test/main.test.ts) for more action types and uses.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
interface ModelObj {
|
|
2
|
+
[key: string]: any;
|
|
3
|
+
}
|
|
4
|
+
type SortFn = (a: ModelObj, b: ModelObj) => number;
|
|
5
|
+
interface ReducerOpts {
|
|
6
|
+
stateType?: 'list' | 'map' | 'static';
|
|
7
|
+
sort?: SortFn;
|
|
8
|
+
keyName?: string;
|
|
9
|
+
}
|
|
10
|
+
declare function buildReducers(key: string, opts?: ReducerOpts): (state: any, action: {
|
|
11
|
+
type: string;
|
|
12
|
+
payload?: any;
|
|
13
|
+
sort?: ((a: ModelObj, b: ModelObj) => number) | undefined;
|
|
14
|
+
}) => any;
|
|
15
|
+
export { buildReducers };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildReducers = void 0;
|
|
4
|
+
const keySort = (key) => (a, b) => {
|
|
5
|
+
if (typeof a[key] === 'number' && typeof b[key] === 'number')
|
|
6
|
+
return a[key] - b[key];
|
|
7
|
+
else if (typeof a[key] === 'string' && typeof b[key] === 'string')
|
|
8
|
+
return a[key].localeCompare(b[key]);
|
|
9
|
+
return 0;
|
|
10
|
+
};
|
|
11
|
+
const mapInsertReducer = (state, action) => {
|
|
12
|
+
if (!state)
|
|
13
|
+
state = {};
|
|
14
|
+
let resp = Array.isArray(action.payload) ? action.payload : [action.payload];
|
|
15
|
+
state = Object.assign({}, state);
|
|
16
|
+
for (let i in resp) {
|
|
17
|
+
state[resp[i][action.keyName]] = Object.assign({}, resp[i]);
|
|
18
|
+
}
|
|
19
|
+
return state;
|
|
20
|
+
};
|
|
21
|
+
const mapDeleteReducer = (state, action) => {
|
|
22
|
+
if (!state)
|
|
23
|
+
state = {};
|
|
24
|
+
let resp = Array.isArray(action.payload) ? action.payload : [action.payload];
|
|
25
|
+
state = Object.assign({}, state);
|
|
26
|
+
for (let i in resp) {
|
|
27
|
+
delete state[resp[i][action.keyName]];
|
|
28
|
+
}
|
|
29
|
+
return state;
|
|
30
|
+
};
|
|
31
|
+
const mapReplaceReducer = (state, action) => {
|
|
32
|
+
state = {};
|
|
33
|
+
let resp = Array.isArray(action.payload) ? action.payload : [action.payload];
|
|
34
|
+
for (let i in resp) {
|
|
35
|
+
state[resp[i][action.keyName]] = Object.assign({}, resp[i]);
|
|
36
|
+
}
|
|
37
|
+
return state;
|
|
38
|
+
};
|
|
39
|
+
const mapClearReducer = () => {
|
|
40
|
+
return {};
|
|
41
|
+
};
|
|
42
|
+
const listInsertReducer = (state, action) => {
|
|
43
|
+
if (!state)
|
|
44
|
+
state = [];
|
|
45
|
+
let resp = Array.isArray(action.payload) ? action.payload : [action.payload];
|
|
46
|
+
state = [...state];
|
|
47
|
+
let respMap = resp.map((r) => r[action.keyName]);
|
|
48
|
+
let stateMap = state.map((r) => r[action.keyName]);
|
|
49
|
+
let toInsert = respMap.filter((id) => stateMap.indexOf(id) < 0);
|
|
50
|
+
let toReplace = respMap.filter((id) => stateMap.indexOf(id) >= 0);
|
|
51
|
+
for (let i in toReplace) {
|
|
52
|
+
let stateIndex = stateMap.indexOf(toReplace[i]);
|
|
53
|
+
let respIndex = respMap.indexOf(toReplace[i]);
|
|
54
|
+
state[stateIndex] = Object.assign({}, resp[respIndex]);
|
|
55
|
+
}
|
|
56
|
+
if (toInsert.length > 0) {
|
|
57
|
+
let inserts = toInsert.map((id) => resp[respMap.indexOf(id)]);
|
|
58
|
+
state = [...state, ...inserts];
|
|
59
|
+
}
|
|
60
|
+
if (action === null || action === void 0 ? void 0 : action.sort)
|
|
61
|
+
state.sort(action === null || action === void 0 ? void 0 : action.sort);
|
|
62
|
+
return state;
|
|
63
|
+
};
|
|
64
|
+
const listSortReducer = (state, action) => {
|
|
65
|
+
if (!state)
|
|
66
|
+
state = [];
|
|
67
|
+
state = [...state];
|
|
68
|
+
let sort = action && action.sort ? action.sort : keySort(action.keyName);
|
|
69
|
+
state.sort(sort);
|
|
70
|
+
return state;
|
|
71
|
+
};
|
|
72
|
+
const listDeleteReducer = (state, action) => {
|
|
73
|
+
if (!state)
|
|
74
|
+
state = [];
|
|
75
|
+
let resp = Array.isArray(action.payload) ? action.payload : [action.payload];
|
|
76
|
+
let stateMap = state.map((s) => s[action.keyName]);
|
|
77
|
+
for (let i in resp) {
|
|
78
|
+
let index = stateMap.indexOf(resp[i][action.keyName]);
|
|
79
|
+
if (index >= 0)
|
|
80
|
+
state.splice(index, 1);
|
|
81
|
+
}
|
|
82
|
+
return state;
|
|
83
|
+
};
|
|
84
|
+
const listClearReducer = () => {
|
|
85
|
+
return [];
|
|
86
|
+
};
|
|
87
|
+
const listReplaceReducer = (state, action) => {
|
|
88
|
+
let resp = Array.isArray(action.payload) ? action.payload : [action.payload];
|
|
89
|
+
resp = resp.map((r) => Object.assign({}, r));
|
|
90
|
+
if (action === null || action === void 0 ? void 0 : action.sort)
|
|
91
|
+
resp.sort(action === null || action === void 0 ? void 0 : action.sort);
|
|
92
|
+
return resp;
|
|
93
|
+
};
|
|
94
|
+
const objInsertReducer = (state, action) => {
|
|
95
|
+
return action.payload;
|
|
96
|
+
};
|
|
97
|
+
const objReplaceReducer = (state, action) => {
|
|
98
|
+
return action.payload;
|
|
99
|
+
};
|
|
100
|
+
const objDeleteReducer = () => {
|
|
101
|
+
return null;
|
|
102
|
+
};
|
|
103
|
+
const objClearReducer = () => {
|
|
104
|
+
return null;
|
|
105
|
+
};
|
|
106
|
+
const OPS = ['insert', 'replace', 'delete', 'clear', 'sort'];
|
|
107
|
+
function buildReducers(key, opts) {
|
|
108
|
+
return (state, action) => {
|
|
109
|
+
let isList = opts && (opts === null || opts === void 0 ? void 0 : opts.stateType) === 'list';
|
|
110
|
+
let isMap = opts && (opts === null || opts === void 0 ? void 0 : opts.stateType) === 'map';
|
|
111
|
+
let rx = new RegExp(`^${key}/([^\/]+)$`);
|
|
112
|
+
let m = action.type.match(rx);
|
|
113
|
+
if (!m)
|
|
114
|
+
return state || (isList ? [] : isMap ? {} : null);
|
|
115
|
+
let op = m[1];
|
|
116
|
+
let payload = action.payload;
|
|
117
|
+
let keyName = (opts && (opts === null || opts === void 0 ? void 0 : opts.keyName)) || "id";
|
|
118
|
+
if (isMap && !OPS.includes(op)) {
|
|
119
|
+
if (payload && !Array.isArray(payload)) {
|
|
120
|
+
payload[keyName] = op;
|
|
121
|
+
op = "insert";
|
|
122
|
+
}
|
|
123
|
+
if (!payload) {
|
|
124
|
+
payload = {};
|
|
125
|
+
payload[keyName] = op;
|
|
126
|
+
op = "delete";
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
let sort = action.sort || (opts && (opts === null || opts === void 0 ? void 0 : opts.sort));
|
|
130
|
+
if (op === "insert") {
|
|
131
|
+
if (isList && payload)
|
|
132
|
+
return listInsertReducer(state, { payload, sort, keyName });
|
|
133
|
+
else if (isMap && payload)
|
|
134
|
+
return mapInsertReducer(state, { payload, keyName });
|
|
135
|
+
return objInsertReducer(state, { payload });
|
|
136
|
+
}
|
|
137
|
+
else if (op === "replace") {
|
|
138
|
+
if (isList)
|
|
139
|
+
return listReplaceReducer(state, { payload, sort, keyName });
|
|
140
|
+
else if (isMap)
|
|
141
|
+
return mapReplaceReducer(state, { payload, keyName });
|
|
142
|
+
return objReplaceReducer(state, { payload });
|
|
143
|
+
}
|
|
144
|
+
else if (op === "delete") {
|
|
145
|
+
if (isList)
|
|
146
|
+
return listDeleteReducer(state, { payload, keyName });
|
|
147
|
+
else if (isMap)
|
|
148
|
+
return mapDeleteReducer(state, { payload, keyName });
|
|
149
|
+
return objDeleteReducer();
|
|
150
|
+
}
|
|
151
|
+
else if (op === "clear") {
|
|
152
|
+
if (isList)
|
|
153
|
+
return listClearReducer();
|
|
154
|
+
else if (isMap)
|
|
155
|
+
return mapClearReducer();
|
|
156
|
+
return objClearReducer();
|
|
157
|
+
}
|
|
158
|
+
else if (op === "sort") {
|
|
159
|
+
if (isList)
|
|
160
|
+
return listSortReducer(state, { sort, keyName });
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
console.error(`unknown op (${op}) in action type: ${action.type}. Op should be one of: insert, delete, replace, clear, or sort.`);
|
|
164
|
+
}
|
|
165
|
+
return state || (isList ? [] : isMap ? {} : null);
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
exports.buildReducers = buildReducers;
|
|
169
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/esm/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
interface ModelObj {
|
|
2
|
+
[key: string]: any;
|
|
3
|
+
}
|
|
4
|
+
type SortFn = (a: ModelObj, b: ModelObj) => number;
|
|
5
|
+
interface ReducerOpts {
|
|
6
|
+
stateType?: 'list' | 'map' | 'static';
|
|
7
|
+
sort?: SortFn;
|
|
8
|
+
keyName?: string;
|
|
9
|
+
}
|
|
10
|
+
declare function buildReducers(key: string, opts?: ReducerOpts): (state: any, action: {
|
|
11
|
+
type: string;
|
|
12
|
+
payload?: any;
|
|
13
|
+
sort?: ((a: ModelObj, b: ModelObj) => number) | undefined;
|
|
14
|
+
}) => any;
|
|
15
|
+
export { buildReducers };
|
package/esm/index.js
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
const keySort = (key) => (a, b) => {
|
|
2
|
+
if (typeof a[key] === 'number' && typeof b[key] === 'number')
|
|
3
|
+
return a[key] - b[key];
|
|
4
|
+
else if (typeof a[key] === 'string' && typeof b[key] === 'string')
|
|
5
|
+
return a[key].localeCompare(b[key]);
|
|
6
|
+
return 0;
|
|
7
|
+
};
|
|
8
|
+
const mapInsertReducer = (state, action) => {
|
|
9
|
+
if (!state)
|
|
10
|
+
state = {};
|
|
11
|
+
let resp = Array.isArray(action.payload) ? action.payload : [action.payload];
|
|
12
|
+
state = Object.assign({}, state);
|
|
13
|
+
for (let i in resp) {
|
|
14
|
+
state[resp[i][action.keyName]] = Object.assign({}, resp[i]);
|
|
15
|
+
}
|
|
16
|
+
return state;
|
|
17
|
+
};
|
|
18
|
+
const mapDeleteReducer = (state, action) => {
|
|
19
|
+
if (!state)
|
|
20
|
+
state = {};
|
|
21
|
+
let resp = Array.isArray(action.payload) ? action.payload : [action.payload];
|
|
22
|
+
state = Object.assign({}, state);
|
|
23
|
+
for (let i in resp) {
|
|
24
|
+
delete state[resp[i][action.keyName]];
|
|
25
|
+
}
|
|
26
|
+
return state;
|
|
27
|
+
};
|
|
28
|
+
const mapReplaceReducer = (state, action) => {
|
|
29
|
+
state = {};
|
|
30
|
+
let resp = Array.isArray(action.payload) ? action.payload : [action.payload];
|
|
31
|
+
for (let i in resp) {
|
|
32
|
+
state[resp[i][action.keyName]] = Object.assign({}, resp[i]);
|
|
33
|
+
}
|
|
34
|
+
return state;
|
|
35
|
+
};
|
|
36
|
+
const mapClearReducer = () => {
|
|
37
|
+
return {};
|
|
38
|
+
};
|
|
39
|
+
const listInsertReducer = (state, action) => {
|
|
40
|
+
if (!state)
|
|
41
|
+
state = [];
|
|
42
|
+
let resp = Array.isArray(action.payload) ? action.payload : [action.payload];
|
|
43
|
+
state = [...state];
|
|
44
|
+
let respMap = resp.map((r) => r[action.keyName]);
|
|
45
|
+
let stateMap = state.map((r) => r[action.keyName]);
|
|
46
|
+
let toInsert = respMap.filter((id) => stateMap.indexOf(id) < 0);
|
|
47
|
+
let toReplace = respMap.filter((id) => stateMap.indexOf(id) >= 0);
|
|
48
|
+
for (let i in toReplace) {
|
|
49
|
+
let stateIndex = stateMap.indexOf(toReplace[i]);
|
|
50
|
+
let respIndex = respMap.indexOf(toReplace[i]);
|
|
51
|
+
state[stateIndex] = Object.assign({}, resp[respIndex]);
|
|
52
|
+
}
|
|
53
|
+
if (toInsert.length > 0) {
|
|
54
|
+
let inserts = toInsert.map((id) => resp[respMap.indexOf(id)]);
|
|
55
|
+
state = [...state, ...inserts];
|
|
56
|
+
}
|
|
57
|
+
if (action?.sort)
|
|
58
|
+
state.sort(action?.sort);
|
|
59
|
+
return state;
|
|
60
|
+
};
|
|
61
|
+
const listSortReducer = (state, action) => {
|
|
62
|
+
if (!state)
|
|
63
|
+
state = [];
|
|
64
|
+
state = [...state];
|
|
65
|
+
let sort = action && action.sort ? action.sort : keySort(action.keyName);
|
|
66
|
+
state.sort(sort);
|
|
67
|
+
return state;
|
|
68
|
+
};
|
|
69
|
+
const listDeleteReducer = (state, action) => {
|
|
70
|
+
if (!state)
|
|
71
|
+
state = [];
|
|
72
|
+
let resp = Array.isArray(action.payload) ? action.payload : [action.payload];
|
|
73
|
+
let stateMap = state.map((s) => s[action.keyName]);
|
|
74
|
+
for (let i in resp) {
|
|
75
|
+
let index = stateMap.indexOf(resp[i][action.keyName]);
|
|
76
|
+
if (index >= 0)
|
|
77
|
+
state.splice(index, 1);
|
|
78
|
+
}
|
|
79
|
+
return state;
|
|
80
|
+
};
|
|
81
|
+
const listClearReducer = () => {
|
|
82
|
+
return [];
|
|
83
|
+
};
|
|
84
|
+
const listReplaceReducer = (state, action) => {
|
|
85
|
+
let resp = Array.isArray(action.payload) ? action.payload : [action.payload];
|
|
86
|
+
resp = resp.map((r) => Object.assign({}, r));
|
|
87
|
+
if (action?.sort)
|
|
88
|
+
resp.sort(action?.sort);
|
|
89
|
+
return resp;
|
|
90
|
+
};
|
|
91
|
+
const objInsertReducer = (state, action) => {
|
|
92
|
+
return action.payload;
|
|
93
|
+
};
|
|
94
|
+
const objReplaceReducer = (state, action) => {
|
|
95
|
+
return action.payload;
|
|
96
|
+
};
|
|
97
|
+
const objDeleteReducer = () => {
|
|
98
|
+
return null;
|
|
99
|
+
};
|
|
100
|
+
const objClearReducer = () => {
|
|
101
|
+
return null;
|
|
102
|
+
};
|
|
103
|
+
const OPS = ['insert', 'replace', 'delete', 'clear', 'sort'];
|
|
104
|
+
function buildReducers(key, opts) {
|
|
105
|
+
return (state, action) => {
|
|
106
|
+
let isList = opts && opts?.stateType === 'list';
|
|
107
|
+
let isMap = opts && opts?.stateType === 'map';
|
|
108
|
+
let rx = new RegExp(`^${key}/([^\/]+)$`);
|
|
109
|
+
let m = action.type.match(rx);
|
|
110
|
+
if (!m)
|
|
111
|
+
return state || (isList ? [] : isMap ? {} : null);
|
|
112
|
+
let op = m[1];
|
|
113
|
+
let payload = action.payload;
|
|
114
|
+
let keyName = (opts && opts?.keyName) || "id";
|
|
115
|
+
if (isMap && !OPS.includes(op)) {
|
|
116
|
+
if (payload && !Array.isArray(payload)) {
|
|
117
|
+
payload[keyName] = op;
|
|
118
|
+
op = "insert";
|
|
119
|
+
}
|
|
120
|
+
if (!payload) {
|
|
121
|
+
payload = {};
|
|
122
|
+
payload[keyName] = op;
|
|
123
|
+
op = "delete";
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
let sort = action.sort || (opts && opts?.sort);
|
|
127
|
+
if (op === "insert") {
|
|
128
|
+
if (isList && payload)
|
|
129
|
+
return listInsertReducer(state, { payload, sort, keyName });
|
|
130
|
+
else if (isMap && payload)
|
|
131
|
+
return mapInsertReducer(state, { payload, keyName });
|
|
132
|
+
return objInsertReducer(state, { payload });
|
|
133
|
+
}
|
|
134
|
+
else if (op === "replace") {
|
|
135
|
+
if (isList)
|
|
136
|
+
return listReplaceReducer(state, { payload, sort, keyName });
|
|
137
|
+
else if (isMap)
|
|
138
|
+
return mapReplaceReducer(state, { payload, keyName });
|
|
139
|
+
return objReplaceReducer(state, { payload });
|
|
140
|
+
}
|
|
141
|
+
else if (op === "delete") {
|
|
142
|
+
if (isList)
|
|
143
|
+
return listDeleteReducer(state, { payload, keyName });
|
|
144
|
+
else if (isMap)
|
|
145
|
+
return mapDeleteReducer(state, { payload, keyName });
|
|
146
|
+
return objDeleteReducer();
|
|
147
|
+
}
|
|
148
|
+
else if (op === "clear") {
|
|
149
|
+
if (isList)
|
|
150
|
+
return listClearReducer();
|
|
151
|
+
else if (isMap)
|
|
152
|
+
return mapClearReducer();
|
|
153
|
+
return objClearReducer();
|
|
154
|
+
}
|
|
155
|
+
else if (op === "sort") {
|
|
156
|
+
if (isList)
|
|
157
|
+
return listSortReducer(state, { sort, keyName });
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
console.error(`unknown op (${op}) in action type: ${action.type}. Op should be one of: insert, delete, replace, clear, or sort.`);
|
|
161
|
+
}
|
|
162
|
+
return state || (isList ? [] : isMap ? {} : null);
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
export { buildReducers };
|
|
166
|
+
//# sourceMappingURL=index.js.map
|
package/esm/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "riducers",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Dynamic reducers with insert, delete, replace, clear, and sort actions on 'id' based list of objects",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "esm/index.js",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"esm",
|
|
10
|
+
"src"
|
|
11
|
+
],
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/sleeksky-dev/riducers.git"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"clean": "rimraf dist esm",
|
|
18
|
+
"prebuild": "npm run clean",
|
|
19
|
+
"preversion": "npm run build",
|
|
20
|
+
"postversion": "git push --follow-tags",
|
|
21
|
+
"test": "jest",
|
|
22
|
+
"build:esm": "tsc --target es2022 --outDir esm",
|
|
23
|
+
"build:cjs": "tsc --target es2018 --module commonjs --outDir dist",
|
|
24
|
+
"build": "npm run build:esm && npm run build:cjs"
|
|
25
|
+
},
|
|
26
|
+
"author": "Yusuf Bhabhrawala",
|
|
27
|
+
"license": "ISC",
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/jest": "^29.2.0",
|
|
30
|
+
"jest": "^29.2.1",
|
|
31
|
+
"rimraf": "^3.0.2",
|
|
32
|
+
"ts-jest": "^29.0.3",
|
|
33
|
+
"typescript": "^4.8.4"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
|
|
2
|
+
type Id = number | string;
|
|
3
|
+
|
|
4
|
+
interface ModelObj {
|
|
5
|
+
[key: string]: any;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
type SortFn = (a: ModelObj, b: ModelObj) => number;
|
|
9
|
+
|
|
10
|
+
interface ListAction {
|
|
11
|
+
payload: ModelObj | ModelObj[];
|
|
12
|
+
sort?: SortFn;
|
|
13
|
+
keyName: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface ListSortAction {
|
|
17
|
+
sort?: SortFn;
|
|
18
|
+
keyName: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const keySort = (key: string) => (a: ModelObj, b: ModelObj) => {
|
|
22
|
+
if (typeof a[key] === 'number' && typeof b[key] === 'number') return a[key] - b[key];
|
|
23
|
+
else if (typeof a[key] === 'string' && typeof b[key] === 'string') return a[key].localeCompare(b[key]);
|
|
24
|
+
return 0;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const mapInsertReducer = (state: ModelObj, action: ListAction) => {
|
|
28
|
+
if (!state) state = {};
|
|
29
|
+
let resp: ModelObj[] = Array.isArray(action.payload) ? action.payload : [action.payload];
|
|
30
|
+
state = Object.assign({}, state);
|
|
31
|
+
for (let i in resp) {
|
|
32
|
+
state[resp[i][action.keyName]] = Object.assign({}, resp[i]);
|
|
33
|
+
}
|
|
34
|
+
return state;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const mapDeleteReducer = (state: ModelObj, action: ListAction) => {
|
|
38
|
+
if (!state) state = {};
|
|
39
|
+
let resp: ModelObj[] = Array.isArray(action.payload) ? action.payload : [action.payload];
|
|
40
|
+
state = Object.assign({}, state);
|
|
41
|
+
for (let i in resp) {
|
|
42
|
+
delete state[resp[i][action.keyName]];
|
|
43
|
+
}
|
|
44
|
+
return state;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const mapReplaceReducer = (state: ModelObj, action: ListAction) => {
|
|
48
|
+
state = {};
|
|
49
|
+
let resp: ModelObj[] = Array.isArray(action.payload) ? action.payload : [action.payload];
|
|
50
|
+
for (let i in resp) {
|
|
51
|
+
state[resp[i][action.keyName]] = Object.assign({}, resp[i]);
|
|
52
|
+
}
|
|
53
|
+
return state;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const mapClearReducer = () => {
|
|
57
|
+
return {};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const listInsertReducer = (state: ModelObj[], action: ListAction) => {
|
|
61
|
+
if (!state) state = [];
|
|
62
|
+
let resp: ModelObj[] = Array.isArray(action.payload) ? action.payload : [action.payload];
|
|
63
|
+
|
|
64
|
+
state = [...state];
|
|
65
|
+
let respMap: Id[] = resp.map((r: any) => r[action.keyName]);
|
|
66
|
+
let stateMap: Id[] = state.map((r: any) => r[action.keyName]);
|
|
67
|
+
let toInsert: Id[] = respMap.filter((id : number | string) => stateMap.indexOf(id) < 0);
|
|
68
|
+
let toReplace: Id[] = respMap.filter((id: number | string) => stateMap.indexOf(id) >= 0);
|
|
69
|
+
for (let i in toReplace) {
|
|
70
|
+
let stateIndex = stateMap.indexOf(toReplace[i]);
|
|
71
|
+
let respIndex = respMap.indexOf(toReplace[i]);
|
|
72
|
+
state[stateIndex] = Object.assign({}, resp[respIndex]);
|
|
73
|
+
}
|
|
74
|
+
if (toInsert.length > 0) {
|
|
75
|
+
let inserts = toInsert.map((id: number | string) => resp[respMap.indexOf(id)]);
|
|
76
|
+
state = [...state, ...inserts];
|
|
77
|
+
}
|
|
78
|
+
if (action?.sort) state.sort(action?.sort);
|
|
79
|
+
return state;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const listSortReducer = (state: ModelObj[], action: ListSortAction) => {
|
|
83
|
+
if (!state) state = [];
|
|
84
|
+
state = [...state];
|
|
85
|
+
let sort = action && action.sort ? action.sort : keySort(action.keyName);
|
|
86
|
+
state.sort(sort);
|
|
87
|
+
return state;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const listDeleteReducer = (state: ModelObj[], action: ListAction) => {
|
|
91
|
+
if (!state) state = [];
|
|
92
|
+
let resp: ModelObj[] = Array.isArray(action.payload) ? action.payload : [action.payload];
|
|
93
|
+
|
|
94
|
+
let stateMap: Id[] = state.map((s: any) => s[action.keyName]);
|
|
95
|
+
for (let i in resp) {
|
|
96
|
+
let index = stateMap.indexOf(resp[i][action.keyName]);
|
|
97
|
+
if (index >= 0) state.splice(index, 1);
|
|
98
|
+
}
|
|
99
|
+
return state;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const listClearReducer = () => {
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const listReplaceReducer = (state: ModelObj[], action: ListAction) => {
|
|
107
|
+
let resp: ModelObj[] = Array.isArray(action.payload) ? action.payload : [action.payload];
|
|
108
|
+
resp = resp.map((r: any) => Object.assign({}, r));
|
|
109
|
+
if (action?.sort) resp.sort(action?.sort);
|
|
110
|
+
return resp;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const objInsertReducer = (state: any, action: { payload: any }) => {
|
|
114
|
+
return action.payload
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const objReplaceReducer = (state: any, action: { payload: any }) => {
|
|
118
|
+
return action.payload
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const objDeleteReducer = () => {
|
|
122
|
+
return null
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const objClearReducer = () => {
|
|
126
|
+
return null
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
interface ReducerOpts {
|
|
130
|
+
stateType?: 'list' | 'map' | 'static';
|
|
131
|
+
sort?: SortFn;
|
|
132
|
+
keyName?: string;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const OPS = ['insert', 'replace', 'delete', 'clear', 'sort'];
|
|
136
|
+
function reducerBuilder(key: string, opts?: ReducerOpts) {
|
|
137
|
+
return (state: any, action: { type: string; payload?: any; sort?: (a: ModelObj, b: ModelObj) => number }) => {
|
|
138
|
+
let isList = opts && opts?.stateType === 'list';
|
|
139
|
+
let isMap = opts && opts?.stateType === 'map';
|
|
140
|
+
let rx = new RegExp(`^${key}/([^\/]+)$`);
|
|
141
|
+
let m = action.type.match(rx);
|
|
142
|
+
if (!m) return state || (isList ? [] : isMap ? {} : null);
|
|
143
|
+
|
|
144
|
+
let op = m[1];
|
|
145
|
+
let payload = action.payload;
|
|
146
|
+
let keyName = (opts && opts?.keyName) || "id";
|
|
147
|
+
|
|
148
|
+
if (isMap && !OPS.includes(op)) {
|
|
149
|
+
if (payload && !Array.isArray(payload)) {
|
|
150
|
+
payload[keyName] = op;
|
|
151
|
+
op = "insert";
|
|
152
|
+
}
|
|
153
|
+
if (!payload) {
|
|
154
|
+
payload = {};
|
|
155
|
+
payload[keyName] = op;
|
|
156
|
+
op = "delete";
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
let sort = action.sort || (opts && opts?.sort);
|
|
161
|
+
if (op === "insert") {
|
|
162
|
+
if (isList && payload) return listInsertReducer(state, {payload, sort, keyName});
|
|
163
|
+
else if (isMap && payload) return mapInsertReducer(state, {payload, keyName});
|
|
164
|
+
return objInsertReducer(state, {payload});
|
|
165
|
+
} else if (op === "replace") {
|
|
166
|
+
if (isList) return listReplaceReducer(state, {payload, sort, keyName});
|
|
167
|
+
else if (isMap) return mapReplaceReducer(state, {payload, keyName});
|
|
168
|
+
return objReplaceReducer(state, {payload});
|
|
169
|
+
} else if (op === "delete") {
|
|
170
|
+
if (isList) return listDeleteReducer(state, {payload, keyName});
|
|
171
|
+
else if (isMap) return mapDeleteReducer(state, {payload, keyName});
|
|
172
|
+
return objDeleteReducer();
|
|
173
|
+
} else if (op === "clear") {
|
|
174
|
+
if (isList) return listClearReducer()
|
|
175
|
+
else if (isMap) return mapClearReducer();
|
|
176
|
+
return objClearReducer();
|
|
177
|
+
} else if (op === "sort") {
|
|
178
|
+
if (isList) return listSortReducer(state, {sort, keyName});
|
|
179
|
+
} else {
|
|
180
|
+
console.error(`unknown op (${op}) in action type: ${action.type}. Op should be one of: insert, delete, replace, clear, or sort.`);
|
|
181
|
+
}
|
|
182
|
+
return state || (isList ? [] : isMap ? {} : null);
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export { reducerBuilder };
|