├── .babelrc ├── .github └── dependabot.yml ├── .gitignore ├── LICENSE ├── README.md ├── dist ├── index.d.ts └── index.js ├── package-lock.json ├── package.json ├── src └── index.js ├── test ├── test.html ├── test.js ├── test_.js └── webpack.config.test.js └── todo.txt /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env", 4 | "minify" 5 | ] 6 | } -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | ignore: 9 | - dependency-name: "@babel/core" 10 | versions: 11 | - 7.12.13 12 | - 7.12.16 13 | - 7.12.17 14 | - 7.13.1 15 | - 7.13.10 16 | - 7.13.13 17 | - 7.13.14 18 | - 7.13.15 19 | - 7.13.8 20 | - dependency-name: y18n 21 | versions: 22 | - 4.0.1 23 | - 4.0.2 24 | - dependency-name: "@babel/cli" 25 | versions: 26 | - 7.12.13 27 | - 7.12.16 28 | - 7.12.17 29 | - 7.13.0 30 | - 7.13.10 31 | - 7.13.14 32 | - dependency-name: "@babel/preset-env" 33 | versions: 34 | - 7.12.13 35 | - 7.12.16 36 | - 7.12.17 37 | - 7.13.0 38 | - 7.13.10 39 | - 7.13.12 40 | - 7.13.5 41 | - 7.13.8 42 | - 7.13.9 43 | - dependency-name: webpack-cli 44 | versions: 45 | - 4.5.0 46 | - dependency-name: lodash-es 47 | versions: 48 | - 4.17.20 49 | - dependency-name: redux 50 | versions: 51 | - 4.0.5 52 | - dependency-name: rimraf 53 | versions: 54 | - 3.0.2 55 | - dependency-name: mixin-deep 56 | versions: 57 | - 1.3.2 58 | - dependency-name: babel-loader 59 | versions: 60 | - 6.4.1 61 | - dependency-name: webpack 62 | versions: 63 | - 2.7.0 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log* 2 | node_modules 3 | .npm 4 | .node_repl_history -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-present, Frank Kilkelly (https://monivea.com/) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Redux-LocalStorage-Simple 2 | 3 | Save and load Redux state to and from LocalStorage. 4 | 5 | ## Installation 6 | ```sh 7 | npm install --save redux-localstorage-simple 8 | ``` 9 | 10 | ## Usage Example (ES6 code) 11 | 12 | ```js 13 | import { applyMiddleware, createStore } from "redux" 14 | import reducer from "./reducer" 15 | 16 | // Import the necessary methods for saving and loading 17 | import { save, load } from "redux-localstorage-simple" 18 | 19 | /* 20 | Saving to LocalStorage is achieved using Redux 21 | middleware. The 'save' method is called by Redux 22 | each time an action is handled by your reducer. 23 | */ 24 | const createStoreWithMiddleware 25 | = applyMiddleware( 26 | save() // Saving done here 27 | )(createStore) 28 | 29 | /* 30 | Loading from LocalStorage happens during 31 | creation of the Redux store. 32 | */ 33 | const store = createStoreWithMiddleware( 34 | reducer, 35 | load() // Loading done here 36 | ) 37 | ``` 38 | 39 | ## API 40 | 41 | ### save([Object config]) 42 | 43 | Saving to LocalStorage is achieved using [Redux middleware](http://redux.js.org/docs/advanced/Middleware.html) and saves each time an action is handled by your reducer. You will need to pass the `save` method into Redux's `applyMiddleware` method, like so... 44 | 45 | ```js 46 | applyMiddleware(save()) 47 | ``` 48 | 49 | See the Usage Example above to get a better idea of how this works. 50 | 51 | #### Arguments 52 | The `save` method takes a optional configuration object as an argument. It has the following properties: 53 | 54 | ``` 55 | { 56 | [Array states], 57 | [Array ignoreStates] 58 | [String namespace], 59 | [String namespaceSeparator], 60 | [Number debounce], 61 | [Boolean disableWarnings] 62 | } 63 | ``` 64 | 65 | - states (Array, optional) - This is an optional array of strings specifying which parts of the Redux state tree you want to save to LocalStorage. e.g. ["user", "products"]. Typically states have identical names to your Redux reducers. If you do not specify any states then your entire Redux state tree will be saved to LocalStorage. 66 | - ignoreStates (Array, optional) - This is an optional array of strings specifying which parts of the Redux state tree you do **not** want to save to LocalStorage i.e. ignore. e.g. ["miscUselessInfo1", "miscUselessInfo2"]. Typically states have identical names to your Redux reducers. Unlike the `states` property, `ignoreStates` only works on top-level properties within your state, not nested state as shown in the **Advanced Usage** section below e.g. "miscUselessInfo1" = works, "miscUselessInfo1.innerInfo" = doesn't work. 67 | - namespace (String, optional) - This is an optional string specifying the namespace to add to your LocalStorage items. For example if you have a part of your Redux state tree called "user" and you specify the namespace "my_cool_app", it will be saved to LocalStorage as "my_cool_app_user" 68 | - namespaceSeparator (String, optional) - This is an optional string specifying the separator used between the namespace and the state keys. For example with the namespaceSeparator set to "::", the key saved to the LocalStorage would be "my_cool_app::user" 69 | - debounce (Number, optional) - Debouncing period (in milliseconds) to wait before saving to LocalStorage. Use this as a performance optimization if you feel you are saving to LocalStorage too often. Recommended value: 500 - 1000 milliseconds 70 | - disableWarnings (Boolean, optional) - Any exceptions thrown by LocalStorage will be logged as warnings in the JavaScript console by default, but can be silenced by setting `disableWarnings` to true. 71 | 72 | #### Examples 73 | 74 | Save entire state tree - EASIEST OPTION. 75 | 76 | ```js 77 | save() 78 | ``` 79 | 80 | Save specific parts of the state tree. 81 | 82 | ```js 83 | save({ states: ["user", "products"] }) 84 | ``` 85 | 86 | Save entire state tree except the states you want to ignore. 87 | 88 | ```js 89 | save({ ignoreStates: ["miscUselessInfo1", "miscUselessInfo2"] }) 90 | ``` 91 | 92 | Save the entire state tree under the namespace "my_cool_app". The key "my_cool_app" will appear in LocalStorage. 93 | 94 | ```js 95 | save({ namespace: "my_cool_app" }) 96 | ``` 97 | 98 | Save the entire state tree only after a debouncing period of 500 milliseconds has elapsed 99 | 100 | ```js 101 | save({ debounce: 500 }) 102 | ``` 103 | 104 | Save specific parts of the state tree with the namespace "my_cool_app". The keys "my_cool_app_user" and "my_cool_app_products" will appear in LocalStorage. 105 | 106 | ```js 107 | save({ 108 | states: ["user", "products"], 109 | namespace: "my_cool_app" 110 | }) 111 | ``` 112 | 113 | Save specific parts of the state tree with the namespace "my_cool_app" and the namespace separator "::". The keys "my_cool_app::user" and "my_cool_app::products" will appear in LocalStorage. 114 | 115 | ```js 116 | save({ 117 | states: ["user", "products"], 118 | namespace: "my_cool_app", 119 | namespaceSeparator: "::" 120 | }) 121 | ``` 122 | 123 | ### load([Object config]) 124 | Loading Redux state from LocalStorage happens during creation of the Redux store. 125 | 126 | ```js 127 | createStore(reducer, load()) 128 | ``` 129 | 130 | See the Usage Example above to get a better idea of how this works. 131 | 132 | #### Arguments 133 | The `load` method takes a optional configuration object as an argument. It has the following properties: 134 | 135 | ``` 136 | { 137 | [Array states], 138 | [String namespace], 139 | [String namespaceSeparator], 140 | [Object preloadedState], 141 | [Boolean disableWarnings] 142 | } 143 | ``` 144 | 145 | - states (Array, optional) - This is an optional array of strings specifying which parts of the Redux state tree you want to load from LocalStorage. e.g. ["user", "products"]. These parts of the state tree must have been previously saved using the `save` method. Typically states have identical names to your Redux reducers. If you do not specify any states then your entire Redux state tree will be loaded from LocalStorage. 146 | - namespace (String, optional) - If you have saved your entire state tree or parts of your state tree with a namespace you will need to specify it in order to load it from LocalStorage. 147 | - namespaceSeparator (String, optional) - If you have saved entire state tree or parts of your state tree with a namespaceSeparator, you will need to specify it in order to load it from LocalStorage. 148 | - preloadedState (Object, optional) - Passthrough for the `preloadedState` argument in Redux's `createStore` method. See section **Advanced Usage** below. 149 | - disableWarnings (Boolean, optional) - When you first try to a load a state from LocalStorage you will see a warning in the JavaScript console informing you that this state load is invalid. This is because the `save` method hasn't been called yet and this state has yet to been written to LocalStorage. You may not care to see this warning so to disable it set `disableWarnings` to true. Any exceptions thrown by LocalStorage will also be logged as warnings by default, but can be silenced by setting `disableWarnings` to true. 150 | 151 | #### Examples 152 | 153 | Load entire state tree - EASIEST OPTION. 154 | 155 | ```js 156 | load() 157 | ``` 158 | 159 | Load specific parts of the state tree. 160 | 161 | ```js 162 | load({ states: ["user", "products"] }) 163 | ``` 164 | 165 | Load the entire state tree which was previously saved with the namespace "my_cool_app". 166 | 167 | ```js 168 | load({ namespace: "my_cool_app" }) 169 | ``` 170 | 171 | Load specific parts of the state tree which was previously saved with the namespace "my_cool_app". 172 | 173 | ```js 174 | load({ 175 | states: ["user", "products"], 176 | namespace: "my_cool_app" 177 | }) 178 | ``` 179 | 180 | Load specific parts of the state tree which was previously saved with the namespace "my_cool_app" and namespace separator "::". 181 | 182 | ```js 183 | load({ 184 | states: ["user", "products"], 185 | namespace: "my_cool_app", 186 | namespaceSeparator: "::" 187 | }) 188 | ``` 189 | 190 | ### combineLoads(...loads) 191 | If you provided more than one call to `save` in your Redux middleware you will need to use `combineLoads` for a more intricate loading process. 192 | 193 | #### Arguments 194 | - loads - This method takes any number of `load` methods as arguments, with each load handling a different part of the state tree. In practice you will provide one `load` method to handle each `save` method provided in your Redux middleware. 195 | 196 | #### Example 197 | 198 | Load parts of the state tree saved with different namespaces. Here are the `save` methods in your Redux middleware: 199 | 200 | ```js 201 | applyMiddleware( 202 | save({ states: ["user"], namespace: "account_stuff" }), 203 | save({ states: ["products", "categories"], namespace: "site_stuff" }) 204 | ) 205 | ``` 206 | 207 | The corresponding use of `combineLoads` looks like this: 208 | 209 | ```js 210 | combineLoads( 211 | load({ states: ["user"], namespace: "account_stuff" }), 212 | load({ states: ["products", "categories"], namespace: "site_stuff" }) 213 | ) 214 | ``` 215 | 216 | ### clear([Object config]) 217 | 218 | Clears all Redux state tree data from LocalStorage. Note: only clears data which was saved using this module's functionality 219 | 220 | #### Arguments 221 | 222 | The `clear` method takes a optional configuration object as an argument. It has the following properties: 223 | 224 | ``` 225 | { 226 | [String namespace], 227 | [Boolean disableWarnings] 228 | } 229 | ``` 230 | 231 | - namespace - If you have saved your entire state tree or parts of your state tree under a namespace you will need to specify it in order to clear that data from LocalStorage. 232 | - disableWarnings (Boolean, optional) - Any exceptions thrown by LocalStorage will be logged as warnings in the JavaScript console by default, but can be silenced by setting `disableWarnings` to true. 233 | 234 | #### Examples 235 | 236 | Clear all Redux state tree data saved without a namespace. 237 | 238 | ```js 239 | clear() 240 | ``` 241 | 242 | Clear Redux state tree data saved with a namespace. 243 | 244 | ```js 245 | clear({ 246 | namespace: "my_cool_app" 247 | }) 248 | ``` 249 | 250 | ## Advanced Usage 251 | 252 | In a more complex project you may find that you are saving unnecessary reducer data to LocalStorage and would appreciate a more granular approach. Thankfully there is a way to do this. 253 | 254 | First let's look at a normal example. Let's say you have a reducer called `settings` and its state tree looks like this: 255 | 256 | ```js 257 | const settingsReducerInitialState = { 258 | theme: 'light', 259 | itemsPerPage: 10 260 | } 261 | ``` 262 | 263 | Using `redux-localstorage-simple`'s `save()` method for the `settings` reducer would look like this: 264 | 265 | ```js 266 | save({ states: ["settings"] }) 267 | ``` 268 | 269 | This saves all of the `settings` reducer's properties to LocalStorage. But wait, what if we really only care about saving the user's choice of `theme` and not `itemsPerPage`. Here's how to fix this: 270 | 271 | ```js 272 | save({ states: ["settings.theme"] }) 273 | ``` 274 | 275 | This saves only the `theme` setting to LocalStorage. However this presents an additional problem, if `itemsPerPage` is not saved won't my app crash when it can't find it upon loading from LocalStorage? 276 | 277 | Yes in most cases it would. So to prevent this you can use the `preloadedState` argument in the `load()` method to provide some initial data. 278 | 279 | ```js 280 | load({ 281 | states: ["settings.theme"], 282 | preloadedState: { 283 | itemsPerPage: 10 284 | } 285 | }) 286 | ``` 287 | 288 | Also note in the above example that since `settings.theme` was specified in the `load()` method we must also mirror this exactly in the `save()` method. This goes for all states you specify using the granular approach. 289 | 290 | So if you have: 291 | 292 | `save({ states: ["settings.theme"] })` 293 | 294 | You must also have: 295 | 296 | `load({ states: ["settings.theme"] })` 297 | 298 | ## Testing 299 | 300 | To run tests for this package open the file 'test/test.html' in your browser. Because this package uses LocalStorage we therefore need to test it in an environment which supports it i.e. modern browsers. 301 | 302 | ## Removal of support for Immutable.js data structures 303 | 304 | Support for Immutable.js data structures has been removed as of version 1.4.0. If you require this functionality please install version 1.4.0 using the following command: 305 | 306 | `npm install --save redux-localstorage-simple@1.4.0` 307 | 308 | ## Feedback 309 | 310 | Pull requests and opened issues are welcome! 311 | 312 | ## License 313 | 314 | MIT 315 | -------------------------------------------------------------------------------- /dist/index.d.ts: -------------------------------------------------------------------------------- 1 | import {Middleware} from "redux"; 2 | import * as m from 'redux-localstorage-simple'; 3 | 4 | declare module 'redux-localstorage-simple' { 5 | interface RLSOptions { 6 | states?: string[]; 7 | ignoreStates?: string[]; 8 | namespace?: string; 9 | namespaceSeparator?: string; 10 | debounce?: number; 11 | disableWarnings?: boolean; 12 | } 13 | interface LoadOptions { 14 | states?: string[]; 15 | immutablejs?: boolean; 16 | namespace?: string; 17 | namespaceSeparator?: string; 18 | preloadedState?: {}; 19 | disableWarnings?: boolean; 20 | } 21 | interface ClearOptions { 22 | namespace?: string; 23 | disableWarnings?: boolean; 24 | } 25 | export function save(options?:RLSOptions):Middleware 26 | export function load(options?:LoadOptions):object 27 | export function clear(options?:ClearOptions):void 28 | export function combineLoads(...loads:object[]):object 29 | } 30 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | "use strict";var _merge=_interopRequireDefault(require("merge"));Object.defineProperty(exports,"__esModule",{value:!0}),exports.clear=clear,exports.combineLoads=combineLoads,exports.load=load,exports.save=save;function _interopRequireDefault(a){return a&&a.__esModule?a:{default:a}}function _slicedToArray(a,b){return _arrayWithHoles(a)||_iterableToArrayLimit(a,b)||_unsupportedIterableToArray(a,b)||_nonIterableRest()}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _unsupportedIterableToArray(a,b){if(a){if("string"==typeof a)return _arrayLikeToArray(a,b);var c=Object.prototype.toString.call(a).slice(8,-1);return"Object"===c&&a.constructor&&(c=a.constructor.name),"Map"===c||"Set"===c?Array.from(a):"Arguments"===c||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(c)?_arrayLikeToArray(a,b):void 0}}function _arrayLikeToArray(a,b){(null==b||b>a.length)&&(b=a.length);for(var c=0,d=Array(b);c (disableWarnings ? warnSilent : warnConsole) 38 | 39 | // --------------------------------------------------- 40 | /* lensPath 41 | 42 | DESCRIPTION 43 | ---------- 44 | Gets inner data from an object based on a specified path 45 | 46 | PARAMETERS 47 | ---------- 48 | @path (Array of Strings) - Path used to get an object's inner data 49 | e.g. ['prop', 'innerProp'] 50 | @obj (Object) - Object to get inner data from 51 | 52 | USAGE EXAMPLE 53 | ------------- 54 | lensPath( 55 | ['prop', 'innerProp'], 56 | { prop: { innerProp: 123 } } 57 | ) 58 | 59 | returns 60 | 61 | 123 62 | */ 63 | 64 | function lensPath (path, obj) { 65 | if (obj === undefined) { 66 | return null 67 | } else if (path.length === 1) { 68 | return obj[path[0]] 69 | } else { 70 | return lensPath(path.slice(1), obj[path[0]]) 71 | } 72 | } 73 | 74 | // --------------------------------------------------- 75 | /* realiseObject 76 | 77 | DESCRIPTION 78 | ---------- 79 | Create an object from a specified path, with 80 | the innermost property set with an initial value 81 | 82 | PARAMETERS 83 | ---------- 84 | @objectPath (String) - Object path e.g. 'myObj.prop1.prop2' 85 | @objectInitialValue (Any, optional) - Value of the innermost property once object is created 86 | 87 | USAGE EXAMPLE 88 | ------------- 89 | 90 | realiseObject('myObj.prop1.prop2', 123) 91 | 92 | returns 93 | 94 | { 95 | myObj: { 96 | prop1: { 97 | prop2: 123 98 | } 99 | } 100 | } 101 | */ 102 | 103 | function realiseObject (objectPath, objectInitialValue = {}) { 104 | function realiseObject_ (objectPathArr, objectInProgress) { 105 | if (objectPathArr.length === 0) { 106 | return objectInProgress 107 | } else { 108 | return realiseObject_(objectPathArr.slice(1), {[objectPathArr[0]]: objectInProgress}) 109 | } 110 | } 111 | return realiseObject_(objectPath.split('.').reverse(), objectInitialValue) 112 | } 113 | 114 | // --------------------------------------------------- 115 | // SafeLocalStorage wrapper to handle the minefield of exceptions 116 | // that localStorage can throw. JSON.parse() is handled here as well. 117 | 118 | function SafeLocalStorage (warnFn) { 119 | this.warnFn = warnFn || warnConsole 120 | } 121 | 122 | Object.defineProperty(SafeLocalStorage.prototype, 'length', { 123 | get: function length () { 124 | try { 125 | return localStorage.length 126 | } catch (err) { 127 | this.warnFn(err) 128 | } 129 | return 0 130 | }, 131 | configurable: true, 132 | enumerable: true 133 | }); 134 | 135 | SafeLocalStorage.prototype.key = function key (ind) { 136 | try { 137 | return localStorage.key(ind) 138 | } catch (err) { 139 | this.warnFn(err) 140 | } 141 | return null 142 | } 143 | 144 | SafeLocalStorage.prototype.setItem = function setItem (key, val) { 145 | try { 146 | localStorage.setItem(key, JSON.stringify(val)) 147 | } catch (err) { 148 | this.warnFn(err) 149 | } 150 | } 151 | 152 | SafeLocalStorage.prototype.getItem = function getItem (key) { 153 | try { 154 | return JSON.parse(localStorage.getItem(key)) 155 | } catch (err) { 156 | this.warnFn(err) 157 | } 158 | return null 159 | } 160 | 161 | SafeLocalStorage.prototype.removeItem = function removeItem (key) { 162 | try { 163 | localStorage.removeItem(key) 164 | } catch (err) { 165 | this.warnFn(err) 166 | } 167 | } 168 | 169 | // --------------------------------------------------- 170 | 171 | /** 172 | Saves specified parts of the Redux state tree into localstorage 173 | Note: this is Redux middleware. Read this for an explanation: 174 | http://redux.js.org/docs/advanced/Middleware.html 175 | 176 | PARAMETERS 177 | ---------- 178 | @config (Object) - Contains configuration options (leave blank to save entire state tree to localstorage) 179 | 180 | Properties: 181 | states (Array of Strings, optional) - States to save e.g. ['user', 'products'] 182 | namespace (String, optional) - Namespace to add before your LocalStorage items 183 | debounce (Number, optional) - Debouncing period (in milliseconds) to wait before saving to LocalStorage 184 | Use this as a performance optimization if you feel you are saving 185 | to LocalStorage too often. Recommended value: 500 - 1000 milliseconds 186 | 187 | USAGE EXAMPLES 188 | ------------- 189 | 190 | // save entire state tree - EASIEST OPTION 191 | save() 192 | 193 | // save specific parts of the state tree 194 | save({ 195 | states: ['user', 'products'] 196 | }) 197 | 198 | // save the entire state tree under the namespace 'my_cool_app'. The key 'my_cool_app' will appear in LocalStorage 199 | save({ 200 | namespace: 'my_cool_app' 201 | }) 202 | 203 | // save the entire state tree only after a debouncing period of 500 milliseconds has elapsed 204 | save({ 205 | debounce: 500 206 | }) 207 | 208 | // save specific parts of the state tree with the namespace 'my_cool_app'. The keys 'my_cool_app_user' and 'my_cool_app_products' will appear in LocalStorage 209 | save({ 210 | states: ['user', 'products'], 211 | namespace: 'my_cool_app', 212 | debounce: 500 213 | }) 214 | */ 215 | 216 | export function save ({ 217 | states = STATES_DEFAULT, 218 | ignoreStates = IGNORE_STATES_DEFAULT, 219 | namespace = NAMESPACE_DEFAULT, 220 | namespaceSeparator = NAMESPACE_SEPARATOR_DEFAULT, 221 | debounce = DEBOUNCE_DEFAULT, 222 | disableWarnings = DISABLE_WARNINGS_DEFAULT 223 | } = {}) { 224 | return store => next => action => { 225 | // Bake disableWarnings into the warn function 226 | const warn_ = warn(disableWarnings) 227 | 228 | const returnValue = next(action) 229 | let state_ 230 | 231 | // Validate 'states' parameter 232 | if (!isArray(states)) { 233 | console.error(MODULE_NAME, "'states' parameter in 'save()' method was passed a non-array value. Setting default value instead. Check your 'save()' method.") 234 | states = STATES_DEFAULT 235 | } 236 | 237 | // Validate 'ignoreStates' parameter 238 | if (!isArray(ignoreStates)) { 239 | console.error(MODULE_NAME, "'ignoreStates' parameter in 'save()' method was passed a non-array value. Setting default value instead. Check your 'save()' method.") 240 | ignoreStates = IGNORE_STATES_DEFAULT 241 | } 242 | 243 | // Validate individual entries in'ignoreStates' parameter 244 | if (ignoreStates.length > 0) { 245 | ignoreStates = ignoreStates.filter(function (ignoreState) { 246 | if (!isString(ignoreState)) { 247 | console.error(MODULE_NAME, "'ignoreStates' array contains a non-string value. Ignoring this value. Check your 'ignoreStates' array.") 248 | } else { 249 | return ignoreState 250 | } 251 | }) 252 | } 253 | 254 | // Validate 'namespace' parameter 255 | if (!isString(namespace)) { 256 | console.error(MODULE_NAME, "'namespace' parameter in 'save()' method was passed a non-string value. Setting default value instead. Check your 'save()' method.") 257 | namespace = NAMESPACE_DEFAULT 258 | } 259 | 260 | // Validate 'namespaceSeparator' parameter 261 | if (!isString(namespaceSeparator)) { 262 | console.error(MODULE_NAME, "'namespaceSeparator' parameter in 'save()' method was passed a non-string value. Setting default value instead. Check your 'save()' method.") 263 | namespaceSeparator = NAMESPACE_SEPARATOR_DEFAULT 264 | } 265 | 266 | // Validate 'debounce' parameter 267 | if (!isInteger(debounce)) { 268 | console.error(MODULE_NAME, "'debounce' parameter in 'save()' method was passed a non-integer value. Setting default value instead. Check your 'save()' method.") 269 | debounce = DEBOUNCE_DEFAULT 270 | } 271 | 272 | // Check if there are states to ignore 273 | if (ignoreStates.length > 0) { 274 | state_= handleIgnoreStates(ignoreStates, store.getState()) 275 | } else { 276 | state_= store.getState() 277 | } 278 | 279 | const storage = new SafeLocalStorage(warn_) 280 | 281 | // Check to see whether to debounce LocalStorage saving 282 | if (debounce) { 283 | // Clear the debounce timeout if it was previously set 284 | if (debounceTimeouts.get(states + namespace)) { 285 | clearTimeout(debounceTimeouts.get(states + namespace)) 286 | } 287 | 288 | // Save to LocalStorage after the debounce period has elapsed 289 | debounceTimeouts.set( 290 | states + namespace, 291 | setTimeout(function () { 292 | _save(states, namespace) 293 | }, debounce) 294 | ) 295 | // No debouncing necessary so save to LocalStorage right now 296 | } else { 297 | _save(states, namespace) 298 | } 299 | 300 | // Digs into rootState for the data to put in LocalStorage 301 | function getStateForLocalStorage (state, rootState) { 302 | const delimiter = '.' 303 | 304 | if (state.split(delimiter).length > 1) { 305 | return lensPath(state.split(delimiter), rootState) 306 | } else { 307 | return lensPath([state], rootState) 308 | } 309 | } 310 | 311 | // Local function to avoid duplication of code above 312 | function _save () { 313 | if (states.length === 0) { 314 | storage.setItem(namespace, state_) 315 | } else { 316 | states.forEach(state => { 317 | const key = namespace + namespaceSeparator + state 318 | const stateForLocalStorage = getStateForLocalStorage(state, state_) 319 | if (stateForLocalStorage) { 320 | storage.setItem(key, stateForLocalStorage) 321 | } else { 322 | // Make sure nothing is ever saved for this incorrect state 323 | storage.removeItem(key) 324 | } 325 | }) 326 | } 327 | } 328 | 329 | return returnValue 330 | } 331 | } 332 | 333 | /** 334 | Loads specified states from localstorage into the Redux state tree. 335 | 336 | PARAMETERS 337 | ---------- 338 | @config (Object) - Contains configuration options (leave blank to load entire state tree, if it was saved previously that is) 339 | Properties: 340 | states (Array of Strings, optional) - Parts of state tree to load e.g. ['user', 'products'] 341 | namespace (String, optional) - Namespace required to retrieve your LocalStorage items, if any 342 | 343 | Usage examples: 344 | 345 | // load entire state tree - EASIEST OPTION 346 | load() 347 | 348 | // load specific parts of the state tree 349 | load({ 350 | states: ['user', 'products'] 351 | }) 352 | 353 | // load the entire state tree which was previously saved with the namespace "my_cool_app" 354 | load({ 355 | namespace: 'my_cool_app' 356 | }) 357 | 358 | // load specific parts of the state tree which was previously saved with the namespace "my_cool_app" 359 | load({ 360 | states: ['user', 'products'], 361 | namespace: 'my_cool_app' 362 | }) 363 | 364 | */ 365 | 366 | export function load ({ 367 | states = STATES_DEFAULT, 368 | immutablejs = IMMUTABLEJS_DEFAULT, 369 | namespace = NAMESPACE_DEFAULT, 370 | namespaceSeparator = NAMESPACE_SEPARATOR_DEFAULT, 371 | preloadedState = {}, 372 | disableWarnings = DISABLE_WARNINGS_DEFAULT 373 | } = {}) { 374 | // Bake disableWarnings into the warn function 375 | const warn_ = warn(disableWarnings) 376 | 377 | // Validate 'states' parameter 378 | if (!isArray(states)) { 379 | console.error(MODULE_NAME, "'states' parameter in 'load()' method was passed a non-array value. Setting default value instead. Check your 'load()' method.") 380 | states = STATES_DEFAULT 381 | } 382 | 383 | // Validate 'namespace' parameter 384 | if (!isString(namespace)) { 385 | console.error(MODULE_NAME, "'namespace' parameter in 'load()' method was passed a non-string value. Setting default value instead. Check your 'load()' method.") 386 | namespace = NAMESPACE_DEFAULT 387 | } 388 | 389 | // Validate 'namespaceSeparator' parameter 390 | if (!isString(namespaceSeparator)) { 391 | console.error(MODULE_NAME, "'namespaceSeparator' parameter in 'load()' method was passed a non-string value. Setting default value instead. Check your 'load()' method.") 392 | namespaceSeparator = NAMESPACE_SEPARATOR_DEFAULT 393 | } 394 | 395 | // Display immmutablejs deprecation notice if developer tries to utilise it 396 | if (immutablejs === true) { 397 | warn_('Support for Immutable.js data structures has been deprecated as of version 2.0.0. Please use version 1.4.0 if you require this functionality.') 398 | } 399 | 400 | const storage = new SafeLocalStorage(warn_) 401 | 402 | let loadedState = preloadedState 403 | 404 | // Load all of the namespaced Redux data from LocalStorage into local Redux state tree 405 | if (states.length === 0) { 406 | const val = storage.getItem(namespace) 407 | if (val) { 408 | loadedState = val 409 | } 410 | } else { // Load only specified states into the local Redux state tree 411 | states.forEach(function (state) { 412 | const key = namespace + namespaceSeparator + state 413 | const val = storage.getItem(key) 414 | if (val) { 415 | loadedState = merge.recursive(loadedState, realiseObject(state, val)) 416 | } else { 417 | warn_("Invalid load '" + key + "' provided. Check your 'states' in 'load()'. If this is your first time running this app you may see this message. To disable it in future use the 'disableWarnings' flag, see documentation.") 418 | } 419 | }) 420 | } 421 | 422 | return loadedState 423 | } 424 | 425 | /** 426 | Combines multiple 'load' method calls to return a single state for use in Redux's createStore method. 427 | Use this when parts of the loading process need to be handled differently e.g. some parts of your state tree use different namespaces 428 | 429 | PARAMETERS 430 | ---------- 431 | @loads - 'load' method calls passed into this method as normal arguments 432 | 433 | Usage example: 434 | 435 | // Load parts of the state tree saved with different namespaces 436 | combineLoads( 437 | load({ states: ['user'], namespace: 'account_stuff' }), 438 | load({ states: ['products', 'categories'], namespace: 'site_stuff' ) 439 | ) 440 | */ 441 | 442 | export function combineLoads (...loads) { 443 | let combinedLoad = {} 444 | 445 | loads.forEach(load => { 446 | // Make sure current 'load' is an object 447 | if (!isObject(load)) { 448 | console.error(MODULE_NAME, "One or more loads provided to 'combineLoads()' is not a valid object. Ignoring the invalid load/s. Check your 'combineLoads()' method.") 449 | load = {} 450 | } 451 | 452 | for (let state in load) { 453 | combinedLoad[state] = load[state] 454 | } 455 | }) 456 | 457 | return combinedLoad 458 | } 459 | 460 | /** 461 | Clears all Redux state tree data from LocalStorage 462 | Remember to provide a namespace if you used one during the save process 463 | 464 | PARAMETERS 465 | ---------- 466 | @config (Object) -Contains configuration options (leave blank to clear entire state tree from LocalStorage, if it was saved without a namespace) 467 | Properties: 468 | namespace (String, optional) - Namespace that you used during the save process 469 | 470 | Usage example: 471 | 472 | // clear all Redux state tree data saved without a namespace 473 | clear() 474 | 475 | // clear Redux state tree data saved with a namespace 476 | clear({ 477 | namespace: 'my_cool_app' 478 | }) 479 | */ 480 | 481 | export function clear ({ 482 | namespace = NAMESPACE_DEFAULT, 483 | disableWarnings = DISABLE_WARNINGS_DEFAULT 484 | } = {}) { 485 | // Bake disableWarnings into the warn function 486 | const warn_ = warn(disableWarnings) 487 | 488 | // Validate 'namespace' parameter 489 | if (!isString(namespace)) { 490 | console.error(MODULE_NAME, "'namespace' parameter in 'clear()' method was passed a non-string value. Setting default value instead. Check your 'clear()' method.") 491 | namespace = NAMESPACE_DEFAULT 492 | } 493 | 494 | const storage = new SafeLocalStorage(warn_) 495 | 496 | const len = storage.length 497 | for (let ind = 0; ind < len; ind++) { 498 | const key = storage.key(ind) 499 | 500 | // key starts with namespace 501 | if (key && key.slice(0, namespace.length) === namespace) { 502 | storage.removeItem(key) 503 | } 504 | } 505 | } 506 | 507 | // --------------------------------------------------- 508 | // Utility functions 509 | 510 | function isArray (value) { 511 | return Object.prototype.toString.call(value) === '[object Array]' 512 | } 513 | 514 | function isString (value) { 515 | return typeof value === 'string' 516 | } 517 | 518 | function isInteger (value) { 519 | return typeof value === 'number' && 520 | isFinite(value) && 521 | Math.floor(value) === value 522 | } 523 | 524 | function isObject (value) { 525 | return value !== null && typeof value === 'object' 526 | } 527 | 528 | // Removes ignored states from the main state object 529 | function handleIgnoreStates (ignoreStates, stateFull) { 530 | let stateFullMinusIgnoreStates = Object.entries(stateFull).reduce(function (acc, [key, value]) { 531 | if (ignoreStates.indexOf(key) === -1) { 532 | acc[key] = stateFull[key] 533 | } 534 | return acc 535 | }, {}) 536 | return stateFullMinusIgnoreStates 537 | } 538 | -------------------------------------------------------------------------------- /test/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Tests for redux-localstorage-simple 5 | 11 | 12 | 13 |
14 |

