Comparing version 0.5.0 to 1.0.0
@@ -7,2 +7,7 @@ # Changelog | ||
## [1.0.0] - 2018-12-22 | ||
### Changed | ||
- Use new pattern to write logical | ||
- Update package and use webpack | ||
## [0.5.0] - 2018-06-25 | ||
@@ -9,0 +14,0 @@ ### Changed |
{ | ||
"name": "mycache", | ||
"version": "0.5.0", | ||
"version": "1.0.0", | ||
"description": "A Cache library", | ||
"keywords": [ | ||
"cache", | ||
"indexedDB", | ||
"localstorage", | ||
"localStorage", | ||
"sessionStorage", | ||
"memoryStore", | ||
"javascript" | ||
@@ -21,8 +22,10 @@ ], | ||
"src", | ||
"dist" | ||
"umd", | ||
"es", | ||
"lib" | ||
], | ||
"main": "dist/cjs", | ||
"module": "dist/esm/mycache.prod.min.js", | ||
"browser": "dist/umd/mycache.prod.min.js", | ||
"types": "src/index", | ||
"main": "lib/index.js", | ||
"module": "es/index.js", | ||
"browser": "umd/mycache.js", | ||
"types": "es/typings.d.ts", | ||
"repository": { | ||
@@ -33,32 +36,42 @@ "type": "git", | ||
"scripts": { | ||
"build": "cross-env rimraf lib build dist && tsc && rollup -c && node ./scripts/bundles", | ||
"dev": "tsc --watch src", | ||
"lint": "tslint src/*", | ||
"prepublish": "npm run build", | ||
"build": "npm run build:ts && npm run build:cjs && npm run build:umd", | ||
"build:ts": "cross-env rimraf es && tsc", | ||
"build:cjs": "cross-env rimraf lib && cross-env NODE_ENV=commonjs BABEL_ENV=cjs babel ./es -d lib", | ||
"build:umd": "cross-env rimraf umd && cross-env BABEL_ENV=umd webpack --config webpack.config.js", | ||
"clean": "cross-env rimraf lib build dist", | ||
"lint": "tslint -c src/**/*", | ||
"test": "npm run build && nyc ava", | ||
"report": "nyc report --reporter=html" | ||
}, | ||
"dependencies": { | ||
"localforage": "^1.7.2" | ||
}, | ||
"devDependencies": { | ||
"@types/node": "^9.6.0", | ||
"@babel/cli": "^7.1.0", | ||
"@babel/core": "^7.0.0", | ||
"@babel/plugin-proposal-class-properties": "^7.0.0", | ||
"@babel/plugin-proposal-export-default-from": "^7.0.0", | ||
"@babel/plugin-proposal-export-namespace-from": "^7.0.0", | ||
"@babel/plugin-proposal-object-rest-spread": "^7.0.0", | ||
"@babel/polyfill": "^7.0.0", | ||
"@babel/preset-env": "^7.0.0", | ||
"@babel/register": "^7.0.0", | ||
"@babel/runtime": "^7.0.0", | ||
"@types/node": "^10.1.4", | ||
"ava": "^0.25.0", | ||
"babel-preset-es2015": "^6.24.1", | ||
"babel-register": "^6.26.0", | ||
"babel-loader": "^8.0.0", | ||
"babel-plugin-lodash": "^3.3.0", | ||
"coveralls": "^3.0.0", | ||
"cross-env": "^5.1.4", | ||
"husky": "^0.14.3", | ||
"lint-staged": "^7.0.4", | ||
"nyc": "^11.6.0", | ||
"puppeteer": "^1.3.0", | ||
"cross-env": "^5.2.0", | ||
"husky": "^1.3.0", | ||
"lint-staged": "^8.0.0", | ||
"nyc": "^13.0.0", | ||
"prettier": "^1.15.3", | ||
"puppeteer": "^1.11.0", | ||
"rimraf": "^2.6.2", | ||
"rollup": "^0.57.1", | ||
"rollup-plugin-commonjs": "^9.1.0", | ||
"rollup-plugin-node-resolve": "^3.3.0", | ||
"rollup-plugin-replace": "^2.0.0", | ||
"rollup-plugin-uglify": "^3.0.0", | ||
"sinon": "^4.5.0", | ||
"tslint": "^5.9.1", | ||
"typescript": "^2.8.1", | ||
"uglify-es": "^3.3.10" | ||
"tslint": "^5.10.0", | ||
"typescript": "^3.1.0", | ||
"webpack": "^4.20.0", | ||
"webpack-bundle-analyzer": "^3.0.3", | ||
"webpack-cli": "^3.1.0" | ||
}, | ||
@@ -87,10 +100,5 @@ "husky": { | ||
"require": [ | ||
"babel-register" | ||
], | ||
"babel": { | ||
"presets": [ | ||
"es2015" | ||
] | ||
} | ||
"@babel/register" | ||
] | ||
} | ||
} |
@@ -8,6 +8,4 @@ # Mycache | ||
Mycache is a cache library enhanced front end local cache, and provides two kinds of cache: persist cache and memory cache. | ||
Mycache is a cache library enhanced front end local cache. It can provide 4 stores, includes indexedDB, localStorage, sessionStorage and memorayStore. | ||
The persist cache use two park to store, localStorage is responsible for store the meta info, and indexeddb is responsible for store value. | ||
## Installation | ||
@@ -25,5 +23,5 @@ NPM is the easiest and fastest way to get started using Mycache. | ||
```js | ||
import { Persist } from 'mycache'; | ||
import Mycache from 'mycache'; | ||
const persist = new Persist(); | ||
const mycache = new Mycache(); | ||
``` | ||
@@ -34,10 +32,8 @@ | ||
```js | ||
import { Persist } from 'mycache'; | ||
import Mycache from 'mycache'; | ||
const persist = new Persist(); | ||
const mycache = new Mycache(); | ||
async function persist() { | ||
await persist.set('key', 'value'); | ||
return await persist.get('key'); | ||
} | ||
await mycache.set('key', 'value'); | ||
const val = await mycache.get('key'); | ||
``` | ||
@@ -47,49 +43,7 @@ | ||
MemCache Config: | ||
```js | ||
import { MemCache } from 'mycache'; | ||
import Mycache from 'mycache'; | ||
const cache = new MemCache({ | ||
const mycache = new Mycache({ | ||
name: 'mycache', // name prefix of key | ||
}); | ||
``` | ||
MemCache API: | ||
```ts | ||
// get value of key | ||
function get(key: string): Promise<any> {} | ||
// get all value of keys | ||
function gets() : Promise<any> {} | ||
// set key value and expire time | ||
function set<T>(key: string, value: T, expire: number | Date = -1): Promise<T> {} | ||
// append key value and expire time | ||
function append<T>(key: string, value: T, expire: number | Date = -1): Promise<T> {} | ||
// if the key has in local | ||
function has(key: string): Promise<boolean> {} | ||
// remove key | ||
function remove(key: string): Promise<void> {} | ||
// get all keys | ||
function keys(): Promise<string[]> {} | ||
// clear all keys | ||
function clear(): Promise<void> {} | ||
// the length of all keys | ||
function length(): Promise<number> {} | ||
// each all keys by callback | ||
function each(iterator: (value: any, key: string, iterationNumber: number) => void): Promise<boolean> {} | ||
// if the key is expired | ||
function isExpired(key: string): Promise<boolean> {} | ||
``` | ||
Persist Config: | ||
```js | ||
import { Persist } from 'mycache'; | ||
const persist = new Persist({ | ||
name: 'mycache', // name prefix of key | ||
storeName: 'persist', // The name of the datastore | ||
isCompress: false, // if enable string compress | ||
valueMaxLength: 20 * 1000, // max length of value | ||
oldItemsCount: 0.2, // this count of old items | ||
@@ -99,3 +53,3 @@ }); | ||
Persist API: | ||
Mycache API: | ||
@@ -127,4 +81,2 @@ ```ts | ||
function getExpiredKeys(): Promise<string[]> {} | ||
// if the key is overlength | ||
function isOverLength(key: string): Promise<boolean> {} | ||
// get all overlength keys | ||
@@ -135,3 +87,3 @@ function getOverLengthKeys(): Promise<string[]> {} | ||
// get items by sorted | ||
function getSortedItems(): Promise<typed.IPersistMetaDataMap[]> {} | ||
function getSortedItems(): Promise<typed.IMycacheMetaDataMap[]> {} | ||
``` | ||
@@ -138,0 +90,0 @@ |
365
src/index.ts
@@ -1,9 +0,360 @@ | ||
import MemCache from './MemCache/MemCache'; | ||
import Persist from './Persist/Persist'; | ||
import * as typed from './typed'; | ||
// import * as localForage from 'localforage'; | ||
import { StorageStore } from './StorageStore'; | ||
import * as typed from './typings'; | ||
import * as utils from './Utils/utils'; | ||
export { | ||
typed, | ||
Persist, | ||
MemCache, | ||
const DEFAULT_CONFIG: typed.IMycacheConfig = { | ||
oldItemsCount: 0.2, | ||
}; | ||
interface ITempCache { | ||
count: number; | ||
items: typed.IMycacheMetaDataMap; | ||
} | ||
class Mycache { | ||
private cacheConfig: typed.IMycacheConfig; | ||
private cacheInstance: StorageStore; | ||
constructor(config: typed.IMycacheConfig = {}) { | ||
this.cacheConfig = utils.extend(DEFAULT_CONFIG, config); | ||
const stores = ['indexedDB', 'localStorage']; | ||
this.cacheInstance = new StorageStore(stores, { | ||
prefix: this.cacheConfig.name, | ||
}); | ||
} | ||
public async getOldKeys(): Promise<string[]> { | ||
try { | ||
const length = await this.length(); | ||
const oldItemsCount = this.cacheConfig.oldItemsCount; | ||
const oldCount = | ||
oldItemsCount < 1 | ||
? Math.floor(length * oldItemsCount) | ||
: Math.floor(oldItemsCount); | ||
const getkeys: string[] = []; | ||
const cacheSorted = await this.getSortedItems(); | ||
const sortedCache = cacheSorted.reverse(); | ||
for (let i = 0; i < sortedCache.length; i++) { | ||
const value = sortedCache[i]; | ||
if (i < oldCount) { | ||
getkeys.push(value.key); | ||
} | ||
} | ||
return Promise.resolve(getkeys); | ||
} catch (err) { | ||
return Promise.reject(err); | ||
} | ||
} | ||
public async getExpiredKeys(): Promise<string[]> { | ||
try { | ||
const getkeys: string[] = []; | ||
const keys = await this.keys(); | ||
for (const key of keys) { | ||
const isExpired = await this.isExpired(key); | ||
if (isExpired) { | ||
getkeys.push(key); | ||
} | ||
} | ||
return Promise.resolve(getkeys); | ||
} catch (err) { | ||
return Promise.reject(err); | ||
} | ||
} | ||
public async isExpired( | ||
key: string, | ||
currentTime: number = new Date().getTime() | ||
): Promise<boolean> { | ||
try { | ||
const res = await this.get(key); | ||
if (res && res.expire) { | ||
return Promise.resolve(this.expiredVaule(res.expire, currentTime)); | ||
} else { | ||
return Promise.resolve(false); | ||
} | ||
} catch (err) { | ||
return Promise.reject(err); | ||
} | ||
} | ||
public async get( | ||
key: string, | ||
currentTime: number = new Date().getTime() | ||
): Promise<any> { | ||
try { | ||
const res: typed.IMycacheDataMapValue = await this.cacheInstance.get(key); | ||
if (!res) { | ||
return Promise.resolve(null); | ||
} | ||
if ( | ||
res.expire !== undefined && | ||
res.now !== undefined && | ||
res.count !== undefined | ||
) { | ||
const isExpired = this.expiredVaule(res.expire, currentTime); | ||
if (isExpired) { | ||
await this.remove(key); | ||
return Promise.resolve(null); | ||
} | ||
return Promise.resolve(res.value); | ||
} | ||
// If don't mycache init, return value directly | ||
return Promise.resolve(res); | ||
} catch (err) { | ||
return Promise.reject(err); | ||
} | ||
} | ||
public async gets(keys: string[]): Promise<any> { | ||
try { | ||
const res = []; | ||
for (const key of keys) { | ||
res.push(await this.get(key)); | ||
} | ||
return Promise.resolve(res); | ||
} catch (err) { | ||
return Promise.reject(err); | ||
} | ||
} | ||
public async set<T>( | ||
key: string, | ||
value: T, | ||
expire: number | Date = -1 | ||
): Promise<T> { | ||
try { | ||
const res = await this.get(key); | ||
// If don't use mycache init, return value directly | ||
if (res && !res.expire && !res.count && !res.now) { | ||
return this.cacheInstance.set(key, value); | ||
} | ||
const now = new Date().getTime(); | ||
let expireTime; | ||
if (utils.isDate(expire)) { | ||
expireTime = (expire as Date).getTime(); | ||
} else if (utils.isNumber(expire) && expire > 0) { | ||
// expire number is second | ||
expireTime = now + (expire as number) * 1000; | ||
} else { | ||
expireTime = -1; | ||
} | ||
let count = 0; | ||
if (res && res.count !== undefined) { | ||
count = res.count + 1; | ||
} | ||
let realValue; | ||
if (value) { | ||
realValue = { | ||
value, | ||
now, | ||
count, | ||
expire: expireTime, | ||
}; | ||
} else { | ||
realValue = { | ||
...res, | ||
now, | ||
count, | ||
}; | ||
} | ||
return this.cacheInstance.set(key, realValue); | ||
} catch (err) { | ||
if (err.name.toUpperCase().indexOf('QUOTA') >= 0) { | ||
await this.clearKeys(); | ||
return Promise.resolve(null); | ||
} | ||
return Promise.reject(err); | ||
} | ||
} | ||
public async append<T>( | ||
key: string, | ||
value: T, | ||
expire: number | Date = -1 | ||
): Promise<T> { | ||
try { | ||
const res = await this.get(key); | ||
if (!res) { | ||
return this.set(key, value, expire); | ||
} | ||
expire = expire ? expire : res.expire; | ||
if (utils.isArray(value) && utils.isArray(res)) { | ||
value = (res as any).concat(value); | ||
} else if (utils.isPlainObject(value) && utils.isPlainObject(res)) { | ||
value = utils.extend(res, value); | ||
} | ||
return this.set(key, value, expire); | ||
} catch (err) { | ||
if (err.name.toUpperCase().indexOf('QUOTA') >= 0) { | ||
await this.clearKeys(); | ||
return Promise.resolve(null); | ||
} | ||
return Promise.reject(err); | ||
} | ||
} | ||
public async has(key: string): Promise<boolean> { | ||
try { | ||
const res = await this.get(key); | ||
if (res) { | ||
return Promise.resolve(true); | ||
} else { | ||
return Promise.resolve(false); | ||
} | ||
} catch (err) { | ||
return Promise.reject(err); | ||
} | ||
} | ||
public async remove(key: string): Promise<void> { | ||
try { | ||
await this.cacheInstance.remove(key); | ||
return Promise.resolve(); | ||
} catch (err) { | ||
return Promise.reject(err); | ||
} | ||
} | ||
public async clear(): Promise<void> { | ||
try { | ||
await this.cacheInstance.clear(); | ||
return Promise.resolve(); | ||
} catch (err) { | ||
return Promise.reject(err); | ||
} | ||
} | ||
public keys(): Promise<string[]> { | ||
return this.cacheInstance.keys(); | ||
} | ||
public length(): Promise<number> { | ||
return this.cacheInstance.length(); | ||
} | ||
public async each( | ||
iterator: (value: any, key: string, num: number) => void | ||
): Promise<boolean> { | ||
try { | ||
const cache = await this.keys(); | ||
for (let i = 0; i < cache.length; i++) { | ||
const key = cache[i]; | ||
const value = await this.get(key); | ||
if (iterator) { | ||
await iterator(value, key, i); | ||
} | ||
} | ||
return Promise.resolve(true); | ||
} catch (err) { | ||
return Promise.reject(err); | ||
} | ||
} | ||
public async getSortedItems(): Promise<typed.IMycacheMetaDataMap[]> { | ||
try { | ||
const keys = await this.keys(); | ||
const cache: typed.IMycacheMetaDataMap[] = []; | ||
for (const key of keys) { | ||
const value = await this.get(key); | ||
cache.push({ ...value, key }); | ||
} | ||
const countGroup: any = {}; | ||
for (const item of cache) { | ||
if (!countGroup[item.count]) { | ||
countGroup[item.count] = []; | ||
} | ||
countGroup[item.count].push(item); | ||
} | ||
let sortCountSet: ITempCache[] = []; | ||
for (const i in countGroup) { | ||
if (countGroup.hasOwnProperty(i)) { | ||
// sort by now desc | ||
sortCountSet.push({ | ||
count: parseInt(i, 10), | ||
items: countGroup[i].sort( | ||
(a: typed.IMycacheMetaDataMap, b: typed.IMycacheMetaDataMap) => | ||
b.now - a.now | ||
), | ||
}); | ||
} | ||
} | ||
// sort by count desc | ||
sortCountSet = sortCountSet.sort( | ||
(a: ITempCache, b: ITempCache) => b.count - a.count | ||
); | ||
let finalCache: typed.IMycacheMetaDataMap[] = []; | ||
for (const res of sortCountSet) { | ||
finalCache = finalCache.concat(res.items); | ||
} | ||
return Promise.resolve(finalCache); | ||
} catch (err) { | ||
return Promise.reject(err); | ||
} | ||
} | ||
private expiredVaule(expire: number, currentTime: number): boolean { | ||
return expire && expire > 0 && expire < currentTime; | ||
} | ||
private async clearKeys(): Promise<boolean> { | ||
try { | ||
let keys = await this.getExpiredKeys(); | ||
keys.concat(await this.getOldKeys()); | ||
keys = keys.sort().filter((item, index, array) => { | ||
return !index || item !== array[index - 1]; | ||
}); | ||
for (const key of keys) { | ||
await this.remove(key); | ||
} | ||
return Promise.resolve(true); | ||
} catch (err) { | ||
return Promise.reject(err); | ||
} | ||
} | ||
} | ||
module.exports = Mycache; |
@@ -18,16 +18,24 @@ const toString = Object.prototype.toString; | ||
function isObjectObject(o: any) { | ||
return isObject(o) === true | ||
&& Object.prototype.toString.call(o) === '[object Object]'; | ||
return ( | ||
isObject(o) === true && | ||
Object.prototype.toString.call(o) === '[object Object]' | ||
); | ||
} | ||
function isPlainObject(o: any) { | ||
if (isObjectObject(o) === false) { return false; } | ||
if (isObjectObject(o) === false) { | ||
return false; | ||
} | ||
// If has modified constructor | ||
const ctor = o.constructor; | ||
if (typeof ctor !== 'function') { return false; } | ||
if (typeof ctor !== 'function') { | ||
return false; | ||
} | ||
// If has modified prototype | ||
const prot = ctor.prototype; | ||
if (isObjectObject(prot) === false) { return false; } | ||
if (isObjectObject(prot) === false) { | ||
return false; | ||
} | ||
@@ -44,3 +52,5 @@ // If constructor does not have an Object-specific method | ||
function extend(target: any, source: any) { | ||
if (source === null || typeof source !== 'object') { return target; } | ||
if (source === null || typeof source !== 'object') { | ||
return target; | ||
} | ||
@@ -57,5 +67,9 @@ const keys = Object.keys(source); | ||
function omit(obj: any, props: any) { | ||
if (!isObject(obj)) { return {}; } | ||
if (!isObject(obj)) { | ||
return {}; | ||
} | ||
if (typeof props === 'string') { props = [props]; } | ||
if (typeof props === 'string') { | ||
props = [props]; | ||
} | ||
@@ -66,3 +80,3 @@ const keys = Object.keys(obj); | ||
for (const key of keys) { | ||
if (!props || (props.indexOf(key) === -1)) { | ||
if (!props || props.indexOf(key) === -1) { | ||
res[key] = obj[key]; | ||
@@ -75,19 +89,2 @@ } | ||
// http://www.alloyteam.com/2013/12/js-calculate-the-number-of-bytes-occupied-by-a-string/ | ||
function utf16ByteLength(str: string): number { | ||
let total = 0; | ||
let charCode; | ||
for (let i = 0; i < str.length; i++) { | ||
charCode = str.charCodeAt(i); | ||
if (charCode <= 0xffff) { | ||
total += 2; | ||
} else { | ||
total += 4; | ||
} | ||
} | ||
return total; | ||
} | ||
export { isDate, isNumber, isArray, isPlainObject, extend, omit, utf16ByteLength }; | ||
export { isDate, isNumber, isArray, isPlainObject, extend, omit }; |
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
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
0
38
0
0
1
215088
28
4511
85
- Removedlocalforage@^1.7.2
- Removedimmediate@3.0.6(transitive)
- Removedlie@3.1.1(transitive)
- Removedlocalforage@1.10.0(transitive)