ngrx-store-localstorage
Advanced tools
Comparing version 0.1.4 to 0.1.5
@@ -1,1 +0,4 @@ | ||
export declare const localStorageSync: (keys: any[], rehydrate?: boolean) => (reducer: any) => (state: {}, action: any) => any; | ||
export declare const dateReviver: (key: string, value: any) => any; | ||
export declare const rehydrateApplicationState: (keys: any[], storage: Storage) => any; | ||
export declare const syncStateUpdate: (state: any, keys: any[], storage: Storage) => void; | ||
export declare const localStorageSync: (keys: any[], rehydrate?: boolean, storage?: Storage) => (reducer: any) => (state: any, action: any) => any; |
@@ -5,9 +5,7 @@ "use strict"; | ||
//correctly parse dates from local storage | ||
var parseWithDates = function (jsonData) { | ||
return JSON.parse(jsonData, function (key, value) { | ||
if (typeof value === 'string' && (detectDate.test(value))) { | ||
return new Date(value); | ||
} | ||
return value; | ||
}); | ||
exports.dateReviver = function (key, value) { | ||
if (typeof value === 'string' && (detectDate.test(value))) { | ||
return new Date(value); | ||
} | ||
return value; | ||
}; | ||
@@ -27,10 +25,28 @@ var validateStateKeys = function (keys) { | ||
}; | ||
var rehydrateApplicationState = function (keys) { | ||
exports.rehydrateApplicationState = function (keys, storage) { | ||
return keys.reduce(function (acc, curr) { | ||
if (typeof curr == 'object') { | ||
curr = Object.keys(curr)[0]; | ||
var key = curr; | ||
var reviver = exports.dateReviver; | ||
var deserialize = undefined; | ||
if (typeof key == 'object') { | ||
key = Object.keys(key)[0]; | ||
// use the custom reviver function | ||
if (typeof curr[key] === 'function') { | ||
reviver = curr[key]; | ||
} | ||
else { | ||
// use custom reviver function if available | ||
if (curr[key].reviver) { | ||
reviver = curr[key].reviver; | ||
} | ||
// use custom serialize function if available | ||
if (curr[key].deserialize) { | ||
deserialize = curr[key].deserialize; | ||
} | ||
} | ||
} | ||
var stateSlice = localStorage.getItem(curr); | ||
var stateSlice = storage.getItem(key); | ||
if (stateSlice) { | ||
return Object.assign({}, acc, (_a = {}, _a[curr] = parseWithDates(stateSlice), _a)); | ||
var raw = JSON.parse(stateSlice, reviver); | ||
return Object.assign({}, acc, (_a = {}, _a[key] = deserialize ? deserialize(raw) : raw, _a)); | ||
} | ||
@@ -41,5 +57,7 @@ return acc; | ||
}; | ||
var syncStateUpdate = function (state, keys) { | ||
exports.syncStateUpdate = function (state, keys, storage) { | ||
keys.forEach(function (key) { | ||
var stateSlice = state[key]; | ||
var replacer = undefined; | ||
var space = undefined; | ||
if (typeof key == 'object') { | ||
@@ -49,6 +67,27 @@ var name_1 = Object.keys(key)[0]; | ||
if (key[name_1]) { | ||
stateSlice = key[name_1].reduce(function (memo, attr) { | ||
memo[attr] = stateSlice[attr]; | ||
return memo; | ||
}, {}); | ||
// use serialize function if specified. | ||
if (key[name_1].serialize) { | ||
stateSlice = key[name_1].serialize(stateSlice); | ||
} | ||
else { | ||
var filter = undefined; | ||
if (key[name_1].reduce) { | ||
filter = key[name_1]; | ||
} | ||
else if (key[name_1].filter) { | ||
filter = key[name_1].filter; | ||
} | ||
if (filter) { | ||
stateSlice = filter.reduce(function (memo, attr) { | ||
memo[attr] = stateSlice[attr]; | ||
return memo; | ||
}, {}); | ||
} | ||
} | ||
/* | ||
Replacer and space arguments to pass to JSON.stringify. | ||
If these fields don't exist, undefined will be passed. | ||
*/ | ||
replacer = key[name_1].replacer; | ||
space = key[name_1].space; | ||
} | ||
@@ -59,3 +98,3 @@ key = name_1; | ||
try { | ||
localStorage.setItem(key, JSON.stringify(stateSlice)); | ||
storage.setItem(key, typeof stateSlice == 'string' ? stateSlice : JSON.stringify(stateSlice, replacer, space)); | ||
} | ||
@@ -68,7 +107,8 @@ catch (e) { | ||
}; | ||
exports.localStorageSync = function (keys, rehydrate) { | ||
exports.localStorageSync = function (keys, rehydrate, storage) { | ||
if (rehydrate === void 0) { rehydrate = false; } | ||
if (storage === void 0) { storage = localStorage; } | ||
return function (reducer) { | ||
var stateKeys = validateStateKeys(keys); | ||
var rehydratedState = rehydrate ? rehydrateApplicationState(stateKeys) : undefined; | ||
var rehydratedState = rehydrate ? exports.rehydrateApplicationState(stateKeys, storage) : undefined; | ||
return function (state, action) { | ||
@@ -84,3 +124,3 @@ if (state === void 0) { state = rehydratedState; } | ||
var nextState = reducer(state, action); | ||
syncStateUpdate(nextState, stateKeys); | ||
exports.syncStateUpdate(nextState, stateKeys, storage); | ||
return nextState; | ||
@@ -90,1 +130,2 @@ }; | ||
}; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "ngrx-store-localstorage", | ||
"version": "0.1.4", | ||
"version": "0.1.5", | ||
"description": "State and local storage syncing for @ngrx/store", | ||
"main": "./dist/index.js", | ||
"scripts": { | ||
"build_dist": "tsc", | ||
"build_dist": "rimraf dist && tsc", | ||
"prepublish": "npm run typings && npm run build_dist", | ||
"clean:test": "rimraf tmp", | ||
"clean:dist": "rimraf dist", | ||
"lint": "tslint src/**.ts", | ||
"build_tests": "tsc -p spec", | ||
"exec_tests": "jasmine", | ||
"test": "tsc -p spec && jasmine && npm run clean:test", | ||
"typings": "typings install" | ||
@@ -29,20 +35,33 @@ }, | ||
"peerDependencies": { | ||
"@ngrx/core": "^1.0.0", | ||
"rxjs": "^5.0.0-beta.6", | ||
"@angular/core": "^2.0.0-rc.5", | ||
"@ngrx/store": "^2.0.0" | ||
}, | ||
"devDependencies": { | ||
"@angular/core": "^2.0.0-rc.1", | ||
"@angular/common": "^2.0.0-rc.5", | ||
"@angular/compiler": "^2.0.0-rc.5", | ||
"@angular/compiler-cli": "^0.5.0", | ||
"@angular/core": "^2.0.0-rc.5", | ||
"@angular/platform-browser": "^2.0.0-rc.5", | ||
"@angular/platform-server": "^2.0.0-rc.5", | ||
"@angular/tsc-wrapped": "^0.2.2", | ||
"@ngrx/core": "^1.0.0", | ||
"@types/jasmine": "^2.2.31", | ||
"@types/node": "^6.0.33", | ||
"core-js": "^2.4.1", | ||
"es6-promise": "^3.0.2", | ||
"es6-shim": "^0.33.13", | ||
"es6-shim": "^0.35.0", | ||
"jasmine": "^2.4.1", | ||
"jasmine-core": "^2.4.1", | ||
"lodash": "^3.10.1", | ||
"reflect-metadata": "0.1.2", | ||
"rimraf": "^2.5.1", | ||
"rimraf": "^2.5.2", | ||
"rxjs": "5.0.0-beta.6", | ||
"tslint": "^3.4.0", | ||
"typescript": "^1.7.3", | ||
"typings": "^0.6.6", | ||
"zone.js": "^0.6.6", | ||
"@ngrx/store": "^2.0.0", | ||
"rxjs": "5.0.0-beta.6" | ||
"typescript": "next", | ||
"typings": "^0.8.1", | ||
"zone.js": "^0.6.12" | ||
}, | ||
"typings": "./dist/index.d.ts" | ||
} |
@@ -14,14 +14,12 @@ # ngrx-store-localstorage | ||
3. Optionally specify whether to rehydrate this state from local storage as `initialState` on application bootstrap. | ||
4. Invoke composed function with application reducers as an argument to `provideStore`. | ||
4. Invoke composed function with application reducers as an argument to `StoreModule.provideStore`. | ||
```ts | ||
import {bootstrap} from '@angular/platform-browser-dynamic'; | ||
import {TodoApp} from './todo-app'; | ||
import {provideStore} from "@ngrx/store"; | ||
import {compose} from "@ngrx/core/compose"; | ||
import {localStorageSync} from "ngrx-store-localstorage"; | ||
import { Store, StoreModule } from '@ngrx/store'; | ||
import { todos, visibilityFilter } from './reducers'; | ||
import { NgModule } from '@angular/core' | ||
export function main() { | ||
return bootstrap(TodoApp, [ | ||
provideStore( | ||
@NgModule({ | ||
imports: [ | ||
BrowserModule, | ||
StoreModule.provideStore( | ||
compose( | ||
@@ -32,11 +30,9 @@ localStorageSync(['todos']), | ||
) | ||
]) | ||
.catch(err => console.error(err)); | ||
} | ||
document.addEventListener('DOMContentLoaded', main); | ||
] | ||
}) | ||
export class MyAppModule {} | ||
``` | ||
## API | ||
### `localStorageSync(keys : any[], rehydrateState : boolean = false) : Reducer` | ||
### `localStorageSync(keys : any[], rehydrateState : boolean = false, storage: Storage = localStorage) : Reducer` | ||
Provide state (reducer) keys to sync with local storage. Optionally specify whether to rehydrate `initialState` from local storage on bootstrap. | ||
@@ -49,4 +45,24 @@ *Returns a meta-reducer* | ||
* \(*object[]*): Array of objects where for each object the key represents the state key and the value represents an array of properties which should be synced. This allows for the partial state sync (e.g. `localStorageSync([{todos: ['name', 'status'] }, ... ])`) | ||
* \(*object[]*): Array of objects where for each object the key represents the state key and the value represents custom serialize/deserialize options. This can be one of the following: | ||
* an array of properties which should be synced. This allows for the partial state sync (e.g. `localStorageSync([{todos: ['name', 'status'] }, ... ])`) | ||
* a reviver function as specified in the [JSON.parse documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse) | ||
* an object with properties that specify one or more of the following: | ||
* serialize: a function that takes a state object and returns a plain json object to pass to json.stringify | ||
* deserialize: a function that takes that takes the raw JSON from JSON.parse and builds a state object | ||
* replacer: a replacer function as specified in the [JSON.stringify documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) | ||
* space: the space value to pass JSON.stringify | ||
* reviver: a reviver function as specified in the [JSON.parse documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse) | ||
* filter: an array of properties which should be synced (same format as the stand-along array specified above) | ||
* `rehydrateState` \(*boolean? = false*): Pull initial state from local storage on startup | ||
* `storage` \(*Storage? = localStorage*): Specify an object that conforms to the Storage interface to use, this will default localStorage |
@@ -5,9 +5,7 @@ const INIT_ACTION = "@ngrx/store/init"; | ||
//correctly parse dates from local storage | ||
const parseWithDates = (jsonData: string) => { | ||
return JSON.parse(jsonData, (key: any, value: any) => { | ||
if (typeof value === 'string' && (detectDate.test(value))) { | ||
return new Date(value); | ||
} | ||
return value; | ||
}); | ||
export const dateReviver = (key : string, value : any) => { | ||
if (typeof value === 'string' && (detectDate.test(value))) { | ||
return new Date(value); | ||
} | ||
return value; | ||
}; | ||
@@ -33,10 +31,30 @@ | ||
const rehydrateApplicationState = (keys: string[]) => { | ||
export const rehydrateApplicationState = (keys: any[], storage : Storage) => { | ||
return keys.reduce((acc, curr) => { | ||
if (typeof curr == 'object') { | ||
curr = Object.keys(curr)[0]; | ||
let key = curr; | ||
let reviver = dateReviver; | ||
let deserialize = undefined; | ||
if (typeof key == 'object') { | ||
key = Object.keys(key)[0]; | ||
// use the custom reviver function | ||
if (typeof curr[key] === 'function') { | ||
reviver = curr[key]; | ||
} | ||
else { | ||
// use custom reviver function if available | ||
if (curr[key].reviver) { | ||
reviver = curr[key].reviver; | ||
} | ||
// use custom serialize function if available | ||
if (curr[key].deserialize) { | ||
deserialize = curr[key].deserialize; | ||
} | ||
} | ||
} | ||
let stateSlice = localStorage.getItem(curr); | ||
let stateSlice = storage.getItem(key); | ||
if(stateSlice){ | ||
return Object.assign({}, acc, { [curr]: parseWithDates(stateSlice) }) | ||
let raw = JSON.parse(stateSlice,reviver); | ||
return Object.assign({}, acc, { [key]: deserialize ? deserialize(raw) : raw}); | ||
} | ||
@@ -47,19 +65,45 @@ return acc; | ||
const syncStateUpdate = (state : any, keys : string[]) => { | ||
export const syncStateUpdate = (state : any, keys : any[], storage : Storage) => { | ||
keys.forEach(key => { | ||
let stateSlice = state[key]; | ||
let replacer = undefined; | ||
let space = undefined; | ||
if (typeof key == 'object') { | ||
let name = Object.keys(key)[0]; | ||
stateSlice = state[name]; | ||
let name = Object.keys(key)[0]; | ||
stateSlice = state[name]; | ||
if (key[name]) { | ||
stateSlice = key[name].reduce((memo, attr) => { | ||
memo[attr] = stateSlice[attr]; | ||
return memo; | ||
}, {}); | ||
} | ||
if (key[name]) { | ||
// use serialize function if specified. | ||
if (key[name].serialize) { | ||
stateSlice = key[name].serialize(stateSlice); | ||
} | ||
// if serialize function is not specified filter on fields if an array has been provided. | ||
else { | ||
let filter = undefined; | ||
if (key[name].reduce) { | ||
filter = key[name]; | ||
} | ||
else if (key[name].filter) { | ||
filter = key[name].filter; | ||
} | ||
if (filter) { | ||
stateSlice = filter.reduce((memo, attr) => { | ||
memo[attr] = stateSlice[attr]; | ||
return memo; | ||
}, {}); | ||
key = name; | ||
} | ||
} | ||
/* | ||
Replacer and space arguments to pass to JSON.stringify. | ||
If these fields don't exist, undefined will be passed. | ||
*/ | ||
replacer = key[name].replacer; | ||
space = key[name].space; | ||
} | ||
key = name; | ||
} | ||
@@ -69,3 +113,3 @@ | ||
try{ | ||
localStorage.setItem(key, JSON.stringify(stateSlice)); | ||
storage.setItem(key, typeof stateSlice == 'string' ? stateSlice : JSON.stringify(stateSlice,replacer,space)); | ||
} catch(e){ | ||
@@ -78,5 +122,5 @@ console.warn('Unable to save state to localStorage:', e); | ||
export const localStorageSync = (keys : any[], rehydrate : boolean = false) => (reducer : any) => { | ||
export const localStorageSync = (keys : any[], rehydrate : boolean = false, storage: Storage = localStorage) => (reducer : any) => { | ||
const stateKeys = validateStateKeys(keys); | ||
const rehydratedState = rehydrate ? rehydrateApplicationState(stateKeys) : undefined; | ||
const rehydratedState = rehydrate ? rehydrateApplicationState(stateKeys, storage) : undefined; | ||
@@ -92,5 +136,5 @@ return function(state = rehydratedState, action : any){ | ||
const nextState = reducer(state, action); | ||
syncStateUpdate(nextState, stateKeys); | ||
syncStateUpdate(nextState, stateKeys, storage); | ||
return nextState; | ||
}; | ||
}; |
{ | ||
"compilerOptions": { | ||
"target": "ES5", | ||
"emitDecoratorMetadata": true, | ||
"experimentalDecorators": true, | ||
"module": "commonjs", | ||
"moduleResolution": "node", | ||
"outDir": "dist", | ||
"declaration": true | ||
}, | ||
"files": [ | ||
"typings/main.d.ts", | ||
"src/index.ts" | ||
], | ||
"exclude": [ | ||
"node_modules" | ||
] | ||
} | ||
"compilerOptions": { | ||
"target": "ES5", | ||
"emitDecoratorMetadata": true, | ||
"experimentalDecorators": true, | ||
"module": "commonjs", | ||
"moduleResolution": "node", | ||
"outDir": "dist", | ||
"declaration": true, | ||
"lib": ["es2015", "dom"], | ||
"sourceMap": true | ||
}, | ||
"files": [ | ||
"src/index.ts" | ||
], | ||
"angularCompilerOptions": { | ||
"skipTemplateCodegen": true | ||
} | ||
} |
@@ -9,2 +9,2 @@ { | ||
} | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
33777
16
530
66
4
23
1