You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

185 lines
4.7 KiB

2 years ago
// @flow
import getStoredStateV5 from '../getStoredState'
import type { PersistConfig, Transform } from '../types'
type V4Config = {
storage?: Object,
serialize: boolean,
keyPrefix?: string,
transforms?: Array<Transform>,
blacklist?: Array<string>,
whitelist?: Array<string>,
}
export default function getStoredState(v4Config: V4Config) {
return function(v5Config: PersistConfig) {
return getStoredStateV5(v5Config).then(state => {
if (state) return state
else return getStoredStateV4(v4Config)
})
}
}
const KEY_PREFIX = 'reduxPersist:'
function hasLocalStorage() {
if (typeof self !== 'object' || !('localStorage' in self)) {
return false
}
try {
let storage = self.localStorage
const testKey = `redux-persist localStorage test`
storage.setItem(testKey, 'test')
storage.getItem(testKey)
storage.removeItem(testKey)
} catch (e) {
if (process.env.NODE_ENV !== 'production')
console.warn(
`redux-persist localStorage test failed, persistence will be disabled.`
)
return false
}
return true
}
let noop = (...args: any) => {
/* noop */ return null
}
const noStorage = {
getItem: noop,
setItem: noop,
removeItem: noop,
getAllKeys: noop,
}
const createAsyncLocalStorage = () => {
if (!hasLocalStorage()) return noStorage
let localStorage = self.localStorage
return {
getAllKeys: function(cb) {
try {
var keys = []
for (var i = 0; i < localStorage.length; i++) {
keys.push(localStorage.key(i))
}
cb(null, keys)
} catch (e) {
cb(e)
}
},
getItem(key, cb) {
try {
var s = localStorage.getItem(key)
cb(null, s)
} catch (e) {
cb(e)
}
},
setItem(key, string, cb) {
try {
localStorage.setItem(key, string)
cb(null)
} catch (e) {
cb(e)
}
},
removeItem(key, cb) {
try {
localStorage.removeItem(key)
cb && cb(null)
} catch (e) {
cb(e)
}
},
}
}
function getStoredStateV4(v4Config: V4Config) {
return new Promise((resolve, reject) => {
let storage = v4Config.storage || createAsyncLocalStorage()
const deserializer =
v4Config.serialize === false
? data => data
: (serial: string) => JSON.parse(serial)
const blacklist = v4Config.blacklist || []
const whitelist = v4Config.whitelist || false
const transforms = v4Config.transforms || []
const keyPrefix =
v4Config.keyPrefix !== undefined ? v4Config.keyPrefix : KEY_PREFIX
// fallback getAllKeys to `keys` if present (LocalForage compatability)
if (storage.keys && !storage.getAllKeys)
storage = { ...storage, getAllKeys: storage.keys }
let restoredState = {}
let completionCount = 0
storage.getAllKeys((err, allKeys = []) => {
if (err) {
if (process.env.NODE_ENV !== 'production')
console.warn(
'redux-persist/getStoredState: Error in storage.getAllKeys'
)
return reject(err)
}
let persistKeys = allKeys
.filter(key => key.indexOf(keyPrefix) === 0)
.map(key => key.slice(keyPrefix.length))
let keysToRestore = persistKeys.filter(passWhitelistBlacklist)
let restoreCount = keysToRestore.length
if (restoreCount === 0) resolve(undefined)
keysToRestore.forEach(key => {
storage.getItem(createStorageKey(key), (err, serialized) => {
if (err && process.env.NODE_ENV !== 'production')
console.warn(
'redux-persist/getStoredState: Error restoring data for key:',
key,
err
)
else restoredState[key] = rehydrate(key, serialized)
completionCount += 1
if (completionCount === restoreCount) resolve(restoredState)
})
})
})
function rehydrate(key: string, serialized: ?string) {
let state = null
try {
let data = serialized ? deserializer(serialized) : undefined
state = transforms.reduceRight((subState, transformer) => {
return transformer.out(subState, key, {})
}, data)
} catch (err) {
if (process.env.NODE_ENV !== 'production')
console.warn(
'redux-persist/getStoredState: Error restoring data for key:',
key,
err
)
}
return state
}
function passWhitelistBlacklist(key) {
if (whitelist && whitelist.indexOf(key) === -1) return false
if (blacklist.indexOf(key) !== -1) return false
return true
}
function createStorageKey(key) {
return `${keyPrefix}${key}`
}
})
}
function defaultDeserializer(serial: string) {
return JSON.parse(serial)
}