Tests for redux-localstorage-simple

15 |

Tests are run through your browser because LocalStorage needs to exist in the environment.

16 |
17 |

Test 0: LocalStorage, are you there?

18 |

Test 1: Save and load entire Redux state tree:

19 |

Test 2: Save and load part of Redux state tree:

20 |

Test 3: Save and load entire Redux state tree under a specified namespace:

21 |

Test 4: Save and load part of Redux state tree under a specified namespace:

22 |

Test 5: Save and load entire Redux state tree under a specified namespace with a specific namespaceSeparator:

23 |

Test 6: Save and load part of Redux state tree under a specified namespace with a specific namespaceSeparator:

24 |

Test 7: Clear Redux state tree data saved with the default namespace:

25 |

Test 8: Clear Redux state tree data saved with a specific namespace:

26 |

Test 9: Save Redux state with debouncing:

27 |

Test 10: Save and load specific properties of a part of Redux state tree under a specified namespace:

28 |

Test 11: Save and load entire Redux state tree except the states we ignore:

29 |
30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | (()=>{var t={1924:(t,e,r)=>{"use strict";var n=r(210),o=r(5559),i=o(n("String.prototype.indexOf"));t.exports=function(t,e){var r=n(t,!!e);return"function"==typeof r&&i(t,".prototype.")>-1?o(r):r}},5559:(t,e,r)=>{"use strict";var n=r(8612),o=r(210),i=o("%Function.prototype.apply%"),a=o("%Function.prototype.call%"),u=o("%Reflect.apply%",!0)||n.call(a,i),c=o("%Object.getOwnPropertyDescriptor%",!0),p=o("%Object.defineProperty%",!0),f=o("%Math.max%");if(p)try{p({},"a",{value:1})}catch(t){p=null}t.exports=function(t){var e=u(n,a,arguments);if(c&&p){var r=c(e,"length");r.configurable&&p(e,"length",{value:1+f(0,t.length-(arguments.length-1))})}return e};var l=function(){return u(n,i,arguments)};p?p(t.exports,"apply",{value:l}):t.exports.apply=l},251:(t,e,r)=>{"use strict";var n=r(2215),o=r(2584),i=r(609),a=r(8420),u=r(2847),c=r(5826),p=r(8923),f=r(3679),l=r(210),y=r(1924),s=r(3483),g=r(3216),v=r(7478),b=r(6430),d=r(3533),h=y("Date.prototype.getTime"),m=Object.getPrototypeOf,S=y("Object.prototype.toString"),j=l("%Set%",!0),O=y("Map.prototype.has",!0),w=y("Map.prototype.get",!0),A=y("Map.prototype.size",!0),x=y("Set.prototype.add",!0),P=y("Set.prototype.delete",!0),E=y("Set.prototype.has",!0),I=y("Set.prototype.size",!0);function k(t,e,r,n){for(var o,i=g(t);(o=i.next())&&!o.done;)if(R(e,o.value,r,n))return P(t,o.value),!0;return!1}function M(t){return void 0===t?null:"object"!=typeof t?"symbol"!=typeof t&&("string"!=typeof t&&"number"!=typeof t||+t==+t):void 0}function F(t,e,r,n,o,i){var a=M(r);if(null!=a)return a;var u=w(e,a),c=d({},o,{strict:!1});return!(void 0===u&&!O(e,a)||!R(n,u,c,i))&&!O(t,a)&&R(n,u,c,i)}function T(t,e,r){var n=M(r);return null!=n?n:E(e,n)&&!E(t,n)}function _(t,e,r,n,o,i){for(var a,u,c=g(t);(a=c.next())&&!a.done;)if(R(r,u=a.value,o,i)&&R(n,w(e,u),o,i))return P(t,u),!0;return!1}function R(t,e,r,l){var y=r||{};if(y.strict?i(t,e):t===e)return!0;if(f(t)!==f(e))return!1;if(!t||!e||"object"!=typeof t&&"object"!=typeof e)return y.strict?i(t,e):t==e;var v,P=l.has(t),M=l.has(e);if(P&&M){if(l.get(t)===l.get(e))return!0}else v={};return P||l.set(t,v),M||l.set(e,v),function(t,e,r,i){var f,l;if(typeof t!=typeof e)return!1;if(null==t||null==e)return!1;if(S(t)!==S(e))return!1;if(o(t)!==o(e))return!1;if(c(t)!==c(e))return!1;var y=t instanceof Error,v=e instanceof Error;if(y!==v)return!1;if((y||v)&&(t.name!==e.name||t.message!==e.message))return!1;var P=a(t),M=a(e);if(P!==M)return!1;if((P||M)&&(t.source!==e.source||u(t)!==u(e)))return!1;var W=p(t),N=p(e);if(W!==N)return!1;if((W||N)&&h(t)!==h(e))return!1;if(r.strict&&m&&m(t)!==m(e))return!1;if(b(t)!==b(e))return!1;var U=B(t),$=B(e);if(U!==$)return!1;if(U||$){if(t.length!==e.length)return!1;for(f=0;f=0;f--)if(D[f]!=C[f])return!1;for(f=D.length-1;f>=0;f--)if(!R(t[l=D[f]],e[l],r,i))return!1;var L=s(t),z=s(e);return L===z&&("Set"===L||"Set"===z?function(t,e,r,n){if(I(t)!==I(e))return!1;for(var o,i,a,u=g(t),c=g(e);(o=u.next())&&!o.done;)if(o.value&&"object"==typeof o.value)a||(a=new j),x(a,o.value);else if(!E(e,o.value)){if(r.strict)return!1;if(!T(t,e,o.value))return!1;a||(a=new j),x(a,o.value)}if(a){for(;(i=c.next())&&!i.done;)if(i.value&&"object"==typeof i.value){if(!k(a,i.value,r.strict,n))return!1}else if(!r.strict&&!E(t,i.value)&&!k(a,i.value,r.strict,n))return!1;return 0===I(a)}return!0}(t,e,r,i):"Map"!==L||function(t,e,r,n){if(A(t)!==A(e))return!1;for(var o,i,a,u,c,p,f=g(t),l=g(e);(o=f.next())&&!o.done;)if(u=o.value[0],c=o.value[1],u&&"object"==typeof u)a||(a=new j),x(a,u);else if(void 0===(p=w(e,u))&&!O(e,u)||!R(c,p,r,n)){if(r.strict)return!1;if(!F(t,e,u,c,r,n))return!1;a||(a=new j),x(a,u)}if(a){for(;(i=l.next())&&!i.done;)if(u=i.value[0],p=i.value[1],u&&"object"==typeof u){if(!_(a,t,u,p,r,n))return!1}else if(!(r.strict||t.has(u)&&R(w(t,u),p,r,n)||_(a,t,u,p,d({},r,{strict:!1}),n)))return!1;return 0===I(a)}return!0}(t,e,r,i))}(t,e,y,l)}function B(t){return!(!t||"object"!=typeof t||"number"!=typeof t.length||"function"!=typeof t.copy||"function"!=typeof t.slice||t.length>0&&"number"!=typeof t[0]||!(t.constructor&&t.constructor.isBuffer&&t.constructor.isBuffer(t)))}t.exports=function(t,e,r){return R(t,e,r,v())}},4289:(t,e,r)=>{"use strict";var n=r(2215),o="function"==typeof Symbol&&"symbol"==typeof Symbol("foo"),i=Object.prototype.toString,a=Array.prototype.concat,u=Object.defineProperty,c=u&&function(){var t={};try{for(var e in u(t,"x",{enumerable:!1,value:t}),t)return!1;return t.x===t}catch(t){return!1}}(),p=function(t,e,r,n){var o;(!(e in t)||"function"==typeof(o=n)&&"[object Function]"===i.call(o)&&n())&&(c?u(t,e,{configurable:!0,enumerable:!1,value:r,writable:!0}):t[e]=r)},f=function(t,e){var r=arguments.length>2?arguments[2]:{},i=n(e);o&&(i=a.call(i,Object.getOwnPropertySymbols(e)));for(var u=0;u{var e=Object.prototype.hasOwnProperty,r=Object.prototype.toString;t.exports=function(t,n,o){if("[object Function]"!==r.call(n))throw new TypeError("iterator must be a function");var i=t.length;if(i===+i)for(var a=0;a{"use strict";var e="Function.prototype.bind called on incompatible ",r=Array.prototype.slice,n=Object.prototype.toString,o="[object Function]";t.exports=function(t){var i=this;if("function"!=typeof i||n.call(i)!==o)throw new TypeError(e+i);for(var a,u=r.call(arguments,1),c=function(){if(this instanceof a){var e=i.apply(this,u.concat(r.call(arguments)));return Object(e)===e?e:this}return i.apply(t,u.concat(r.call(arguments)))},p=Math.max(0,i.length-u.length),f=[],l=0;l{"use strict";var n=r(7648);t.exports=Function.prototype.bind||n},210:(t,e,r)=>{"use strict";var n,o=SyntaxError,i=Function,a=TypeError,u=function(t){try{return i('"use strict"; return ('+t+").constructor;")()}catch(t){}},c=Object.getOwnPropertyDescriptor;if(c)try{c({},"")}catch(t){c=null}var p=function(){throw new a},f=c?function(){try{return p}catch(t){try{return c(arguments,"callee").get}catch(t){return p}}}():p,l=r(1405)(),y=Object.getPrototypeOf||function(t){return t.__proto__},s={},g="undefined"==typeof Uint8Array?n:y(Uint8Array),v={"%AggregateError%":"undefined"==typeof AggregateError?n:AggregateError,"%Array%":Array,"%ArrayBuffer%":"undefined"==typeof ArrayBuffer?n:ArrayBuffer,"%ArrayIteratorPrototype%":l?y([][Symbol.iterator]()):n,"%AsyncFromSyncIteratorPrototype%":n,"%AsyncFunction%":s,"%AsyncGenerator%":s,"%AsyncGeneratorFunction%":s,"%AsyncIteratorPrototype%":s,"%Atomics%":"undefined"==typeof Atomics?n:Atomics,"%BigInt%":"undefined"==typeof BigInt?n:BigInt,"%Boolean%":Boolean,"%DataView%":"undefined"==typeof DataView?n:DataView,"%Date%":Date,"%decodeURI%":decodeURI,"%decodeURIComponent%":decodeURIComponent,"%encodeURI%":encodeURI,"%encodeURIComponent%":encodeURIComponent,"%Error%":Error,"%eval%":eval,"%EvalError%":EvalError,"%Float32Array%":"undefined"==typeof Float32Array?n:Float32Array,"%Float64Array%":"undefined"==typeof Float64Array?n:Float64Array,"%FinalizationRegistry%":"undefined"==typeof FinalizationRegistry?n:FinalizationRegistry,"%Function%":i,"%GeneratorFunction%":s,"%Int8Array%":"undefined"==typeof Int8Array?n:Int8Array,"%Int16Array%":"undefined"==typeof Int16Array?n:Int16Array,"%Int32Array%":"undefined"==typeof Int32Array?n:Int32Array,"%isFinite%":isFinite,"%isNaN%":isNaN,"%IteratorPrototype%":l?y(y([][Symbol.iterator]())):n,"%JSON%":"object"==typeof JSON?JSON:n,"%Map%":"undefined"==typeof Map?n:Map,"%MapIteratorPrototype%":"undefined"!=typeof Map&&l?y((new Map)[Symbol.iterator]()):n,"%Math%":Math,"%Number%":Number,"%Object%":Object,"%parseFloat%":parseFloat,"%parseInt%":parseInt,"%Promise%":"undefined"==typeof Promise?n:Promise,"%Proxy%":"undefined"==typeof Proxy?n:Proxy,"%RangeError%":RangeError,"%ReferenceError%":ReferenceError,"%Reflect%":"undefined"==typeof Reflect?n:Reflect,"%RegExp%":RegExp,"%Set%":"undefined"==typeof Set?n:Set,"%SetIteratorPrototype%":"undefined"!=typeof Set&&l?y((new Set)[Symbol.iterator]()):n,"%SharedArrayBuffer%":"undefined"==typeof SharedArrayBuffer?n:SharedArrayBuffer,"%String%":String,"%StringIteratorPrototype%":l?y(""[Symbol.iterator]()):n,"%Symbol%":l?Symbol:n,"%SyntaxError%":o,"%ThrowTypeError%":f,"%TypedArray%":g,"%TypeError%":a,"%Uint8Array%":"undefined"==typeof Uint8Array?n:Uint8Array,"%Uint8ClampedArray%":"undefined"==typeof Uint8ClampedArray?n:Uint8ClampedArray,"%Uint16Array%":"undefined"==typeof Uint16Array?n:Uint16Array,"%Uint32Array%":"undefined"==typeof Uint32Array?n:Uint32Array,"%URIError%":URIError,"%WeakMap%":"undefined"==typeof WeakMap?n:WeakMap,"%WeakRef%":"undefined"==typeof WeakRef?n:WeakRef,"%WeakSet%":"undefined"==typeof WeakSet?n:WeakSet},b=function t(e){var r;if("%AsyncFunction%"===e)r=u("async function () {}");else if("%GeneratorFunction%"===e)r=u("function* () {}");else if("%AsyncGeneratorFunction%"===e)r=u("async function* () {}");else if("%AsyncGenerator%"===e){var n=t("%AsyncGeneratorFunction%");n&&(r=n.prototype)}else if("%AsyncIteratorPrototype%"===e){var o=t("%AsyncGenerator%");o&&(r=y(o.prototype))}return v[e]=r,r},d={"%ArrayBufferPrototype%":["ArrayBuffer","prototype"],"%ArrayPrototype%":["Array","prototype"],"%ArrayProto_entries%":["Array","prototype","entries"],"%ArrayProto_forEach%":["Array","prototype","forEach"],"%ArrayProto_keys%":["Array","prototype","keys"],"%ArrayProto_values%":["Array","prototype","values"],"%AsyncFunctionPrototype%":["AsyncFunction","prototype"],"%AsyncGenerator%":["AsyncGeneratorFunction","prototype"],"%AsyncGeneratorPrototype%":["AsyncGeneratorFunction","prototype","prototype"],"%BooleanPrototype%":["Boolean","prototype"],"%DataViewPrototype%":["DataView","prototype"],"%DatePrototype%":["Date","prototype"],"%ErrorPrototype%":["Error","prototype"],"%EvalErrorPrototype%":["EvalError","prototype"],"%Float32ArrayPrototype%":["Float32Array","prototype"],"%Float64ArrayPrototype%":["Float64Array","prototype"],"%FunctionPrototype%":["Function","prototype"],"%Generator%":["GeneratorFunction","prototype"],"%GeneratorPrototype%":["GeneratorFunction","prototype","prototype"],"%Int8ArrayPrototype%":["Int8Array","prototype"],"%Int16ArrayPrototype%":["Int16Array","prototype"],"%Int32ArrayPrototype%":["Int32Array","prototype"],"%JSONParse%":["JSON","parse"],"%JSONStringify%":["JSON","stringify"],"%MapPrototype%":["Map","prototype"],"%NumberPrototype%":["Number","prototype"],"%ObjectPrototype%":["Object","prototype"],"%ObjProto_toString%":["Object","prototype","toString"],"%ObjProto_valueOf%":["Object","prototype","valueOf"],"%PromisePrototype%":["Promise","prototype"],"%PromiseProto_then%":["Promise","prototype","then"],"%Promise_all%":["Promise","all"],"%Promise_reject%":["Promise","reject"],"%Promise_resolve%":["Promise","resolve"],"%RangeErrorPrototype%":["RangeError","prototype"],"%ReferenceErrorPrototype%":["ReferenceError","prototype"],"%RegExpPrototype%":["RegExp","prototype"],"%SetPrototype%":["Set","prototype"],"%SharedArrayBufferPrototype%":["SharedArrayBuffer","prototype"],"%StringPrototype%":["String","prototype"],"%SymbolPrototype%":["Symbol","prototype"],"%SyntaxErrorPrototype%":["SyntaxError","prototype"],"%TypedArrayPrototype%":["TypedArray","prototype"],"%TypeErrorPrototype%":["TypeError","prototype"],"%Uint8ArrayPrototype%":["Uint8Array","prototype"],"%Uint8ClampedArrayPrototype%":["Uint8ClampedArray","prototype"],"%Uint16ArrayPrototype%":["Uint16Array","prototype"],"%Uint32ArrayPrototype%":["Uint32Array","prototype"],"%URIErrorPrototype%":["URIError","prototype"],"%WeakMapPrototype%":["WeakMap","prototype"],"%WeakSetPrototype%":["WeakSet","prototype"]},h=r(8612),m=r(7642),S=h.call(Function.call,Array.prototype.concat),j=h.call(Function.apply,Array.prototype.splice),O=h.call(Function.call,String.prototype.replace),w=h.call(Function.call,String.prototype.slice),A=/[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g,x=/\\(\\)?/g,P=function(t){var e=w(t,0,1),r=w(t,-1);if("%"===e&&"%"!==r)throw new o("invalid intrinsic syntax, expected closing `%`");if("%"===r&&"%"!==e)throw new o("invalid intrinsic syntax, expected opening `%`");var n=[];return O(t,A,(function(t,e,r,o){n[n.length]=r?O(o,x,"$1"):e||t})),n},E=function(t,e){var r,n=t;if(m(d,n)&&(n="%"+(r=d[n])[0]+"%"),m(v,n)){var i=v[n];if(i===s&&(i=b(n)),void 0===i&&!e)throw new a("intrinsic "+t+" exists, but is not available. Please file an issue!");return{alias:r,name:n,value:i}}throw new o("intrinsic "+t+" does not exist!")};t.exports=function(t,e){if("string"!=typeof t||0===t.length)throw new a("intrinsic name must be a non-empty string");if(arguments.length>1&&"boolean"!=typeof e)throw new a('"allowMissing" argument must be a boolean');var r=P(t),n=r.length>0?r[0]:"",i=E("%"+n+"%",e),u=i.name,p=i.value,f=!1,l=i.alias;l&&(n=l[0],j(r,S([0,1],l)));for(var y=1,s=!0;y=r.length){var h=c(p,g);p=(s=!!h)&&"get"in h&&!("originalValue"in h.get)?h.get:p[g]}else s=m(p,g),p=p[g];s&&!f&&(v[u]=p)}}return p}},932:(t,e,r)=>{"use strict";var n=r.g.BigInt;t.exports=function(){return"function"==typeof n&&"function"==typeof BigInt&&"bigint"==typeof n(42)&&"bigint"==typeof BigInt(42)}},1405:(t,e,r)=>{"use strict";var n="undefined"!=typeof Symbol&&Symbol,o=r(5419);t.exports=function(){return"function"==typeof n&&"function"==typeof Symbol&&"symbol"==typeof n("foo")&&"symbol"==typeof Symbol("bar")&&o()}},5419:t=>{"use strict";t.exports=function(){if("function"!=typeof Symbol||"function"!=typeof Object.getOwnPropertySymbols)return!1;if("symbol"==typeof Symbol.iterator)return!0;var t={},e=Symbol("test"),r=Object(e);if("string"==typeof e)return!1;if("[object Symbol]"!==Object.prototype.toString.call(e))return!1;if("[object Symbol]"!==Object.prototype.toString.call(r))return!1;for(e in t[e]=42,t)return!1;if("function"==typeof Object.keys&&0!==Object.keys(t).length)return!1;if("function"==typeof Object.getOwnPropertyNames&&0!==Object.getOwnPropertyNames(t).length)return!1;var n=Object.getOwnPropertySymbols(t);if(1!==n.length||n[0]!==e)return!1;if(!Object.prototype.propertyIsEnumerable.call(t,e))return!1;if("function"==typeof Object.getOwnPropertyDescriptor){var o=Object.getOwnPropertyDescriptor(t,e);if(42!==o.value||!0!==o.enumerable)return!1}return!0}},6410:(t,e,r)=>{"use strict";var n=r(5419);t.exports=function(){return n()&&!!Symbol.toStringTag}},7642:(t,e,r)=>{"use strict";var n=r(8612);t.exports=n.call(Function.call,Object.prototype.hasOwnProperty)},2584:(t,e,r)=>{"use strict";var n=r(6410)(),o=r(1924)("Object.prototype.toString"),i=function(t){return!(n&&t&&"object"==typeof t&&Symbol.toStringTag in t)&&"[object Arguments]"===o(t)},a=function(t){return!!i(t)||null!==t&&"object"==typeof t&&"number"==typeof t.length&&t.length>=0&&"[object Array]"!==o(t)&&"[object Function]"===o(t.callee)},u=function(){return i(arguments)}();i.isLegacyArguments=a,t.exports=u?i:a},3376:(t,e,r)=>{"use strict";if(r(932)()){var n=BigInt.prototype.valueOf;t.exports=function(t){return null!=t&&"boolean"!=typeof t&&"string"!=typeof t&&"number"!=typeof t&&"symbol"!=typeof t&&"function"!=typeof t&&("bigint"==typeof t||function(t){try{return n.call(t),!0}catch(t){}return!1}(t))}}else t.exports=function(t){return!1}},6814:(t,e,r)=>{"use strict";var n=r(1924),o=n("Boolean.prototype.toString"),i=n("Object.prototype.toString"),a=r(6410)();t.exports=function(t){return"boolean"==typeof t||null!==t&&"object"==typeof t&&(a&&Symbol.toStringTag in t?function(t){try{return o(t),!0}catch(t){return!1}}(t):"[object Boolean]"===i(t))}},8923:(t,e,r)=>{"use strict";var n=Date.prototype.getDay,o=Object.prototype.toString,i=r(6410)();t.exports=function(t){return"object"==typeof t&&null!==t&&(i?function(t){try{return n.call(t),!0}catch(t){return!1}}(t):"[object Date]"===o.call(t))}},8379:t=>{"use strict";var e,r="function"==typeof Map&&Map.prototype?Map:null,n="function"==typeof Set&&Set.prototype?Set:null;r||(e=function(t){return!1});var o=r?Map.prototype.has:null,i=n?Set.prototype.has:null;e||o||(e=function(t){return!1}),t.exports=e||function(t){if(!t||"object"!=typeof t)return!1;try{if(o.call(t),i)try{i.call(t)}catch(t){return!0}return t instanceof r}catch(t){}return!1}},4578:(t,e,r)=>{"use strict";var n=Number.prototype.toString,o=Object.prototype.toString,i=r(6410)();t.exports=function(t){return"number"==typeof t||"object"==typeof t&&(i?function(t){try{return n.call(t),!0}catch(t){return!1}}(t):"[object Number]"===o.call(t))}},8420:(t,e,r)=>{"use strict";var n,o,i,a,u=r(1924),c=r(6410)();if(c){n=u("Object.prototype.hasOwnProperty"),o=u("RegExp.prototype.exec"),i={};var p=function(){throw i};a={toString:p,valueOf:p},"symbol"==typeof Symbol.toPrimitive&&(a[Symbol.toPrimitive]=p)}var f=u("Object.prototype.toString"),l=Object.getOwnPropertyDescriptor;t.exports=c?function(t){if(!t||"object"!=typeof t)return!1;var e=l(t,"lastIndex");if(!e||!n(e,"value"))return!1;try{o(t,a)}catch(t){return t===i}}:function(t){return!(!t||"object"!=typeof t&&"function"!=typeof t)&&"[object RegExp]"===f(t)}},9572:t=>{"use strict";var e,r="function"==typeof Map&&Map.prototype?Map:null,n="function"==typeof Set&&Set.prototype?Set:null;n||(e=function(t){return!1});var o=r?Map.prototype.has:null,i=n?Set.prototype.has:null;e||i||(e=function(t){return!1}),t.exports=e||function(t){if(!t||"object"!=typeof t)return!1;try{if(i.call(t),o)try{o.call(t)}catch(t){return!0}return t instanceof n}catch(t){}return!1}},9981:(t,e,r)=>{"use strict";var n=String.prototype.valueOf,o=Object.prototype.toString,i=r(6410)();t.exports=function(t){return"string"==typeof t||"object"==typeof t&&(i?function(t){try{return n.call(t),!0}catch(t){return!1}}(t):"[object String]"===o.call(t))}},2636:(t,e,r)=>{"use strict";var n=Object.prototype.toString;if(r(1405)()){var o=Symbol.prototype.toString,i=/^Symbol\(.*\)$/;t.exports=function(t){if("symbol"==typeof t)return!0;if("[object Symbol]"!==n.call(t))return!1;try{return function(t){return"symbol"==typeof t.valueOf()&&i.test(o.call(t))}(t)}catch(t){return!1}}}else t.exports=function(t){return!1}},5692:(t,e,r)=>{"use strict";var n=r(9804),o=r(3083),i=r(1924),a=i("Object.prototype.toString"),u=r(6410)(),c="undefined"==typeof globalThis?r.g:globalThis,p=o(),f=i("Array.prototype.indexOf",!0)||function(t,e){for(var r=0;r-1}return!!s&&function(t){var e=!1;return n(y,(function(r,n){if(!e)try{e=r.call(t)===n}catch(t){}})),e}(t)}},1718:t=>{"use strict";var e,r="function"==typeof WeakMap&&WeakMap.prototype?WeakMap:null,n="function"==typeof WeakSet&&WeakSet.prototype?WeakSet:null;r||(e=function(t){return!1});var o=r?r.prototype.has:null,i=n?n.prototype.has:null;e||o||(e=function(t){return!1}),t.exports=e||function(t){if(!t||"object"!=typeof t)return!1;try{if(o.call(t,o),i)try{i.call(t,i)}catch(t){return!0}return t instanceof r}catch(t){}return!1}},5899:(t,e,r)=>{"use strict";var n=r(210),o=r(1924),i=n("%WeakSet%",!0),a=o("WeakSet.prototype.has",!0);if(a){var u=o("WeakMap.prototype.has",!0);t.exports=function(t){if(!t||"object"!=typeof t)return!1;try{if(a(t,a),u)try{u(t,u)}catch(t){return!0}return t instanceof i}catch(t){}return!1}}else t.exports=function(t){return!1}},5826:t=>{var e={}.toString;t.exports=Array.isArray||function(t){return"[object Array]"==e.call(t)}},1965:(t,e)=>{"use strict";function r(){for(var t=[],e=0;e{var n="function"==typeof Map&&Map.prototype,o=Object.getOwnPropertyDescriptor&&n?Object.getOwnPropertyDescriptor(Map.prototype,"size"):null,i=n&&o&&"function"==typeof o.get?o.get:null,a=n&&Map.prototype.forEach,u="function"==typeof Set&&Set.prototype,c=Object.getOwnPropertyDescriptor&&u?Object.getOwnPropertyDescriptor(Set.prototype,"size"):null,p=u&&c&&"function"==typeof c.get?c.get:null,f=u&&Set.prototype.forEach,l="function"==typeof WeakMap&&WeakMap.prototype?WeakMap.prototype.has:null,y="function"==typeof WeakSet&&WeakSet.prototype?WeakSet.prototype.has:null,s="function"==typeof WeakRef&&WeakRef.prototype?WeakRef.prototype.deref:null,g=Boolean.prototype.valueOf,v=Object.prototype.toString,b=Function.prototype.toString,d=String.prototype.match,h=String.prototype.slice,m=String.prototype.replace,S=String.prototype.toUpperCase,j=String.prototype.toLowerCase,O=RegExp.prototype.test,w=Array.prototype.concat,A=Array.prototype.join,x=Array.prototype.slice,P=Math.floor,E="function"==typeof BigInt?BigInt.prototype.valueOf:null,I=Object.getOwnPropertySymbols,k="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?Symbol.prototype.toString:null,M="function"==typeof Symbol&&"object"==typeof Symbol.iterator,F="function"==typeof Symbol&&Symbol.toStringTag&&(Symbol.toStringTag,1)?Symbol.toStringTag:null,T=Object.prototype.propertyIsEnumerable,_=("function"==typeof Reflect?Reflect.getPrototypeOf:Object.getPrototypeOf)||([].__proto__===Array.prototype?function(t){return t.__proto__}:null);function R(t,e){if(t===1/0||t===-1/0||t!=t||t&&t>-1e3&&t<1e3||O.call(/e/,e))return e;var r=/[0-9](?=(?:[0-9]{3})+(?![0-9]))/g;if("number"==typeof t){var n=t<0?-P(-t):P(t);if(n!==t){var o=String(n),i=h.call(e,o.length+1);return m.call(o,r,"$&_")+"."+m.call(m.call(i,/([0-9]{3})/g,"$&_"),/_$/,"")}}return m.call(e,r,"$&_")}var B=r(4654).custom,W=B&&D(B)?B:null;function N(t,e,r){var n="double"===(r.quoteStyle||e)?'"':"'";return n+t+n}function U(t){return m.call(String(t),/"/g,""")}function $(t){return!("[object Array]"!==z(t)||F&&"object"==typeof t&&F in t)}function D(t){if(M)return t&&"object"==typeof t&&t instanceof Symbol;if("symbol"==typeof t)return!0;if(!t||"object"!=typeof t||!k)return!1;try{return k.call(t),!0}catch(t){}return!1}t.exports=function t(e,r,n,o){var u=r||{};if(L(u,"quoteStyle")&&"single"!==u.quoteStyle&&"double"!==u.quoteStyle)throw new TypeError('option "quoteStyle" must be "single" or "double"');if(L(u,"maxStringLength")&&("number"==typeof u.maxStringLength?u.maxStringLength<0&&u.maxStringLength!==1/0:null!==u.maxStringLength))throw new TypeError('option "maxStringLength", if provided, must be a positive integer, Infinity, or `null`');var c=!L(u,"customInspect")||u.customInspect;if("boolean"!=typeof c&&"symbol"!==c)throw new TypeError("option \"customInspect\", if provided, must be `true`, `false`, or `'symbol'`");if(L(u,"indent")&&null!==u.indent&&"\t"!==u.indent&&!(parseInt(u.indent,10)===u.indent&&u.indent>0))throw new TypeError('option "indent" must be "\\t", an integer > 0, or `null`');if(L(u,"numericSeparator")&&"boolean"!=typeof u.numericSeparator)throw new TypeError('option "numericSeparator", if provided, must be `true` or `false`');var v=u.numericSeparator;if(void 0===e)return"undefined";if(null===e)return"null";if("boolean"==typeof e)return e?"true":"false";if("string"==typeof e)return q(e,u);if("number"==typeof e){if(0===e)return 1/0/e>0?"0":"-0";var S=String(e);return v?R(e,S):S}if("bigint"==typeof e){var O=String(e)+"n";return v?R(e,O):O}var P=void 0===u.depth?5:u.depth;if(void 0===n&&(n=0),n>=P&&P>0&&"object"==typeof e)return $(e)?"[Array]":"[Object]";var I,B=function(t,e){var r;if("\t"===t.indent)r="\t";else{if(!("number"==typeof t.indent&&t.indent>0))return null;r=A.call(Array(t.indent+1)," ")}return{base:r,prev:A.call(Array(e+1),r)}}(u,n);if(void 0===o)o=[];else if(G(o,e)>=0)return"[Circular]";function C(e,r,i){if(r&&(o=x.call(o)).push(r),i){var a={depth:u.depth};return L(u,"quoteStyle")&&(a.quoteStyle=u.quoteStyle),t(e,a,n+1,o)}return t(e,u,n+1,o)}if("function"==typeof e){var J=function(t){if(t.name)return t.name;var e=d.call(b.call(t),/^function\s*([\w$]+)/);return e?e[1]:null}(e),Q=X(e,C);return"[Function"+(J?": "+J:" (anonymous)")+"]"+(Q.length>0?" { "+A.call(Q,", ")+" }":"")}if(D(e)){var Z=M?m.call(String(e),/^(Symbol\(.*\))_[^)]*$/,"$1"):k.call(e);return"object"!=typeof e||M?Z:V(Z)}if((I=e)&&"object"==typeof I&&("undefined"!=typeof HTMLElement&&I instanceof HTMLElement||"string"==typeof I.nodeName&&"function"==typeof I.getAttribute)){for(var tt="<"+j.call(String(e.nodeName)),et=e.attributes||[],rt=0;rt"}if($(e)){if(0===e.length)return"[]";var nt=X(e,C);return B&&!function(t){for(var e=0;e=0)return!1;return!0}(nt)?"["+Y(nt,B)+"]":"[ "+A.call(nt,", ")+" ]"}if(function(t){return!("[object Error]"!==z(t)||F&&"object"==typeof t&&F in t)}(e)){var ot=X(e,C);return"cause"in e&&!T.call(e,"cause")?"{ ["+String(e)+"] "+A.call(w.call("[cause]: "+C(e.cause),ot),", ")+" }":0===ot.length?"["+String(e)+"]":"{ ["+String(e)+"] "+A.call(ot,", ")+" }"}if("object"==typeof e&&c){if(W&&"function"==typeof e[W])return e[W]();if("symbol"!==c&&"function"==typeof e.inspect)return e.inspect()}if(function(t){if(!i||!t||"object"!=typeof t)return!1;try{i.call(t);try{p.call(t)}catch(t){return!0}return t instanceof Map}catch(t){}return!1}(e)){var it=[];return a.call(e,(function(t,r){it.push(C(r,e,!0)+" => "+C(t,e))})),K("Map",i.call(e),it,B)}if(function(t){if(!p||!t||"object"!=typeof t)return!1;try{p.call(t);try{i.call(t)}catch(t){return!0}return t instanceof Set}catch(t){}return!1}(e)){var at=[];return f.call(e,(function(t){at.push(C(t,e))})),K("Set",p.call(e),at,B)}if(function(t){if(!l||!t||"object"!=typeof t)return!1;try{l.call(t,l);try{y.call(t,y)}catch(t){return!0}return t instanceof WeakMap}catch(t){}return!1}(e))return H("WeakMap");if(function(t){if(!y||!t||"object"!=typeof t)return!1;try{y.call(t,y);try{l.call(t,l)}catch(t){return!0}return t instanceof WeakSet}catch(t){}return!1}(e))return H("WeakSet");if(function(t){if(!s||!t||"object"!=typeof t)return!1;try{return s.call(t),!0}catch(t){}return!1}(e))return H("WeakRef");if(function(t){return!("[object Number]"!==z(t)||F&&"object"==typeof t&&F in t)}(e))return V(C(Number(e)));if(function(t){if(!t||"object"!=typeof t||!E)return!1;try{return E.call(t),!0}catch(t){}return!1}(e))return V(C(E.call(e)));if(function(t){return!("[object Boolean]"!==z(t)||F&&"object"==typeof t&&F in t)}(e))return V(g.call(e));if(function(t){return!("[object String]"!==z(t)||F&&"object"==typeof t&&F in t)}(e))return V(C(String(e)));if(!function(t){return!("[object Date]"!==z(t)||F&&"object"==typeof t&&F in t)}(e)&&!function(t){return!("[object RegExp]"!==z(t)||F&&"object"==typeof t&&F in t)}(e)){var ut=X(e,C),ct=_?_(e)===Object.prototype:e instanceof Object||e.constructor===Object,pt=e instanceof Object?"":"null prototype",ft=!ct&&F&&Object(e)===e&&F in e?h.call(z(e),8,-1):pt?"Object":"",lt=(ct||"function"!=typeof e.constructor?"":e.constructor.name?e.constructor.name+" ":"")+(ft||pt?"["+A.call(w.call([],ft||[],pt||[]),": ")+"] ":"");return 0===ut.length?lt+"{}":B?lt+"{"+Y(ut,B)+"}":lt+"{ "+A.call(ut,", ")+" }"}return String(e)};var C=Object.prototype.hasOwnProperty||function(t){return t in this};function L(t,e){return C.call(t,e)}function z(t){return v.call(t)}function G(t,e){if(t.indexOf)return t.indexOf(e);for(var r=0,n=t.length;re.maxStringLength){var r=t.length-e.maxStringLength,n="... "+r+" more character"+(r>1?"s":"");return q(h.call(t,0,e.maxStringLength),e)+n}return N(m.call(m.call(t,/(['\\])/g,"\\$1"),/[\x00-\x1f]/g,J),"single",e)}function J(t){var e=t.charCodeAt(0),r={8:"b",9:"t",10:"n",12:"f",13:"r"}[e];return r?"\\"+r:"\\x"+(e<16?"0":"")+S.call(e.toString(16))}function V(t){return"Object("+t+")"}function H(t){return t+" { ? }"}function K(t,e,r,n){return t+" ("+e+") {"+(n?Y(r,n):A.call(r,", "))+"}"}function Y(t,e){if(0===t.length)return"";var r="\n"+e.prev+e.base;return r+A.call(t,","+r)+"\n"+e.prev}function X(t,e){var r=$(t),n=[];if(r){n.length=t.length;for(var o=0;o{"use strict";var e=function(t){return t!=t};t.exports=function(t,r){return 0===t&&0===r?1/t==1/r:t===r||!(!e(t)||!e(r))}},609:(t,e,r)=>{"use strict";var n=r(4289),o=r(5559),i=r(4244),a=r(5624),u=r(2281),c=o(a(),Object);n(c,{getPolyfill:a,implementation:i,shim:u}),t.exports=c},5624:(t,e,r)=>{"use strict";var n=r(4244);t.exports=function(){return"function"==typeof Object.is?Object.is:n}},2281:(t,e,r)=>{"use strict";var n=r(5624),o=r(4289);t.exports=function(){var t=n();return o(Object,{is:t},{is:function(){return Object.is!==t}}),t}},8987:(t,e,r)=>{"use strict";var n;if(!Object.keys){var o=Object.prototype.hasOwnProperty,i=Object.prototype.toString,a=r(1414),u=Object.prototype.propertyIsEnumerable,c=!u.call({toString:null},"toString"),p=u.call((function(){}),"prototype"),f=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],l=function(t){var e=t.constructor;return e&&e.prototype===t},y={$applicationCache:!0,$console:!0,$external:!0,$frame:!0,$frameElement:!0,$frames:!0,$innerHeight:!0,$innerWidth:!0,$onmozfullscreenchange:!0,$onmozfullscreenerror:!0,$outerHeight:!0,$outerWidth:!0,$pageXOffset:!0,$pageYOffset:!0,$parent:!0,$scrollLeft:!0,$scrollTop:!0,$scrollX:!0,$scrollY:!0,$self:!0,$webkitIndexedDB:!0,$webkitStorageInfo:!0,$window:!0},s=function(){if("undefined"==typeof window)return!1;for(var t in window)try{if(!y["$"+t]&&o.call(window,t)&&null!==window[t]&&"object"==typeof window[t])try{l(window[t])}catch(t){return!0}}catch(t){return!0}return!1}();n=function(t){var e=null!==t&&"object"==typeof t,r="[object Function]"===i.call(t),n=a(t),u=e&&"[object String]"===i.call(t),y=[];if(!e&&!r&&!n)throw new TypeError("Object.keys called on a non-object");var g=p&&r;if(u&&t.length>0&&!o.call(t,0))for(var v=0;v0)for(var b=0;b{"use strict";var n=Array.prototype.slice,o=r(1414),i=Object.keys,a=i?function(t){return i(t)}:r(8987),u=Object.keys;a.shim=function(){if(Object.keys){var t=function(){var t=Object.keys(arguments);return t&&t.length===arguments.length}(1,2);t||(Object.keys=function(t){return o(t)?u(n.call(t)):u(t)})}else Object.keys=a;return Object.keys||a},t.exports=a},1414:t=>{"use strict";var e=Object.prototype.toString;t.exports=function(t){var r=e.call(t),n="[object Arguments]"===r;return n||(n="[object Array]"!==r&&null!==t&&"object"==typeof t&&"number"==typeof t.length&&t.length>=0&&"[object Function]"===e.call(t.callee)),n}},2837:(t,e,r)=>{"use strict";var n=r(2215),o=function(t){return null!=t},i=r(5419)(),a=r(1924),u=Object,c=a("Array.prototype.push"),p=a("Object.prototype.propertyIsEnumerable"),f=i?Object.getOwnPropertySymbols:null;t.exports=function(t,e){if(!o(t))throw new TypeError("target must be an object");var r,a,l,y,s,g,v,b=u(t);for(r=1;r{"use strict";var n=r(4289),o=r(5559),i=r(2837),a=r(8162),u=r(4489),c=o.apply(a()),p=function(t,e){return c(Object,arguments)};n(p,{getPolyfill:a,implementation:i,shim:u}),t.exports=p},8162:(t,e,r)=>{"use strict";var n=r(2837);t.exports=function(){return Object.assign?function(){if(!Object.assign)return!1;for(var t="abcdefghijklmnopqrst",e=t.split(""),r={},n=0;n{"use strict";var n=r(4289),o=r(8162);t.exports=function(){var t=o();return n(Object,{assign:t},{assign:function(){return Object.assign!==t}}),t}},3697:t=>{"use strict";var e=Object,r=TypeError;t.exports=function(){if(null!=this&&this!==e(this))throw new r("RegExp.prototype.flags getter called on non-object");var t="";return this.hasIndices&&(t+="d"),this.global&&(t+="g"),this.ignoreCase&&(t+="i"),this.multiline&&(t+="m"),this.dotAll&&(t+="s"),this.unicode&&(t+="u"),this.sticky&&(t+="y"),t}},2847:(t,e,r)=>{"use strict";var n=r(4289),o=r(5559),i=r(3697),a=r(1721),u=r(2753),c=o(a());n(c,{getPolyfill:a,implementation:i,shim:u}),t.exports=c},1721:(t,e,r)=>{"use strict";var n=r(3697),o=r(4289).supportsDescriptors,i=Object.getOwnPropertyDescriptor;t.exports=function(){if(o&&"gim"===/a/gim.flags){var t=i(RegExp.prototype,"flags");if(t&&"function"==typeof t.get&&"boolean"==typeof/a/.dotAll)return t.get}return n}},2753:(t,e,r)=>{"use strict";var n=r(4289).supportsDescriptors,o=r(1721),i=Object.getOwnPropertyDescriptor,a=Object.defineProperty,u=TypeError,c=Object.getPrototypeOf,p=/a/;t.exports=function(){if(!n||!c)throw new u("RegExp.prototype.flags requires a true ES5 environment that supports property descriptors");var t=o(),e=c(p),r=i(e,"flags");return r&&r.get===t||a(e,"flags",{configurable:!0,enumerable:!1,get:t}),t}},7478:(t,e,r)=>{"use strict";var n=r(210),o=r(1924),i=r(631),a=n("%TypeError%"),u=n("%WeakMap%",!0),c=n("%Map%",!0),p=o("WeakMap.prototype.get",!0),f=o("WeakMap.prototype.set",!0),l=o("WeakMap.prototype.has",!0),y=o("Map.prototype.get",!0),s=o("Map.prototype.set",!0),g=o("Map.prototype.has",!0),v=function(t,e){for(var r,n=t;null!==(r=n.next);n=r)if(r.key===e)return n.next=r.next,r.next=t.next,t.next=r,r};t.exports=function(){var t,e,r,n={assert:function(t){if(!n.has(t))throw new a("Side channel does not contain "+i(t))},get:function(n){if(u&&n&&("object"==typeof n||"function"==typeof n)){if(t)return p(t,n)}else if(c){if(e)return y(e,n)}else if(r)return function(t,e){var r=v(t,e);return r&&r.value}(r,n)},has:function(n){if(u&&n&&("object"==typeof n||"function"==typeof n)){if(t)return l(t,n)}else if(c){if(e)return g(e,n)}else if(r)return function(t,e){return!!v(t,e)}(r,n);return!1},set:function(n,o){u&&n&&("object"==typeof n||"function"==typeof n)?(t||(t=new u),f(t,n,o)):c?(e||(e=new c),s(e,n,o)):(r||(r={key:{},next:null}),function(t,e,r){var n=v(t,e);n?n.value=r:t.next={key:e,next:t.next,value:r}}(r,n,o))}};return n}},3679:(t,e,r)=>{"use strict";var n=r(9981),o=r(4578),i=r(6814),a=r(2636),u=r(3376);t.exports=function(t){return null==t||"object"!=typeof t&&"function"!=typeof t?null:n(t)?"String":o(t)?"Number":i(t)?"Boolean":a(t)?"Symbol":u(t)?"BigInt":void 0}},6430:(t,e,r)=>{"use strict";var n=r(9804),o=r(3083),i=r(1924),a=i("Object.prototype.toString"),u=r(6410)(),c="undefined"==typeof globalThis?r.g:globalThis,p=o(),f=i("String.prototype.slice"),l={},y=r(882),s=Object.getPrototypeOf;u&&y&&s&&n(p,(function(t){if("function"==typeof c[t]){var e=new c[t];if(Symbol.toStringTag in e){var r=s(e),n=y(r,Symbol.toStringTag);if(!n){var o=s(r);n=y(o,Symbol.toStringTag)}l[t]=n.get}}}));var g=r(5692);t.exports=function(t){return!!g(t)&&(u&&Symbol.toStringTag in t?function(t){var e=!1;return n(l,(function(r,n){if(!e)try{var o=r.call(t);o===n&&(e=o)}catch(t){}})),e}(t):f(a(t),8,-1))}},4654:()=>{},3083:(t,e,r)=>{"use strict";var n=["BigInt64Array","BigUint64Array","Float32Array","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Uint8Array","Uint8ClampedArray"],o="undefined"==typeof globalThis?r.g:globalThis;t.exports=function(){for(var t=[],e=0;e{"use strict";var n=r(210)("%Object.getOwnPropertyDescriptor%",!0);if(n)try{n([],"length")}catch(t){n=null}t.exports=n},3216:(t,e,r)=>{"use strict";var n=r(2584);if(r(1405)()||r(5419)()){var o=Symbol.iterator;t.exports=function(t){return null!=t&&void 0!==t[o]?t[o]():n(t)?Array.prototype[o].call(t):void 0}}else{var i=r(5826),a=r(9981),u=r(210),c=u("%Map%",!0),p=u("%Set%",!0),f=r(1924),l=f("Array.prototype.push"),y=f("String.prototype.charCodeAt"),s=f("String.prototype.slice"),g=function(t){var e=0;return{next:function(){var r,n=e>=t.length;return n||(r=t[e],e+=1),{done:n,value:r}}}},v=function(t,e){if(i(t)||n(t))return g(t);if(a(t)){var r=0;return{next:function(){var e=function(t,e){if(e+1>=t.length)return e+1;var r=y(t,e);if(r<55296||r>56319)return e+1;var n=y(t,e+1);return n<56320||n>57343?e+1:e+2}(t,r),n=s(t,r,e);return r=e,{done:e>t.length,value:n}}}}return e&&void 0!==t["_es6-shim iterator_"]?t["_es6-shim iterator_"]():void 0};if(c||p){var b=r(8379),d=r(9572),h=f("Map.prototype.forEach",!0),m=f("Set.prototype.forEach",!0);if("undefined"==typeof process||!process.versions||!process.versions.node)var S=f("Map.prototype.iterator",!0),j=f("Set.prototype.iterator",!0),O=function(t){var e=!1;return{next:function(){try{return{done:e,value:e?void 0:t.next()}}catch(t){return e=!0,{done:!0,value:void 0}}}}};var w=f("Map.prototype.@@iterator",!0)||f("Map.prototype._es6-shim iterator_",!0),A=f("Set.prototype.@@iterator",!0)||f("Set.prototype._es6-shim iterator_",!0);t.exports=function(t){return function(t){if(b(t)){if(S)return O(S(t));if(w)return w(t);if(h){var e=[];return h(t,(function(t,r){l(e,[r,t])})),g(e)}}if(d(t)){if(j)return O(j(t));if(A)return A(t);if(m){var r=[];return m(t,(function(t){l(r,t)})),g(r)}}}(t)||v(t)}}else t.exports=function(t){if(null!=t)return v(t,!0)}}},3483:(t,e,r)=>{"use strict";var n=r(8379),o=r(9572),i=r(1718),a=r(5899);t.exports=function(t){if(t&&"object"==typeof t){if(n(t))return"Map";if(o(t))return"Set";if(i(t))return"WeakMap";if(a(t))return"WeakSet"}return!1}}},e={};function r(n){var o=e[n];if(void 0!==o)return o.exports;var i=e[n]={exports:{}};return t[n](i,i.exports,r),i.exports}r.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return r.d(e,{a:e}),e},r.d=(t,e)=>{for(var n in e)r.o(e,n)&&!r.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),r.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),(()=>{"use strict";function t(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function e(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),r.push.apply(r,n)}return r}function n(r){for(var n=1;nt.length)&&(e=t.length);for(var r=0,n=Array(e);rpart of Redux state tree under a specified namespace 386 | // ------------------------------------------------------------------------------- 387 | clearTestData() 388 | 389 | { 390 | 391 | let states = [ 392 | 'reducerMultipleLevels.setting1', 393 | 'reducerMultipleLevels.setting3.level1.level2' 394 | ] 395 | 396 | let middleware = save({ states: states, namespace: NAMESPACE_TEST }) 397 | 398 | // Store which saves to LocalStorage 399 | let storeA = applyMiddleware(middleware)(legacy_createStore)( 400 | combineReducers({ reducerMultipleLevels }), 401 | initialStateReducersPlusMultipleLevels 402 | ) 403 | 404 | storeA.dispatch({ type: MODIFY }) 405 | 406 | // Store which loads from LocalStorage 407 | let storeB = legacy_createStore( 408 | combineReducers({ reducerMultipleLevels }), 409 | load({ 410 | states: states, 411 | namespace: NAMESPACE_TEST, 412 | preloadedState: initialStateReducersPlusMultipleLevels 413 | }) 414 | ) 415 | 416 | let testResult = equal( 417 | storeA.getState(), 418 | storeB.getState() 419 | ) 420 | 421 | outputTestResult('test10', testResult) 422 | } 423 | 424 | // ------------------------------------------------------------------------------- 425 | // TEST 11 - Save and load entire Redux state tree except the states we ignore 426 | // ------------------------------------------------------------------------------- 427 | clearTestData() 428 | 429 | { 430 | 431 | let initialState = { 432 | z1: 0, 433 | z2: 'z', 434 | z3: 1 435 | } 436 | 437 | let successState = { 438 | z2: 'z' 439 | } 440 | 441 | let reducer = function (state = initialState, action) { 442 | switch (action.type) { 443 | case NOOP: 444 | return state 445 | default: 446 | return state 447 | } 448 | } 449 | 450 | let middleware = save({ ignoreStates: ['z1', 'z3'] }) 451 | 452 | // Store which saves to LocalStorage 453 | let storeA = applyMiddleware(middleware)(legacy_createStore)(reducer) 454 | 455 | // Trigger a save to LocalStorage using a noop action 456 | storeA.dispatch({ type: NOOP }) 457 | 458 | // Store which loads from LocalStorage 459 | let storeB = legacy_createStore( 460 | reducer, 461 | load() 462 | ) 463 | 464 | let testResult = equal( 465 | successState, 466 | storeB.getState() 467 | ) 468 | 469 | outputTestResult('test11', testResult) 470 | } 471 | 472 | // ------------------------------------------------------------------------------- 473 | 474 | // Output result of test in browser 475 | function outputTestResult (test, testResult) { 476 | document.getElementById(test).innerHTML = (testResult) ? 'SUCCESS' : 'FAILED' 477 | document.getElementById(test).className = (testResult) ? 'true' : 'false' 478 | } 479 | 480 | // Clear test data in LocalStorage 481 | function clearTestData () { 482 | for (let key in localStorage) { 483 | if (key.slice(0, NAMESPACE_DEFAULT.length) === NAMESPACE_DEFAULT || 484 | key.slice(0, NAMESPACE_TEST.length) === NAMESPACE_TEST) { 485 | localStorage.removeItem(key) 486 | } 487 | } 488 | } 489 | -------------------------------------------------------------------------------- /test/webpack.config.test.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | 5 | mode: 'production', 6 | 7 | entry: { 8 | test: [ 9 | './test/test_.js' 10 | ] 11 | }, 12 | 13 | module: { 14 | rules: [ 15 | { 16 | test: /\.js?/, 17 | use: 'babel-loader', 18 | exclude: /node_modules/ 19 | } 20 | ] 21 | }, 22 | 23 | output: { 24 | // library: 'redux-localstorage-simple', 25 | // libraryTarget: 'umd', 26 | filename: '[name].js', 27 | path: __dirname 28 | } 29 | 30 | } 31 | 32 | -------------------------------------------------------------------------------- /todo.txt: -------------------------------------------------------------------------------- 1 | - Add debouncing to prevent writing to LocalStorage too fast and slowing down the browser experience. --------------------------------------------------------------------------------