Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

angular-cache

Package Overview
Dependencies
Maintainers
1
Versions
29
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

angular-cache - npm Package Compare versions

Comparing version 3.2.4 to 4.0.0

27

CHANGELOG.md

@@ -0,1 +1,28 @@

##### 4.0.0 15 March 2015
###### Breaking API changes
- Completely disassociated angular-cache from the deprecated angular-data (angular-data has been replaced by js-data + js-data-angular)
- Angular module renamed to _angular-cache_
- _DSCacheFactory_ renamed to _CacheFactory_
- _DSBinaryHeap_ renamed to _BinaryHeap_
- Removed `DSCacheFactoryProvider.setCacheDefaults`. You now do `angular.extend(CacheFactoryProvider.defaults, { ... });`
- No longer exposing a `DSCache` constructor function (as it no longer exists)
- `storageMode` can now be set dynamically, which will remove all items from current storage and insert them into the new storage
###### Other
- Fixes #161
- Converted to ES6 and a webpack build with better umd support
- Now exporting the module name _angular-cache_ (when you do `require('angular-cache')` you get `"angular-cache"`)
- Deprecating angular-cache < 4.0.0
###### Backwards compatible bug fixes
- #152 - Expired items sometimes only expire after double time.
- #153 - Missing angular dependency in bower.json
##### 3.2.5 02 February 2015
###### Backwards compatible bug fixes
- #152 - Expired items sometimes only expire after double time.
- #153 - Missing angular dependency in bower.json
##### 3.2.4 17 December 2014

@@ -2,0 +29,0 @@

5

CONTRIBUTING.md

@@ -71,3 +71,3 @@ # Contributing Guide

- Checkout a new branch based on `develop` and name it to what you intend to do:
- Checkout a new branch based on `master` and name it to what you intend to do:
- Example:

@@ -86,3 +86,2 @@ ````

- Make a pull request
- Make sure you send the PR to the `develop` branch
- Travis CI is watching you!
- Travis CI is watching you!

10

dist/angular-cache.min.js

@@ -1,6 +0,6 @@

/**
/*!
* angular-cache
* @version 4.0.0 - Homepage <http://jmdobry.github.io/angular-cache/>
* @author Jason Dobry <jason.dobry@gmail.com>
* @file angular-cache.min.js
* @version 3.2.4 - Homepage <https://github.com/jmdobry/angular-cache>
* @copyright (c) 2013-2014 Jason Dobry <http://www.pseudobry.com>
* @copyright (c) 2013-2015 Jason Dobry <http://www.pseudobry.com>
* @license MIT <https://github.com/jmdobry/angular-cache/blob/master/LICENSE>

@@ -11,3 +11,3 @@ *

!function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g<d.length;g++)e(d[g]);return e}({1:[function(a,b){function c(a,b,c){for(var d=a[c],e=b(d);c>0;){var f=Math.floor((c+1)/2)-1,g=a[f];if(e>=b(g))break;a[f]=d,a[c]=g,c=f}}function d(a,b,c){for(var d=a.length,e=a[c],f=b(e);;){var g=2*(c+1),h=g-1,i=null;if(d>h){var j=a[h],k=b(j);f>k&&(i=h)}if(d>g){var l=a[g],m=b(l);m<(null===i?f:b(a[h]))&&(i=g)}if(null===i)break;a[c]=a[i],a[i]=e,c=i}}function e(a){if(a&&!angular.isFunction(a))throw new Error("DSBinaryHeap(weightFunc): weightFunc: must be a function!");a=a||function(a){return a},this.weightFunc=a,this.heap=[]}function f(){this.$get=function(){return e}}e.prototype.push=function(a){this.heap.push(a),c(this.heap,this.weightFunc,this.heap.length-1)},e.prototype.peek=function(){return this.heap[0]},e.prototype.pop=function(){var a=this.heap[0],b=this.heap.pop();return this.heap.length>0&&(this.heap[0]=b,d(this.heap,this.weightFunc,0)),a},e.prototype.remove=function(a){for(var b=this.heap.length,e=0;b>e;e++)if(angular.equals(this.heap[e],a)){var f=this.heap[e],g=this.heap.pop();return e!==b-1&&(this.heap[e]=g,c(this.heap,this.weightFunc,e),d(this.heap,this.weightFunc,e)),f}return null},e.prototype.removeAll=function(){this.heap=[]},e.prototype.size=function(){return this.heap.length},b.exports={DSBinaryHeapProvider:f,DSBinaryHeap:e}},{}],2:[function(a,b){b.exports=function(){var a=this;clearInterval(a.$$cacheFlushIntervalId),clearInterval(a.$$recycleFreqId),a.removeAll(),a.$$storage&&(a.$$storage().removeItem(a.$$prefix+".keys"),a.$$storage().removeItem(a.$$prefix)),a.$$storage=null,a.$$data=null,a.$$lruHeap=null,a.$$expiresHeap=null,a.$$prefix=null}},{}],3:[function(a,b){var c=a("../utils");b.exports=function(a,b){var d=this;if(angular.isArray(a)){var e=a,f=[];return angular.forEach(e,function(a){var c=d.get(a,b);null!==c&&void 0!==c&&f.push(c)}),f}if(a=c.stringifyNumber(a),!d.$$disabled){if(b=b||{},!angular.isString(a))throw angular.$$minErr("ng")("areq","Expected key to be a string! Found: {0}.",typeof a);if(b&&!angular.isObject(b))throw angular.$$minErr("ng")("areq","Expected options to be an object! Found: {0}.",typeof b);if(b.onExpire&&!angular.isFunction(b.onExpire))throw angular.$$minErr("ng")("areq","Expected options.onExpire to be a function! Found: {0}.",typeof b.onExpire);var g;if(d.$$storage){if(d.$$promises[a])return d.$$promises[a];var h=d.$$storage().getItem(d.$$prefix+".data."+a);if(!h)return;g=angular.fromJson(h)}else{if(!(a in d.$$data))return;g=d.$$data[a]}var i=g.value,j=(new Date).getTime();return d.$$storage?(d.$$lruHeap.remove({key:a,accessed:g.accessed}),g.accessed=j,d.$$lruHeap.push({key:a,accessed:j})):(d.$$lruHeap.remove(g),g.accessed=j,d.$$lruHeap.push(g)),"passive"===d.$$deleteOnExpire&&"expires"in g&&g.expires<j?(d.remove(a),d.$$onExpire?d.$$onExpire(a,g.value,b.onExpire):b.onExpire&&b.onExpire(a,g.value),i=void 0):d.$$storage&&d.$$storage().setItem(d.$$prefix+".data."+a,JSON.stringify(g)),i}}},{"../utils":21}],4:[function(a,b){function c(a,b){var c=this;if(!angular.isString(a))throw angular.$$minErr("ng")("areq","Expected storageMode to be a string! Found: {0}.",typeof a);if("memory"!==a&&"localStorage"!==a&&"sessionStorage"!==a)throw angular.$$minErr("ng")("areq",'Expected storageMode to be "memory", "localStorage" or "sessionStorage"! Found: {0}.',a);if(c.$$storageMode=a,b){if(!angular.isObject(b))throw angular.$$minErr("ng")("areq","Expected storageImpl to be an object! Found: {0}.",typeof b);if(!("setItem"in b&&"function"==typeof b.setItem))throw angular.$$minErr("ng")("areq",'Expected storageImpl to implement "setItem(key, value)"! Found: {0}.',typeof b.setItem);if(!("getItem"in b&&"function"==typeof b.getItem))throw angular.$$minErr("ng")("areq",'Expected storageImpl to implement "getItem(key)"! Found: {0}.',typeof b.getItem);if(!("removeItem"in b)||"function"!=typeof b.removeItem)throw angular.$$minErr("ng")("areq",'Expected storageImpl to implement "removeItem(key)"! Found: {0}.',typeof b.removeItem);c.$$storage=function(){return b}}else if("localStorage"===c.$$storageMode)try{localStorage.setItem("angular-cache","angular-cache"),localStorage.removeItem("angular-cache"),c.$$storage=function(){return localStorage}}catch(d){delete c.$$storage,c.$$storageMode="memory"}else if("sessionStorage"===c.$$storageMode)try{sessionStorage.setItem("angular-cache","angular-cache"),sessionStorage.removeItem("angular-cache"),c.$$storage=function(){return sessionStorage}}catch(d){delete c.$$storage,c.$$storageMode="memory"}}function d(a,b){var c=this;if(a=a||{},b=!!b,!angular.isObject(a))throw angular.$$minErr("ng")("areq","Expected cacheOptions to be an object! Found: {0}.",typeof a);"disabled"in a?c.$$disabled=!!a.disabled:b&&delete c.$$disabled,"storeOnResolve"in a?c.$$storeOnResolve=!!a.storeOnResolve:b&&(c.$$storeOnResolve=!1),"storeOnReject"in a?c.$$storeOnReject=!!a.storeOnReject:b&&(c.$$storeOnReject=!1),"capacity"in a?c.setCapacity(a.capacity):b&&c.setCapacity(null),"deleteOnExpire"in a?c.setDeleteOnExpire(a.deleteOnExpire):b&&c.setDeleteOnExpire(null),"maxAge"in a?c.setMaxAge(a.maxAge):b&&c.setMaxAge(null),"recycleFreq"in a?c.setRecycleFreq(a.recycleFreq):b&&c.setRecycleFreq(null),"cacheFlushInterval"in a?c.setCacheFlushInterval(a.cacheFlushInterval):b&&c.setCacheFlushInterval(null),"onExpire"in a?c.setOnExpire(a.onExpire):b&&c.setOnExpire(null)}function e(a,b){var e=this;e.$$data={},e.$$promises={},e.$$id=a,e.$$storage=null,e.$$expiresHeap=new g(function(a){return a.expires}),e.$$lruHeap=new g(function(a){return a.accessed}),b=b||{},"storageMode"in b&&c.apply(e,[b.storageMode,b.storageImpl]),"storagePrefix"in b&&(e.$$storagePrefix=b.storagePrefix),e.$$prefix=e.$$storagePrefix+a,d.apply(e,[b,!0])}var f=a("../defaults"),g=a("../DSBinaryHeap").DSBinaryHeap;for(var h in f.defaults)e.prototype["$$"+h]=f.defaults[h];e.prototype.setOptions=d,e.prototype.setCapacity=a("./setCapacity"),e.prototype.setDeleteOnExpire=a("./setDeleteOnExpire"),e.prototype.setMaxAge=a("./setMaxAge"),e.prototype.setRecycleFreq=a("./setRecycleFreq"),e.prototype.setCacheFlushInterval=a("./setCacheFlushInterval"),e.prototype.setOnExpire=a("./setOnExpire"),e.prototype.put=a("./put"),e.prototype.get=a("./get"),e.prototype.remove=a("./remove"),e.prototype.removeAll=a("./removeAll"),e.prototype.removeExpired=a("./removeExpired"),e.prototype.destroy=a("./destroy"),e.prototype.info=a("./info"),e.prototype.keySet=a("./keySet"),e.prototype.keys=a("./keys"),e.prototype.disable=function(){this.$$disabled=!0},e.prototype.enable=function(){delete this.$$disabled},e.prototype.touch=function(a){var b=this;if(a){var c=b.get(a,{onExpire:function(a,c){b.put(a,c)}});c&&b.put(a,c)}else for(var d=b.keys(),e=0;e<d.length;e++)b.touch(d[e])},b.exports=e},{"../DSBinaryHeap":1,"../defaults":19,"./destroy":2,"./get":3,"./info":5,"./keySet":6,"./keys":7,"./put":8,"./remove":9,"./removeAll":10,"./removeExpired":11,"./setCacheFlushInterval":12,"./setCapacity":13,"./setDeleteOnExpire":14,"./setMaxAge":15,"./setOnExpire":16,"./setRecycleFreq":17}],5:[function(a,b){b.exports=function(a){var b=this;if(a){var c;if(b.$$storage){var d=b.$$storage().getItem(b.$$prefix+".data."+a);return d?(c=angular.fromJson(d),{created:c.created,accessed:c.accessed,expires:c.expires,isExpired:(new Date).getTime()-c.created>b.$$maxAge}):void 0}return a in b.$$data?(c=b.$$data[a],{created:c.created,accessed:c.accessed,expires:c.expires,isExpired:(new Date).getTime()-c.created>b.$$maxAge}):void 0}return{id:b.$$id,capacity:b.$$capacity,maxAge:b.$$maxAge,deleteOnExpire:b.$$deleteOnExpire,onExpire:b.$$onExpire,cacheFlushInterval:b.$$cacheFlushInterval,recycleFreq:b.$$recycleFreq,storageMode:b.$$storageMode,storageImpl:b.$$storage?b.$$storage():void 0,disabled:b.$$disabled,size:b.$$lruHeap&&b.$$lruHeap.size()||0}}},{}],6:[function(a,b){var c=a("../utils");b.exports=function(){var a=this;if(a.$$storage){var b=a.$$storage().getItem(a.$$prefix+".keys"),d={};if(b)for(var e=angular.fromJson(b),f=0;f<e.length;f++)d[e[f]]=e[f];return d}return c.keySet(a.$$data)}},{"../utils":21}],7:[function(a,b){var c=a("../utils");b.exports=function(){var a=this;if(a.$$storage){var b=a.$$storage().getItem(a.$$prefix+".keys");return b?angular.fromJson(b):[]}return c.keys(a.$$data)}},{"../utils":21}],8:[function(a,b){function c(a){return a&&"function"==typeof a.then}var d=a("../utils");b.exports=function(a,b,e){function f(b,c){return function(d){return b&&(delete g.$$promises[a],angular.isObject(d)&&"status"in d&&"data"in d?(d=[d.status,d.data,d.headers(),d.statusText],g.put(a,d)):g.put(a,d)),c?g.$q.reject(d):d}}e=e||{};var g=this,h="storeOnResolve"in e?!!e.storeOnResolve:g.$$storeOnResolve,i="storeOnReject"in e?!!e.storeOnReject:g.$$storeOnReject;if(!g.$$disabled&&null!==b&&void 0!==b){if(a=d.stringifyNumber(a),!angular.isString(a))throw angular.$$minErr("ng")("areq","Expected key to be a string! Found: {0}.",typeof a);var j=(new Date).getTime(),k={key:a,value:c(b)?b.then(f(h,!1),f(i,!0)):b,created:j,accessed:j};if(k.expires=k.created+g.$$maxAge,g.$$storage){if(c(k.value))return g.$$promises[a]=k.value,g.$$promises[a];var l=g.$$storage().getItem(g.$$prefix+".keys"),m=l?angular.fromJson(l):[],n=g.$$storage().getItem(g.$$prefix+".data."+a);n&&g.remove(a),g.$$expiresHeap.push({key:a,expires:k.expires}),g.$$lruHeap.push({key:a,accessed:k.accessed}),g.$$storage().setItem(g.$$prefix+".data."+a,JSON.stringify(k));for(var o=!1,p=0;p<m.length;p++)if(m[p]===a){o=!0;break}o||m.push(a),g.$$storage().setItem(g.$$prefix+".keys",JSON.stringify(m))}else g.$$data[a]&&g.remove(a),g.$$expiresHeap.push(k),g.$$lruHeap.push(k),g.$$data[a]=k,delete g.$$promises[a];return g.$$lruHeap.size()>g.$$capacity&&g.remove(g.$$lruHeap.peek().key),b}}},{"../utils":21}],9:[function(a,b){b.exports=function(a){var b=this;if(a+="",delete b.$$promises[a],!b.$$storage){var c=b.$$data[a]?b.$$data[a].value:void 0;return b.$$lruHeap.remove(b.$$data[a]),b.$$expiresHeap.remove(b.$$data[a]),b.$$data[a]=null,delete b.$$data[a],c}var d=b.$$storage().getItem(b.$$prefix+".data."+a);if(d){var e=angular.fromJson(d);b.$$lruHeap.remove({key:a,accessed:e.accessed}),b.$$expiresHeap.remove({key:a,expires:e.expires}),b.$$storage().removeItem(b.$$prefix+".data."+a);var f=b.$$storage().getItem(b.$$prefix+".keys"),g=f?angular.fromJson(f):[],h=g.indexOf(a);return h>=0&&g.splice(h,1),b.$$storage().setItem(b.$$prefix+".keys",JSON.stringify(g)),e.value}}},{}],10:[function(a,b){b.exports=function(){var a=this;if(a.$$storage){a.$$lruHeap.removeAll(),a.$$expiresHeap.removeAll();var b=a.$$storage().getItem(a.$$prefix+".keys");if(b)for(var c=angular.fromJson(b),d=0;d<c.length;d++)a.remove(c[d]);a.$$storage().setItem(a.$$prefix+".keys",JSON.stringify([]))}else{a.$$lruHeap.removeAll(),a.$$expiresHeap.removeAll();for(var e in a.$$data)a.$$data[e]=null;a.$$data={}}}},{}],11:[function(a,b){b.exports=function(){for(var a,b,c=this,d=(new Date).getTime(),e={};(b=c.$$expiresHeap.peek())&&b.expires<d;)e[b.key]=b.value?b.value:null,c.$$expiresHeap.pop();if(c.$$storage)for(a in e){var f=c.$$storage().getItem(c.$$prefix+".data."+a);f&&(e[a]=angular.fromJson(f).value,c.remove(a))}else for(a in e)c.remove(a);if(c.$$onExpire)for(a in e)c.$$onExpire(a,e[a]);return e}},{}],12:[function(a,b){b.exports=function(a){var b=this;if(null===a)delete b.$$cacheFlushInterval;else{if(!angular.isNumber(a))throw angular.$$minErr("ng")("areq","Expected cacheFlushInterval to be a number! Found: {0}.",typeof a);if(0>a)throw angular.$$minErr("ng")("areq","Expected cacheFlushInterval to be greater than zero! Found: {0}.",a);a!==b.$$cacheFlushInterval&&(b.$$cacheFlushInterval=a,clearInterval(b.$$cacheFlushIntervalId),function(a){a.$$cacheFlushIntervalId=setInterval(function(){a.removeAll()},a.$$cacheFlushInterval)}(b))}}},{}],13:[function(a,b){b.exports=function(a){var b=this;if(null===a)delete b.$$capacity;else{if(!angular.isNumber(a))throw angular.$$minErr("ng")("areq","Expected capacity to be a number! Found: {0}.",typeof a);if(0>a)throw angular.$$minErr("ng")("areq","Expected capacity to be greater than zero! Found: {0}.",a);b.$$capacity=a}for(var c={};b.$$lruHeap.size()>b.$$capacity;)c[b.$$lruHeap.peek().key]=b.remove(b.$$lruHeap.peek().key);return c}},{}],14:[function(a,b){b.exports=function(a){var b=this;if(null===a)delete b.$$deleteOnExpire;else{if(!angular.isString(a))throw angular.$$minErr("ng")("areq","Expected deleteOnExpire to be a string! Found: {0}.",typeof a);if("none"!==a&&"passive"!==a&&"aggressive"!==a)throw angular.$$minErr("ng")("areq",'Expected deleteOnExpire to be "none", "passive" or "aggressive"! Found: {0}.',a);b.$$deleteOnExpire=a}b.setRecycleFreq(b.$$recycleFreq)}},{}],15:[function(a,b){var c=a("../utils");b.exports=function(a){var b=this;if(null===a)delete b.$$maxAge;else{if(!angular.isNumber(a))throw angular.$$minErr("ng")("areq","Expected maxAge to be a number! Found: {0}.",typeof a);if(0>a)throw angular.$$minErr("ng")("areq","Expected maxAge to be greater than zero! Found: {0}.",a);b.$$maxAge=a}var d,e,f;if(b.$$expiresHeap.removeAll(),b.$$storage){var g=b.$$storage().getItem(b.$$prefix+".keys");for(e=g?angular.fromJson(g):[],d=0;d<e.length;d++){f=e[d];var h=b.$$storage().getItem(b.$$prefix+".data."+f);if(h){var i=angular.fromJson(h);i.expires=b.$$maxAge===Number.MAX_VALUE?Number.MAX_VALUE:i.created+b.$$maxAge,b.$$expiresHeap.push({key:f,expires:i.expires})}}}else for(e=c.keys(b.$$data),d=0;d<e.length;d++)f=e[d],b.$$data[f].expires=b.$$maxAge===Number.MAX_VALUE?Number.MAX_VALUE:b.$$data[f].created+b.$$maxAge,b.$$expiresHeap.push(b.$$data[f]);return"aggressive"===b.$$deleteOnExpire?b.removeExpired():{}}},{"../utils":21}],16:[function(a,b){b.exports=function(a){if(null===a)delete this.$$onExpire;else{if(!angular.isFunction(a))throw angular.$$minErr("ng")("areq","Expected onExpire to be a function! Found: {0}.",typeof a);this.$$onExpire=a}}},{}],17:[function(a,b){b.exports=function(a){var b=this;if(null===a)delete b.$$recycleFreq;else{if(!angular.isNumber(a))throw angular.$$minErr("ng")("areq","Expected recycleFreq to be a number! Found: {0}.",typeof a);if(0>a)throw angular.$$minErr("ng")("areq","Expected recycleFreq to be greater than zero! Found: {0}.",a);b.$$recycleFreq=a}clearInterval(b.$$recycleFreqId),"aggressive"===b.$$deleteOnExpire?!function(a){a.$$recycleFreqId=setInterval(function(){a.removeExpired()},a.$$recycleFreq)}(b):delete b.$$recycleFreqId}},{}],18:[function(a,b){function c(){var a=this,b=new d.Config;a.version=f,a.setCacheDefaults=function(a){if(a=a||{},!angular.isObject(a))throw angular.$$minErr("ng")("areq","Expected options to be an object! Found: {0}.",typeof a);for(var c in d.defaults)c in a&&(b[c]=a[c]);"disabled"in a&&(b.$$disabled=!!a.disabled)},a.$get=["$q",function(a){function c(a){var b,c=[];for(b in a)a.hasOwnProperty(b)&&c.push(b);return c}function g(c,d){if(c in i)throw angular.$$minErr("$cacheFactory")("iid","CacheId '{0}' is already taken!",c);if(!angular.isString(c))throw angular.$$minErr("ng")("areq","Expected cacheId to be a string! Found: {0}.",typeof c);return i[c]=new e(c,angular.extend({},b,d)),i[c].destroy=function(){this.constructor.prototype.destroy.call(this),delete i[this.$$id]},i[c].$q=a,i[c]}function h(a,b){return g(a,b)}var i={};return h.createCache=g,h.version=f,h.info=function(){for(var a=c(i),e={size:a.length,caches:{}},f=0;f<a.length;f++){var g=a[f];e.caches[g]=i[g].info()}var h=e.cacheDefaults=angular.extend({},b);for(var j in d.defaults)j in h||(h[j]=b["$$"+j]);return e},h.get=function(a){if(!angular.isString(a))throw angular.$$minErr("ng")("areq","Expected cacheId to be a string! Found: {0}.",typeof a);return i[a]},h.keySet=function(){var a,b={};for(a in i)i.hasOwnProperty(a)&&(b[a]=a);return b},h.keys=function(){return c(i)},h.destroyAll=function(){for(var a in i)i[a].destroy();i={}},h.clearAll=function(){for(var a in i)i[a].removeAll()},h.enableAll=function(){for(var a in i)i[a].$$disabled=!1},h.disableAll=function(){for(var a in i)i[a].$$disabled=!0},h}]}var d=a("../defaults"),e=a("../DSCache"),f="3.2.4";b.exports=c},{"../DSCache":4,"../defaults":19}],19:[function(a,b){function c(){}var d={capacity:Number.MAX_VALUE,maxAge:Number.MAX_VALUE,deleteOnExpire:"none",onExpire:null,cacheFlushInterval:null,recycleFreq:1e3,storageMode:"memory",storageImpl:null,disabled:!1,storagePrefix:"angular-cache.caches.",storeOnResolve:!1,storeOnReject:!1};for(var e in d)c.prototype["$$"+e]=d[e];b.exports={Config:c,defaults:d}},{}],20:[function(a){!function(b,c){"use strict";c.$$minErr=c.$$minErr||function(a){return function(){var b,d,e=arguments[0],f="["+(a?a+":":"")+e+"] ",g=arguments[1],h=arguments,i=function(a){return"function"==typeof a?a.toString().replace(/ \{[\s\S]*$/,""):"undefined"==typeof a?"undefined":"string"!=typeof a?JSON.stringify(a):a};for(b=f+g.replace(/\{\d+\}/g,function(a){var b,d=+a.slice(1,-1);return d+2<h.length?(b=h[d+2],"function"==typeof b?b.toString().replace(/ ?\{[\s\S]*$/,""):"undefined"==typeof b?"undefined":"string"!=typeof b?c.toJson(b):b):a}),b=b+"\nhttp://errors.angularjs.org/"+c.version.full+"/"+(a?a+"/":"")+e,d=2;d<arguments.length;d++)b=b+(2==d?"?":"&")+"p"+(d-2)+"="+encodeURIComponent(i(arguments[d]));return new Error(b)}},c.module("angular-data.DSBinaryHeap",[]).provider("DSBinaryHeap",a("./DSBinaryHeap").DSBinaryHeapProvider),c.module("angular-data.DSCacheFactory",["ng","angular-data.DSBinaryHeap"]).provider("DSCacheFactory",a("./DSCacheFactory"))}(window,window.angular)},{"./DSBinaryHeap":1,"./DSCacheFactory":18}],21:[function(a,b){b.exports={stringifyNumber:function(a){return angular.isNumber(a)?a.toString():a},keySet:function(a){var b,c={};for(b in a)a.hasOwnProperty(b)&&(c[b]=b);return c},keys:function(a){var b,c=[];for(b in a)a.hasOwnProperty(b)&&c.push(b);return c}}},{}]},{},[20]);
!function(a,b){"object"==typeof exports&&"object"==typeof module?module.exports=b(require("angular")):"function"==typeof define&&define.amd?define(["angular"],b):"object"==typeof exports?exports.angularCacheModuleName=b(require("angular")):a.angularCacheModuleName=b(a.angular)}(this,function(a){return function(a){function b(d){if(c[d])return c[d].exports;var e=c[d]={exports:{},id:d,loaded:!1};return a[d].call(e.exports,e,e.exports,b),e.loaded=!0,e.exports}var c={};return b.m=a,b.c=c,b.p="",b(0)}([function(a,b,c){var d=function(a){return a&&a.__esModule?a["default"]:a},e=function(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")},f=d(c(1)),g=d(c(2)),h=function(a){var b=[],c=void 0;for(c in a)a.hasOwnProperty(c)&&b.push(c);return b},i=function(a){return a&&"function"==typeof a.then},j=function(a){return f.isNumber(a)?a.toString():a},k=function(a){var b,c={};for(b in a)a.hasOwnProperty(b)&&(c[b]=b);return c},l=function n(){e(this,n),this.$get=function(){return g}},m=function o(){var a=this;e(this,o);var b=this.defaults={capacity:Number.MAX_VALUE,maxAge:Number.MAX_VALUE,deleteOnExpire:"none",onExpire:null,cacheFlushInterval:null,recycleFreq:1e3,storageMode:"memory",storageImpl:null,disabled:!1,storagePrefix:"angular-cache.caches.",storeOnResolve:!1,storeOnReject:!1};this.$get=["$q",function(c){function d(a,b){return l(a,b)}var e={},l=function(a,d){if(a in e)throw new Error(""+a+" already exists!");if(!f.isString(a))throw new Error("cacheId must be a string!");var l=e[a]={$$id:a,$$data:{},$$promises:{},$$storage:null,$$expiresHeap:new g(function(a){return a.expires}),$$lruHeap:new g(function(a){return a.accessed}),destroy:function(){clearInterval(this.$$cacheFlushIntervalId),clearInterval(this.$$recycleFreqId),this.removeAll(),this.$$storage&&(this.$$storage().removeItem(""+this.$$prefix+".keys"),this.$$storage().removeItem(this.$$prefix)),this.$$storage=null,this.$$data=null,this.$$lruHeap=null,this.$$expiresHeap=null,this.$$prefix=null,delete e[this.$$id]},disable:function(){this.$$disabled=!0},enable:function(){delete this.$$disabled},get:function(a,b){var c=this;if(f.isArray(a)){var d=function(){var d=a,e=[];return f.forEach(d,function(a){var d=c.get(a,b);null!==d&&void 0!==d&&e.push(d)}),{v:e}}();if("object"==typeof d)return d.v}else if(a=j(a),this.$$disabled)return;if(b=b||{},!f.isString(a))throw new Error("key must be a string!");if(b&&!f.isObject(b))throw new Error("options must be an object!");if(b.onExpire&&!f.isFunction(b.onExpire))throw new Error("options.onExpire must be a function!");var e=void 0;if(this.$$storage){if(this.$$promises[a])return this.$$promises[a];var g=this.$$storage().getItem(""+this.$$prefix+".data."+a);if(!g)return;e=f.fromJson(g)}else{if(!(a in this.$$data))return;e=this.$$data[a]}var h=e.value,i=(new Date).getTime();return this.$$storage?(this.$$lruHeap.remove({key:a,accessed:e.accessed}),e.accessed=i,this.$$lruHeap.push({key:a,accessed:i})):(this.$$lruHeap.remove(e),e.accessed=i,this.$$lruHeap.push(e)),"passive"===this.$$deleteOnExpire&&"expires"in e&&e.expires<i?(this.remove(a),this.$$onExpire?this.$$onExpire.call(this,a,e.value,b.onExpire):b.onExpire&&b.onExpire.call(this,a,e.value),h=void 0):this.$$storage&&this.$$storage().setItem(""+this.$$prefix+".data."+a,JSON.stringify(e)),h},info:function(a){if(a){var b=void 0;if(this.$$storage){var c=this.$$storage().getItem(""+this.$$prefix+".data."+a);return c?(b=f.fromJson(c),{created:b.created,accessed:b.accessed,expires:b.expires,isExpired:(new Date).getTime()-b.created>this.$$maxAge}):void 0}return a in this.$$data?(b=this.$$data[a],{created:b.created,accessed:b.accessed,expires:b.expires,isExpired:(new Date).getTime()-b.created>this.$$maxAge}):void 0}return{id:this.$$id,capacity:this.$$capacity,maxAge:this.$$maxAge,deleteOnExpire:this.$$deleteOnExpire,onExpire:this.$$onExpire,cacheFlushInterval:this.$$cacheFlushInterval,recycleFreq:this.$$recycleFreq,storageMode:this.$$storageMode,storageImpl:this.$$storage?this.$$storage():void 0,disabled:!!this.$$disabled,size:this.$$lruHeap&&this.$$lruHeap.size()||0}},keys:function(){if(this.$$storage){var a=this.$$storage().getItem(""+this.$$prefix+".keys");return a?f.fromJson(a):[]}return h(this.$$data)},keySet:function(){if(this.$$storage){var a=this.$$storage().getItem(""+this.$$prefix+".keys"),b={};if(a)for(var c=f.fromJson(a),d=0;d<c.length;d++)b[c[d]]=c[d];return b}return k(this.$$data)},put:function(a,b,d){var e=this;d=d||{};var g="storeOnResolve"in d?!!d.storeOnResolve:this.$$storeOnResolve,h="storeOnReject"in d?!!d.storeOnReject:this.$$storeOnReject,k=function(b,d){return function(g){return b&&(delete e.$$promises[a],f.isObject(g)&&"status"in g&&"data"in g?(g=[g.status,g.data,g.headers(),g.statusText],e.put(a,g)):e.put(a,g)),d?c.reject(g):g}};if(!this.$$disabled&&null!==b&&void 0!==b){if(a=j(a),!f.isString(a))throw new Error("key must be a string!");var l=(new Date).getTime(),m={key:a,value:i(b)?b.then(k(g,!1),k(h,!0)):b,created:l,accessed:l};if(m.expires=m.created+this.$$maxAge,this.$$storage){if(i(m.value))return this.$$promises[a]=m.value,this.$$promises[a];var n=this.$$storage().getItem(""+this.$$prefix+".keys"),o=n?f.fromJson(n):[],p=this.$$storage().getItem(""+this.$$prefix+".data."+a);p&&this.remove(a),this.$$expiresHeap.push({key:a,expires:m.expires}),this.$$lruHeap.push({key:a,accessed:m.accessed}),this.$$storage().setItem(""+this.$$prefix+".data."+a,JSON.stringify(m));for(var q=!1,r=0;r<o.length;r++)if(o[r]===a){q=!0;break}q||o.push(a),this.$$storage().setItem(""+this.$$prefix+".keys",JSON.stringify(o))}else this.$$data[a]&&this.remove(a),this.$$expiresHeap.push(m),this.$$lruHeap.push(m),this.$$data[a]=m,delete this.$$promises[a];return this.$$lruHeap.size()>this.$$capacity&&this.remove(this.$$lruHeap.peek().key),b}},remove:function(a){if(a+="",delete this.$$promises[a],!this.$$storage){var b=this.$$data[a]?this.$$data[a].value:void 0;return this.$$lruHeap.remove(this.$$data[a]),this.$$expiresHeap.remove(this.$$data[a]),this.$$data[a]=null,delete this.$$data[a],b}var c=this.$$storage().getItem(""+this.$$prefix+".data."+a);if(c){var d=f.fromJson(c);this.$$lruHeap.remove({key:a,accessed:d.accessed}),this.$$expiresHeap.remove({key:a,expires:d.expires}),this.$$storage().removeItem(""+this.$$prefix+".data."+a);var e=this.$$storage().getItem(""+this.$$prefix+".keys"),g=e?f.fromJson(e):[],h=g.indexOf(a);return h>=0&&g.splice(h,1),this.$$storage().setItem(""+this.$$prefix+".keys",JSON.stringify(g)),d.value}},removeAll:function(){if(this.$$storage){this.$$lruHeap.removeAll(),this.$$expiresHeap.removeAll();var a=this.$$storage().getItem(""+this.$$prefix+".keys");if(a)for(var b=f.fromJson(a),c=0;c<b.length;c++)this.remove(b[c]);this.$$storage().setItem(""+this.$$prefix+".keys",JSON.stringify([]))}else{this.$$lruHeap.removeAll(),this.$$expiresHeap.removeAll();for(var d in this.$$data)this.$$data[d]=null;this.$$data={}}},removeExpired:function(){for(var a=(new Date).getTime(),b={},c=void 0,d=void 0;(d=this.$$expiresHeap.peek())&&d.expires<=a;)b[d.key]=d.value?d.value:null,this.$$expiresHeap.pop();if(this.$$storage)for(c in b){var e=this.$$storage().getItem(""+this.$$prefix+".data."+c);e&&(b[c]=f.fromJson(e).value,this.remove(c))}else for(c in b)this.remove(c);if(this.$$onExpire)for(c in b)this.$$onExpire.call(this,c,b[c]);return b},setCacheFlushInterval:function(a){if(null===a)delete this.$$cacheFlushInterval;else{if(!f.isNumber(a))throw new Error("cacheFlushInterval must be a number!");if(0>a)throw new Error("cacheFlushInterval must be greater than zero!");a!==this.$$cacheFlushInterval&&(this.$$cacheFlushInterval=a,clearInterval(this.$$cacheFlushIntervalId),function(a){a.$$cacheFlushIntervalId=setInterval(function(){a.removeAll()},a.$$cacheFlushInterval)}(this))}},setCapacity:function(a){if(null===a)delete this.$$capacity;else{if(!f.isNumber(a))throw new Error("capacity must be a number!");if(0>a)throw new Error("capacity must be greater than zero!");this.$$capacity=a}for(var b={};this.$$lruHeap.size()>this.$$capacity;)b[this.$$lruHeap.peek().key]=this.remove(this.$$lruHeap.peek().key);return b},setDeleteOnExpire:function(a,b){if(null===a)delete this.$$deleteOnExpire;else{if(!f.isString(a))throw new Error("deleteOnExpire must be a string!");if("none"!==a&&"passive"!==a&&"aggressive"!==a)throw new Error('deleteOnExpire must be "none", "passive" or "aggressive"!');this.$$deleteOnExpire=a}b!==!1&&this.setRecycleFreq(this.$$recycleFreq)},setMaxAge:function(a){if(null===a)this.$$maxAge=Number.MAX_VALUE;else{if(!f.isNumber(a))throw new Error("maxAge must be a number!");if(0>a)throw new Error("maxAge must be greater than zero!");this.$$maxAge=a}var b=void 0,c=void 0,d=void 0;if(this.$$expiresHeap.removeAll(),this.$$storage){var e=this.$$storage().getItem(""+this.$$prefix+".keys");for(c=e?f.fromJson(e):[],b=0;b<c.length;b++){d=c[b];var g=this.$$storage().getItem(""+this.$$prefix+".data."+d);if(g){var i=f.fromJson(g);i.expires=this.$$maxAge===Number.MAX_VALUE?Number.MAX_VALUE:i.created+this.$$maxAge,this.$$expiresHeap.push({key:d,expires:i.expires})}}}else for(c=h(this.$$data),b=0;b<c.length;b++)d=c[b],this.$$data[d].expires=this.$$maxAge===Number.MAX_VALUE?Number.MAX_VALUE:this.$$data[d].created+this.$$maxAge,this.$$expiresHeap.push(this.$$data[d]);return"aggressive"===this.$$deleteOnExpire?this.removeExpired():{}},setOnExpire:function(a){if(null===a)delete this.$$onExpire;else{if(!f.isFunction(a))throw new Error("onExpire must be a function!");this.$$onExpire=a}},setOptions:function(a,c){if(a=a||{},c=!!c,!f.isObject(a))throw new Error("cacheOptions must be an object!");"storagePrefix"in a?this.$$storagePrefix=!!a.storagePrefix:c&&(this.$$storagePrefix=b.storagePrefix),this.$$prefix=this.$$storagePrefix+this.$$id,"disabled"in a?this.$$disabled=!!a.disabled:c&&(this.$$disabled=b.disabled),"storageMode"in a||"storageImpl"in a?this.setStorageMode(a.storageMode,a.storageImpl):c&&this.setStorageMode(b.storageMode,b.storageImpl),"storeOnResolve"in a?this.$$storeOnResolve=!!a.storeOnResolve:c&&(this.$$storeOnResolve=b.storeOnResolve),"storeOnReject"in a?this.$$storeOnReject=!!a.storeOnReject:c&&(this.$$storeOnReject=b.storeOnReject),"capacity"in a?this.setCapacity(a.capacity):c&&this.setCapacity(b.capacity),"deleteOnExpire"in a?this.setDeleteOnExpire(a.deleteOnExpire,!1):c&&this.setDeleteOnExpire(b.deleteOnExpire,!1),"maxAge"in a?this.setMaxAge(a.maxAge):c&&this.setMaxAge(b.maxAge),"recycleFreq"in a?this.setRecycleFreq(a.recycleFreq):c&&this.setRecycleFreq(b.recycleFreq),"cacheFlushInterval"in a?this.setCacheFlushInterval(a.cacheFlushInterval):c&&this.setCacheFlushInterval(b.cacheFlushInterval),"onExpire"in a?this.setOnExpire(a.onExpire):c&&this.setOnExpire(b.onExpire)},setRecycleFreq:function(a){if(null===a)delete this.$$recycleFreq;else{if(!f.isNumber(a))throw new Error("recycleFreq must be a number!");if(0>a)throw new Error("recycleFreq must be greater than zero!");this.$$recycleFreq=a}clearInterval(this.$$recycleFreqId),"aggressive"===this.$$deleteOnExpire?!function(a){a.$$recycleFreqId=setInterval(function(){a.removeExpired()},a.$$recycleFreq)}(this):delete this.$$recycleFreqId},setStorageMode:function(a,b){if(!f.isString(a))throw new Error("storageMode must be a string!");if("memory"!==a&&"localStorage"!==a&&"sessionStorage"!==a)throw new Error('storageMode must be "memory", "localStorage" or "sessionStorage"!');var c=!1,d={};if("string"==typeof this.$$storageMode&&this.$$storageMode!==a){var e=this.keys();if(e.length){for(var g=0;g<e.length;g++)d[e[g]]=this.get(e[g]);for(g=0;g<e.length;g++)this.remove(e[g]);c=!0}}if(this.$$storageMode=a,b){if(!f.isObject(b))throw new Error("storageImpl must be an object!");if(!("setItem"in b&&"function"==typeof b.setItem))throw new Error('storageImpl must implement "setItem(key, value)"!');if(!("getItem"in b&&"function"==typeof b.getItem))throw new Error('storageImpl must implement "getItem(key)"!');if(!("removeItem"in b)||"function"!=typeof b.removeItem)throw new Error('storageImpl must implement "removeItem(key)"!');this.$$storage=function(){return b}}else if("localStorage"===this.$$storageMode)try{localStorage.setItem("angular-cache","angular-cache"),localStorage.removeItem("angular-cache"),this.$$storage=function(){return localStorage}}catch(h){delete this.$$storage,this.$$storageMode="memory"}else if("sessionStorage"===this.$$storageMode)try{sessionStorage.setItem("angular-cache","angular-cache"),sessionStorage.removeItem("angular-cache"),this.$$storage=function(){return sessionStorage}}catch(h){delete this.$$storage,this.$$storageMode="memory"}if(c)for(var i in d)this.put(i,d[i])},touch:function(a){var b=this;if(a){var c=this.get(a,{onExpire:function(a,c){return b.put(a,c)}});c&&this.put(a,c)}else for(var d=this.keys(),e=0;e<d.length;e++)this.touch(d[e])}};return l.setOptions(d,!0),l};return d.createCache=l,d.info=function(){var b=h(e),c={size:b.length,caches:{}};f.extend(c,a.defaults);for(var d=0;d<b.length;d++){var g=b[d];c.caches[g]=e[g].info()}return c},d.get=function(a){return e[a]},d.keySet=function(){return k(e)},d.keys=function(){return h(e)},d.destroy=function(a){e[a]&&(e[a].destroy(),delete e[a])},d.destroyAll=function(){for(var a in e)e[a].destroy();e={}},d.clearAll=function(){for(var a in e)e[a].removeAll()},d.removeExpiredFromAll=function(){var a={};for(var b in e)a[b]=e[b].removeExpired();return a},d.enableAll=function(){for(var a in e)e[a].$$disabled=!1},d.disableAll=function(){for(var a in e)e[a].$$disabled=!0},d.touchAll=function(){for(var a in e)e[a].touch()},d}]};f.module("angular-cache",[]).provider("BinaryHeap",l).provider("CacheFactory",m),a.exports="angular-cache"},function(b){b.exports=a},function(a,b){!function(b,c){a.exports=c()}(this,function(){return function(a){function b(d){if(c[d])return c[d].exports;var e=c[d]={exports:{},id:d,loaded:!1};return a[d].call(e.exports,e,e.exports,b),e.loaded=!0,e.exports}var c={};return b.m=a,b.c=c,b.p="",b(0)}([function(a){function b(a,b,c){for(var d=a[c],e=b(d);c>0;){var f=Math.floor((c+1)/2)-1,g=a[f];if(e>=b(g))break;a[f]=d,a[c]=g,c=f}}var c=function(){function a(a,b){for(var c in b){var d=b[c];d.configurable=!0,d.value&&(d.writable=!0)}Object.defineProperties(a,b)}return function(b,c,d){return c&&a(b.prototype,c),d&&a(b,d),b}}(),d=function(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")},e=function(a,b,c){for(var d=a.length,e=a[c],f=b(e);;){var g=2*(c+1),h=g-1,i=null;if(d>h){var j=a[h],k=b(j);f>k&&(i=h)}if(d>g){var l=a[g],m=b(l);m<(null===i?f:b(a[h]))&&(i=g)}if(null===i)break;a[c]=a[i],a[i]=e,c=i}},f=function(){function a(b,c){if(d(this,a),b||(b=function(a){return a}),c||(c=function(a,b){return a===b}),"function"!=typeof b)throw new Error('BinaryHeap([weightFunc][, compareFunc]): "weightFunc" must be a function!');if("function"!=typeof c)throw new Error('BinaryHeap([weightFunc][, compareFunc]): "compareFunc" must be a function!');this.weightFunc=b,this.compareFunc=c,this.heap=[]}return c(a,{push:{value:function(a){this.heap.push(a),b(this.heap,this.weightFunc,this.heap.length-1)}},peek:{value:function(){return this.heap[0]}},pop:{value:function(){var a=this.heap[0],b=this.heap.pop();return this.heap.length>0&&(this.heap[0]=b,e(this.heap,this.weightFunc,0)),a}},remove:{value:function(a){for(var c=this.heap.length,d=0;c>d;d++)if(this.compareFunc(this.heap[d],a)){var f=this.heap[d],g=this.heap.pop();return d!==c-1&&(this.heap[d]=g,b(this.heap,this.weightFunc,d),e(this.heap,this.weightFunc,d)),f}return null}},removeAll:{value:function(){this.heap=[]}},size:{value:function(){return this.heap.length}}}),a}();a.exports=f}])})}])});
//# sourceMappingURL=angular-cache.min.map
{
"name": "angular-cache",
"description": "angular-cache is a very useful replacement for Angular's $cacheFactory.",
"version": "3.2.4",
"homepage": "http://jmdobry.github.io/angular-cache",
"main": "src/index.js",
"version": "4.0.0",
"homepage": "http://jmdobry.github.io/angular-cache/",
"main": "dist/angular-cache.js",
"repository": {

@@ -22,20 +22,21 @@ "type": "git",

],
"postinstall": "node node_modules/grunt-cli/bin/grunt build",
"devDependencies": {
"chai": "1.10.0",
"babel-core": "4.7.12",
"babel-loader": "4.2.0",
"chai": "2.1.2",
"grunt": "0.4.5",
"grunt-browserify": "3.2.1",
"grunt-cli": "0.1.13",
"grunt-contrib-clean": "0.6.0",
"grunt-contrib-jshint": "0.10.0",
"grunt-contrib-uglify": "0.6.0",
"grunt-contrib-uglify": "0.8.0",
"grunt-contrib-watch": "0.6.1",
"grunt-docular": "0.1.2",
"grunt-karma": "0.9.0",
"grunt-karma": "0.10.1",
"grunt-karma-coveralls": "2.5.3",
"karma": "0.12.28",
"grunt-webpack": "1.0.8",
"jit-grunt": "0.9.1",
"jshint": "2.6.3",
"jshint-loader": "0.8.3",
"karma": "0.12.31",
"karma-chai": "0.1.0",
"karma-chrome-launcher": "0.1.7",
"karma-coverage": "0.2.7",
"karma-firefox-launcher": "0.1.3",
"karma-firefox-launcher": "0.1.4",
"karma-mocha": "0.1.10",

@@ -45,10 +46,17 @@ "karma-phantomjs-launcher": "0.1.4",

"karma-sinon": "1.0.4",
"load-grunt-tasks": "1.0.0",
"mocha": "2.0.1",
"sinon": "1.12.2",
"time-grunt": "1.0.0"
"mocha": "2.2.1",
"sinon": "1.14.0",
"time-grunt": "1.1.0",
"webpack": "1.7.3",
"webpack-dev-server": "1.7.0"
},
"scripts": {
"test": "grunt ci"
"test": "grunt test"
},
"dependencies": {
"yabh": "1.0.0"
},
"peerDependencies": {
"angular": ">=1.x"
}
}

@@ -1,15 +0,626 @@

## angular-cache [![Bower version](https://badge.fury.io/bo/angular-cache.svg)](http://badge.fury.io/bo/angular-cache) [![npm version](https://badge.fury.io/js/angular-cache.svg)](http://badge.fury.io/js/angular-cache)
## angular-cache [![bower version](https://img.shields.io/bower/v/angular-cache.svg?style=flat-square)](https://www.npmjs.org/package/angular-cache) [![npm version](https://img.shields.io/npm/v/angular-cache.svg?style=flat-square)](https://www.npmjs.org/package/angular-cache) [![Circle CI](https://img.shields.io/circleci/project/jmdobry/angular-cache/master.svg?style=flat-square)](https://circleci.com/gh/jmdobry/angular-cache/tree/master) [![npm downloads](https://img.shields.io/npm/dm/angular-cache.svg?style=flat-square)](https://www.npmjs.org/package/angular-cache) [![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](https://github.com/jmdobry/angular-cache/blob/master/LICENSE)
__A very useful replacement for Angular's $cacheFactory.__
A very useful replacement for Angular's $cacheFactory.
Documentation for 3.x.x can be found at [angular-data.pseudobry.com](http://angular-data.pseudobry.com).
__versions of angular-cache below 4.0.0 have been deprecated, see the [breaking changes](https://github.com/jmdobry/angular-cache/blob/master/CHANGELOG.md) in 4.0.0__
Documentation for 2.x.x can be found at [jmdobry.github.io/angular-cache](http://jmdobry.github.io/angular-cache).
__Latest Release:__ [![Latest Release](https://img.shields.io/github/release/jmdobry/angular-cache.svg?style=flat-square)](https://github.com/jmdobry/angular-cache/releases)
See [TRANSITION.md](https://github.com/jmdobry/angular-cache/blob/master/TRANSITION.md) for upgrading from 2.x.x to 3.x.x.
__Status:__
## License
[![Dependency Status](https://img.shields.io/gemnasium/jmdobry/angular-cache.svg?style=flat-square)](https://gemnasium.com/jmdobry/angular-cache) [![Coverage Status](https://img.shields.io/coveralls/jmdobry/angular-cache/master.svg?style=flat-square)](https://coveralls.io/r/jmdobry/angular-cache?branch=master) [![Codacity](https://img.shields.io/codacy/5e27e21d0c4c4d4cb203d589384aa93a.svg?style=flat-square)](https://www.codacy.com/public/jasondobry/angular-cache/dashboard)
__Supported Browsers:__
[![browsers](https://img.shields.io/badge/Browser-Chrome%2CFirefox%2CSafari%2COpera%2CIE%209%2B%2CiOS%20Safari%207.1%2B%2CAndroid%20Browser%202.3%2B-green.svg?style=flat-square)](https://github.com/jmdobry/angular-cache)
### Table of Contents
- [Quick Start](#quick-start)
- [The Basics](#the-basics)
- [Working with a cache](#working-with-a-cache)
- [Configuration Options](#configuration-options)
- [Using angular-cache with $http](#using-angular-cache-with-http)
- [Using angular-cache with localStorage](#using-angular-cache-with-localstorage)
- [API Reference](#api-reference)
### Quick Start
`bower install --save angular-cache` or `npm install --save angular-cache`.
```js
angular.module('myApp', ['angular-cache'])
.config(function (CacheFactoryProvider) {
angular.extend(CacheFactoryProvider.defaults, { maxAge: 15 * 60 * 1000 });
})
.service('BookService', function (CacheFactory) {
if (!CacheFactory.get('bookCache')) {
// or CacheFactory('bookCache', { ... });
CacheFactory.createCache('bookCache', {
deleteOnExpire: 'aggressive',
recycleFreq: 60000
});
}
var bookCache = CacheFactory.get('bookCache');
return {
findBookById: function (id) {
return $http.get('/api/books/' + id, { cache: bookCache });
}
};
});
```
### The Basics
First, inject `CacheFactory` then create a cache. Let's go:
```js
app.service('myService', function (CacheFactory) {
var profileCache;
// Check to make sure the cache doesn't already exist
if (!CacheFactory.get('profileCache')) {
profileCache = CacheFactory('profileCache');
}
});
```
Let's add some items to the cache:
```js
profileCache.put('/profiles/34', {
name: 'John',
skills: ['programming', 'piano']
});
profileCache.put('/profiles/22', {
name: 'Sally',
skills: ['marketing', 'climbing', 'painting']
});
```
Right now, these items will stay in the cache until a page refresh.
Let's have items which are added to `profileCache` expire after an hour:
```js
profileCache = CacheFactory('profileCache', {
maxAge: 60 * 60 * 1000 // 1 hour
});
```
Perfect. Say we also want the items removed from the cache when they expire:
```js
profileCache = CacheFactory('profileCache', {
maxAge: 60 * 60 * 1000 // 1 hour,
deleteOnExpire: 'aggressive'
});
```
Let's say that when the items do expire, we want to refresh them with new values:
```js
profileCache = CacheFactory('profileCache', {
maxAge: 60 * 60 * 1000 // 1 hour,
deleteOnExpire: 'aggressive',
onExpire: function (key, value) {
$http.get(key).success(function (data) {
profileCache.put(key, data);
});
}
});
```
Or say we want all of our caches to use that configuration as their default:
```js
angular.module('app', ['angular-cache']).config(function (CacheFactoryProvider) {
angular.extend(CacheFactoryProvider.defaults, {
maxAge: 3600000,
deleteOnExpire: 'aggressive',
onExpire: function (key, value) {
var _this = this; // "this" is the cache in which the item expired
$http.get(key).success(function (data) {
_this.put(key, data);
});
}
});
});
```
### Working with a cache
We can retrieve items from a cache like so:
```js
var profile = profileCache.get('/profiles/34');
profile.name; // 'John'
```
And get information about items in the cache:
```js
var info = profileCache.info('/profiles/34');
info.isExpired; // false
// etc.
```
and information about the cache itself:
```
var info = profileCache.info();
info.size; // 2
info.maxAge; // 3600000
info.deleteOnExpire; // 'aggressive'
// etc.
```
Items are easily removed, and we can destroy our cache when we're done with it:
```js
profileCache.remove('/profiles/34');
profileCache.get('/profiles/34'); // undefined
profileCache.destroy();
CacheFactory.get('profileCache'); // undefined
```
### Configuration Options
These options apply to:
- `CacheFactory(cacheId[, options)`
- `CacheFactory.createCache(cacheId[, options])`
- `Cache#setOptions(options[, strict])`
- `Cache#setMaxAge(maxAge)`, `Cache#setOnExpire(onExpire)`, etc.
##### `cacheFlushInterval`
If set, remove all items from a cache on an interval after the given number of milliseconds. Default: `null`.
##### `capacity`
Maximum number of items a cache can hold. Adding more items than the capacity will cause the cache to operate like an LRU cache, removing the least recently used items to stay under capacity. Default: `Number.MAX_VALUE`.
##### `deleteOnExpire`
Determines the behavior of a cache when an item expires. Default: `none`.
Possible values:
- `none` - Cache will do nothing when an item expires.
- `passive` - Cache will do nothing when an item expires. Expired items will remain in the cache until requested, at which point they are removed, and `undefined` is returned.
- `aggressive` - Cache will remove expired items as soon as they are discovered.
##### `disabled`
Determines whether a cache is disabled. Default: `false`.
##### `onExpire`
A callback function to be executed whenever an expired item is removed from a cache when the cache is in `passive` or `aggressive` mode. Will be passed the `key` and `value` of the expired item.
Will be passed a third `done` argument if the cache is in `passive` mode. This allows you to synchronously access the `key` and `value` of the expired item when you make the `Cache#get(key[, options])` call that is the reason the expired item is being removed in the first place. Default: `null`.
##### `maxAge`
The number of milliseconds until a newly inserted item expires. Default: `Number.MAX_VALUE`.
##### `recycleFreq`
Determines how often a cache will scan for expired items when in `aggressive` mode. Default: `1000` (milliseconds).
##### `storageImpl`
Provide a custom storage medium, e.g. a polyfill for `localStorage`. Default: `null`.
Must implement:
- `setItem` - Same API as `localStorage.setItem(key, value)`
- `getItem` - Same API as `localStorage.getItem(key)`
- `removeItem` - Same API as `localStorage.removeItem(key)`
##### `storageMode`
Determines the storage medium used by a cache. Default: `memory`.
Possible values:
- `memory` - Cache will hold data in memory. Data is cleared when the page is refreshed.
- `localStorage` - Cache will hold data in `localStorage` if available. Data is _not_ cleared when the page is refreshed.
- `sessionStorage` - Cache will hold data in `sessionStorage` if available. Data is _not_ cleared when the page is refreshed.
##### `storagePrefix`
Determines the namespace of a cache when `storageMode` is set to `localStorage` or `sessionStorage`. Make it a shorter string to save space. Default: `angular-cache.caches.`.
##### `storeOnReject`
If inserting a promise into a cache, also insert the rejection value if the promise rejects. Default: `false`.
##### storeOnResolve
If inserting a promise into a cache, also insert the resolved value if the promise resolves. Default: `false`.
### Using angular-cache with $http
__Note:__ The downside of letting `$http` handle caching for you is that it caches the responses (in string form) to your requests–not the JavaScript Object parsed from the response body. This means you can't interact with the data in the cache used by `$http`. See below for how to handle the caching yourself, which gives you more control and the ability to interact with the cache (use it as a data store).
Configure `$http` to use a cache created by `CacheFactory` by default:
```js
app.run(function ($http, CacheFactory) {
$http.defaults.cache = CacheFactory('defaultCache', {
maxAge: 15 * 60 * 1000, // Items added to this cache expire after 15 minutes
cacheFlushInterval: 60 * 60 * 1000, // This cache will clear itself every hour
deleteOnExpire: 'aggressive' // Items will be deleted from this cache when they expire
});
});
```
```js
app.service('MyService', function ($http, $q) {
return {
getDataById: function (id) {
var deferred = $q.defer();
var start = new Date().getTime();
$http.get('api/data/' + id, {
cache: true
}).success(function (data) {
console.log('time taken for request: ' + (new Date().getTime() - start) + 'ms');
deferred.resolve(data);
});
return deferred.promise;
}
};
});
```
```js
app.controller('myCtrl', function (MyService) {
MyService.getDataById(1).then(function (data) {
// e.g. "time taken for request: 2375ms"
// Data returned by this next call is already cached.
return MyService.getDataById(1).then(function (data) {
// e.g. "time taken for request: 1ms"
});
});
});
```
Tell $http to use a cache created by CacheFactory for a specific request:
```js
app.service('MyService', function ($q, $http, CacheFactory) {
CacheFactory('dataCache', {
maxAge: 15 * 60 * 1000, // Items added to this cache expire after 15 minutes
cacheFlushInterval: 60 * 60 * 1000, // This cache will clear itself every hour
deleteOnExpire: 'aggressive' // Items will be deleted from this cache when they expire
});
return {
getDataById: function (id) {
var deferred = $q.defer();
var start = new Date().getTime();
$http.get('api/data/' + id, {
cache: CacheFactory.get('dataCache')
}).success(function (data) {
console.log('time taken for request: ' + (new Date().getTime() - start) + 'ms');
deferred.resolve(data);
});
return deferred.promise;
}
};
});
```
```js
app.controller('myCtrl', function (MyService) {
MyService.getDataById(1).then(function (data) {
// e.g. "time taken for request: 2375ms"
// Data returned by this next call is already cached.
return MyService.getDataById(1).then(function (data) {
// e.g. "time taken for request: 1ms"
});
});
});
```
Do your own caching while using the $http service:
```js
app.service('MyService', function ($q, $http, CacheFactory) {
CacheFactory('dataCache', {
maxAge: 15 * 60 * 1000, // Items added to this cache expire after 15 minutes
cacheFlushInterval: 60 * 60 * 1000, // This cache will clear itself every hour
deleteOnExpire: 'aggressive' // Items will be deleted from this cache when they expire
});
return {
getDataById: function (id) {
var deferred = $q.defer();
var start = new Date().getTime();
var dataCache = CacheFactory.get('dataCache');
// Now that control of inserting/removing from the cache is in our hands,
// we can interact with the data in "dataCache" outside of this context,
// e.g. Modify the data after it has been returned from the server and
// save those modifications to the cache.
if (dataCache.get(id)) {
deferred.resolve(dataCache.get(id));
} else {
$http.get('api/data/' + id).success(function (data) {
console.log('time taken for request: ' + (new Date().getTime() - start) + 'ms');
dataCache.put(id, data);
deferred.resolve(data);
});
}
return deferred.promise;
}
};
});
```
```js
app.controller('myCtrl', function (MyService) {
MyService.getDataById(1).then(function (data) {
// e.g. "time taken for request: 2375ms"
// Data returned by this next call is already cached.
return MyService.getDataById(1).then(function (data) {
// e.g. "time taken for request: 1ms"
});
});
});
```
### Using angular-cache with localStorage
```js
app.service('myService', function (CacheFactory) {
// This cache will sync itself with localStorage if it exists, otherwise it won't. Every time the
// browser loads this app, this cache will attempt to initialize itself with any data it had
// already saved to localStorage (or sessionStorage if you used that).
var myAwesomeCache = CacheFactory('myAwesomeCache', {
maxAge: 15 * 60 * 1000, // Items added to this cache expire after 15 minutes.
cacheFlushInterval: 60 * 60 * 1000, // This cache will clear itself every hour.
deleteOnExpire: 'aggressive', // Items will be deleted from this cache right when they expire.
storageMode: 'localStorage' // This cache will use `localStorage`.
});
});
```
Using angular-cache in browsers that DON'T support localStorage:
Option 1 - Do nothing (the cache will just store data in memory)
Option 2 - Create/use a polyfill that provides the global `localStorage` and `sessionStorage` objects. angular-cache will attempt to use these if it finds them.
Option 3 - Tell angular-cache exactly which polyfill to use (also useful if you just want to use your own implementation/wrapper for localStorage):
```js
app.service('myService', function (CacheFactory) {
var localStoragePolyfill = {
getItem: function (key) { ... },
setItem: function (key, value) { ... },
removeItem: function (key) { ... }
};
// Always use the polyfill
var myAwesomeCache = CacheFactory('myAwesomeCache', {
maxAge: 15 * 60 * 1000, // Items added to this cache expire after 15 minutes.
cacheFlushInterval: 60 * 60 * 1000, // This cache will clear itself every hour.
deleteOnExpire: 'aggressive', // Items will be deleted from this cache right when they expire.
storageMode: 'localStorage', // This cache will use `localStorage`.
storageImpl: localStoragePolyfill // angular-cache will use this polyfill instead of looking for localStorage
});
// Conditionally use the polyfill
var options = {
maxAge: 15 * 60 * 1000, // Items added to this cache expire after 15 minutes.
cacheFlushInterval: 60 * 60 * 1000, // This cache will clear itself every hour.
deleteOnExpire: 'aggressive', // Items will be deleted from this cache right when they expire.
storageMode: 'localStorage' // This cache will use `localStorage`.
};
if (!window.localStorage) {
options.storageImpl = localStoragePolyfill;
}
var myAwesomeCache = CacheFactory('myAwesomeCache', options);
});
```
Documentation on the interface that must be implemented by any storageImpl polyfill used by angular-cache can be found on the W3C Recommendation page for webstorage. The interface itself looks like:
```
interface Storage {
readonly attribute unsigned long length;
DOMString? key(unsigned long index);
getter DOMString getItem(DOMString key);
setter creator void setItem(DOMString key, DOMString value);
deleter void removeItem(DOMString key);
void clear();
};
```
angular-cache cares only about these three methods:
- `setItem`
- `getItem`
- `removeItem`
One developer suggested using store.js–a wrapper and polyfill for localStorage. However, store.js has its own API that doesn't match that of the webstorage spec, so if you want to use store.js or any other 3rd-party polyfill then you'll need to create a wrapper for it if it doesn't have the same API as localStorage . For example:
```js
var storeJsToStandard {
getItem: store.get,
setItem: store.set,
removeItem: store.remove
};
CacheFactory('myNewCache', {
storageMode: 'localStorage',
storageImpl: storeJsToStandard
});
```
### API Reference
##### `CacheFactory(cacheId[, options])` & `CacheFactory.createCache(cacheId[, options])`
Create a cache. Cache must not already exist. `cacheId` must be a string. `options` is an optional argument and must be an object. Any options you pass here will override any default options.
```js
var cache = CacheFactory('cache');
var cache2 = CacheFactory.createCache('cache2');
var cache3 = CacheFactory('cache', { maxAge: 900000 });
var cache4 = CacheFactory('cache'); // Error "cache already exists!"
```
##### `CacheFactory.get(cacheId)`
Return the cache with the given `cacheId`.
##### `CacheFactory.info()`
Return an object of key-value pairs, the keys being cache ids and the values being the result of `.info()` being called on each cache.
##### `CacheFactory.keySet()`
Return the ids of all registered caches as an object.
##### `CacheFactory.keys()`
Return the ids of all registered caches as an array.
##### `CacheFactory.destroy(cacheId)`
Destroy the cache with the given `cacheId`.
##### `CacheFactory.destroyAll()`
Destroy all registered caches.
##### `CacheFactory.clearAll()`
Remove all data from all registered caches.
##### `CacheFactory.enableAll()`
Enable all registered caches.
##### `CacheFactory.disableAll()`
Disable all registered caches.
##### `CacheFactory.touchAll()`
Call `.touch()` on all registered caches.
##### `CacheFactory.removeExpiredFromAll()`
Call `.removeExpired()` on all registered caches. Returns a hash of any expired items, keyed by cache id.
##### `Cache#get(key[, options])`
Return the item with the given `key`. `options`, if provided, must be an object.
If the cache is in `passive` mode, then `options.onExpire` can be a function that will be called with the `key` and `value` of the requested item if the requested item is expired, with the `get` call itself returning undefined.
##### `Cache#put(key, value[, options])`
Insert the item with the given `key` and `value` into the cache. `options`, if provided, must be an object.
If inserting a promise, `options.storeOnReject` determines whether to insert the rejection value if the promise rejects (overriding the default `storeOnReject` setting for the cache).
If inserting a promise, `options.storeOnResolve` determines whether to insert the resolved value if the promise resolves (overriding the default `storeOnResolve` setting for the cache).
##### `Cache.remove(key)`
Remove and return the item with the given `key`, if it is in the cache.
##### `Cache.removeAll()`
Remove all items in the cache.
##### `Cache.removeExpired()`
Remove and return all expired items in the cache.
##### `Cache.destroy()`
Completely destroy this cache and its data.
##### `Cache#info([key])`
`Cache#info()` returns an object containing information about the cache.
`Cache#info(key)` returns an object containing information about the item with the given `key`, if the item is in the cache.
##### `Cache#keySet()`
Return the keys of all items in the cache as an object.
##### `Cache#keys()`
Return the keys of all items in the cache as an array.
##### `Cache#enable()`
Enable the cache.
##### `Cache#disable()`
Disable the cache.
##### `Cache#touch([key])`
`Cache#touch()` will "touch" all items in the cache.
`Cache#touch(key)` will "touch" the item with the given `key`.
##### `Cache#setCacheFlushInterval(cacheFlushInterval)`
Set the `cacheFlushInterval` for the cache.
##### `Cache#setCapacity(capacity)`
Set the `capacity` for the cache. Setting this lower than the current item count will result in those items being removed.
##### `Cache#setDeleteOnExpire(deleteOnExpire)`
Set the `deleteOnExpire` for the cache.
##### `Cache#setMaxAge(maxAge)`
Set the `maxAge` for the cache.
##### `Cache#setOnExpire(onExpire)`
Set the `onExpire` for the cache.
##### `Cache#setRecycleFreq(recycleFreq)`
Set the `recycleFreq` for the cache.
##### `Cache#setStorageMode(storageMode)`
Set the `storageMode` for the cache. This will move data from the current storage medium to the new one.
##### `Cache#setOptions(options[, strict])`
Set multiple options for the cache at a time. Setting `strict` to `true` will reset options for the cache that are not specifically set in the `options` hash to `CacheFactoryProvider.defaults`.
### License
[MIT License](https://github.com/jmdobry/angular-cache/blob/master/LICENSE)
Copyright (C) 2013-2014 Jason Dobry
Copyright (C) 2013-2015 Jason Dobry

@@ -16,0 +627,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of

@@ -1,101 +0,850 @@

(function (window, angular, undefined) {
'use strict';
import angular from 'angular';
import BinaryHeap from 'yabh';
angular.$$minErr = angular.$$minErr || function minErr(module) {
return function () {
var code = arguments[0],
prefix = '[' + (module ? module + ':' : '') + code + '] ',
template = arguments[1],
templateArgs = arguments,
stringify = function (obj) {
if (typeof obj === 'function') {
return obj.toString().replace(/ \{[\s\S]*$/, '');
} else if (typeof obj === 'undefined') {
return 'undefined';
} else if (typeof obj !== 'string') {
return JSON.stringify(obj);
}
return obj;
},
message, i;
let _keys = collection => {
let keys = [], key;
for (key in collection) {
if (collection.hasOwnProperty(key)) {
keys.push(key);
}
}
return keys;
};
message = prefix + template.replace(/\{\d+\}/g, function (match) {
var index = +match.slice(1, -1), arg;
let _isPromiseLike = v => {
return v && typeof v.then === 'function';
};
if (index + 2 < templateArgs.length) {
arg = templateArgs[index + 2];
if (typeof arg === 'function') {
return arg.toString().replace(/ ?\{[\s\S]*$/, '');
} else if (typeof arg === 'undefined') {
return 'undefined';
} else if (typeof arg !== 'string') {
return angular.toJson(arg);
}
return arg;
let _stringifyNumber = number => {
if (angular.isNumber(number)) {
return number.toString();
}
return number;
};
let _keySet = collection => {
var keySet = {}, key;
for (key in collection) {
if (collection.hasOwnProperty(key)) {
keySet[key] = key;
}
}
return keySet;
};
class BinaryHeapProvider {
constructor() {
this.$get = () => BinaryHeap;
}
}
class CacheFactoryProvider {
constructor() {
var defaults = this.defaults = {
capacity: Number.MAX_VALUE,
maxAge: Number.MAX_VALUE,
deleteOnExpire: 'none',
onExpire: null,
cacheFlushInterval: null,
recycleFreq: 1000,
storageMode: 'memory',
storageImpl: null,
disabled: false,
storagePrefix: 'angular-cache.caches.',
storeOnResolve: false,
storeOnReject: false
};
this.$get = ['$q', $q => {
let caches = {};
let createCache = (cacheId, options) => {
if (cacheId in caches) {
throw new Error(`${cacheId} already exists!`);
} else if (!angular.isString(cacheId)) {
throw new Error('cacheId must be a string!');
}
return match;
});
message = message + '\nhttp://errors.angularjs.org/' + angular.version.full + '/' +
(module ? module + '/' : '') + code;
for (i = 2; i < arguments.length; i++) {
message = message + (i == 2 ? '?' : '&') + 'p' + (i - 2) + '=' +
encodeURIComponent(stringify(arguments[i]));
let cache = caches[cacheId] = {
$$id: cacheId,
$$data: {},
$$promises: {},
$$storage: null,
$$expiresHeap: new BinaryHeap(x => x.expires),
$$lruHeap: new BinaryHeap(x => x.accessed),
destroy() {
clearInterval(this.$$cacheFlushIntervalId);
clearInterval(this.$$recycleFreqId);
this.removeAll();
if (this.$$storage) {
this.$$storage().removeItem(`${this.$$prefix}.keys`);
this.$$storage().removeItem(this.$$prefix);
}
this.$$storage = null;
this.$$data = null;
this.$$lruHeap = null;
this.$$expiresHeap = null;
this.$$prefix = null;
delete caches[this.$$id];
},
disable() {
this.$$disabled = true;
},
enable() {
delete this.$$disabled;
},
get(key, options) {
if (angular.isArray(key)) {
let keys = key;
let values = [];
angular.forEach(keys, key => {
let value = this.get(key, options);
if (value !== null && value !== undefined) {
values.push(value);
}
});
return values;
} else {
key = _stringifyNumber(key);
if (this.$$disabled) {
return;
}
}
options = options || {};
if (!angular.isString(key)) {
throw new Error('key must be a string!');
} else if (options && !angular.isObject(options)) {
throw new Error('options must be an object!');
} else if (options.onExpire && !angular.isFunction(options.onExpire)) {
throw new Error('options.onExpire must be a function!');
}
let item;
if (this.$$storage) {
if (this.$$promises[key]) {
return this.$$promises[key];
}
let itemJson = this.$$storage().getItem(`${this.$$prefix}.data.${key}`);
if (itemJson) {
item = angular.fromJson(itemJson);
} else {
return;
}
} else {
if (!(key in this.$$data)) {
return;
}
item = this.$$data[key];
}
let value = item.value;
let now = new Date().getTime();
if (this.$$storage) {
this.$$lruHeap.remove({
key: key,
accessed: item.accessed
});
item.accessed = now;
this.$$lruHeap.push({
key: key,
accessed: now
});
} else {
this.$$lruHeap.remove(item);
item.accessed = now;
this.$$lruHeap.push(item);
}
if (this.$$deleteOnExpire === 'passive' && 'expires' in item && item.expires < now) {
this.remove(key);
if (this.$$onExpire) {
this.$$onExpire.call(this, key, item.value, options.onExpire);
} else if (options.onExpire) {
options.onExpire.call(this, key, item.value);
}
value = undefined;
} else if (this.$$storage) {
this.$$storage().setItem(`${this.$$prefix}.data.${key}`, JSON.stringify(item));
}
return value;
},
info(key) {
if (key) {
let item;
if (this.$$storage) {
var itemJson = this.$$storage().getItem(`${this.$$prefix}.data.${key}`);
if (itemJson) {
item = angular.fromJson(itemJson);
return {
created: item.created,
accessed: item.accessed,
expires: item.expires,
isExpired: (new Date().getTime() - item.created) > this.$$maxAge
};
} else {
return undefined;
}
} else {
if (key in this.$$data) {
item = this.$$data[key];
return {
created: item.created,
accessed: item.accessed,
expires: item.expires,
isExpired: (new Date().getTime() - item.created) > this.$$maxAge
};
} else {
return undefined;
}
}
} else {
return {
id: this.$$id,
capacity: this.$$capacity,
maxAge: this.$$maxAge,
deleteOnExpire: this.$$deleteOnExpire,
onExpire: this.$$onExpire,
cacheFlushInterval: this.$$cacheFlushInterval,
recycleFreq: this.$$recycleFreq,
storageMode: this.$$storageMode,
storageImpl: this.$$storage ? this.$$storage() : undefined,
disabled: !!this.$$disabled,
size: this.$$lruHeap && this.$$lruHeap.size() || 0
};
}
},
keys() {
if (this.$$storage) {
let keysJson = this.$$storage().getItem(`${this.$$prefix}.keys`);
if (keysJson) {
return angular.fromJson(keysJson);
} else {
return [];
}
} else {
return _keys(this.$$data);
}
},
keySet() {
if (this.$$storage) {
let keysJson = this.$$storage().getItem(`${this.$$prefix}.keys`);
let kSet = {};
if (keysJson) {
var keys = angular.fromJson(keysJson);
for (var i = 0; i < keys.length; i++) {
kSet[keys[i]] = keys[i];
}
}
return kSet;
} else {
return _keySet(this.$$data);
}
},
put(key, value, options) {
options = options || {};
let storeOnResolve = 'storeOnResolve' in options ? !!options.storeOnResolve : this.$$storeOnResolve;
let storeOnReject = 'storeOnReject' in options ? !!options.storeOnReject : this.$$storeOnReject;
let getHandler = (store, isError) => {
return v => {
if (store) {
delete this.$$promises[key];
if (angular.isObject(v) && 'status' in v && 'data' in v) {
v = [v.status, v.data, v.headers(), v.statusText];
this.put(key, v);
} else {
this.put(key, v);
}
}
if (isError) {
return $q.reject(v);
} else {
return v;
}
};
};
if (this.$$disabled || value === null || value === undefined) {
return;
}
key = _stringifyNumber(key);
if (!angular.isString(key)) {
throw new Error('key must be a string!');
}
var now = new Date().getTime();
var item = {
key: key,
value: _isPromiseLike(value) ? value.then(getHandler(storeOnResolve, false), getHandler(storeOnReject, true)) : value,
created: now,
accessed: now
};
item.expires = item.created + this.$$maxAge;
if (this.$$storage) {
if (_isPromiseLike(item.value)) {
this.$$promises[key] = item.value;
return this.$$promises[key];
}
var keysJson = this.$$storage().getItem(`${this.$$prefix}.keys`);
var keys = keysJson ? angular.fromJson(keysJson) : [];
var itemJson = this.$$storage().getItem(`${this.$$prefix}.data.${key}`);
// Remove existing
if (itemJson) {
this.remove(key);
}
// Add to expires heap
this.$$expiresHeap.push({
key: key,
expires: item.expires
});
// Add to lru heap
this.$$lruHeap.push({
key: key,
accessed: item.accessed
});
// Set item
this.$$storage().setItem(`${this.$$prefix}.data.${key}`, JSON.stringify(item));
var exists = false;
for (var i = 0; i < keys.length; i++) {
if (keys[i] === key) {
exists = true;
break;
}
}
if (!exists) {
keys.push(key);
}
this.$$storage().setItem(`${this.$$prefix}.keys`, JSON.stringify(keys));
} else {
// Remove existing
if (this.$$data[key]) {
this.remove(key);
}
// Add to expires heap
this.$$expiresHeap.push(item);
// Add to lru heap
this.$$lruHeap.push(item);
// Set item
this.$$data[key] = item;
delete this.$$promises[key];
}
// Handle exceeded capacity
if (this.$$lruHeap.size() > this.$$capacity) {
this.remove(this.$$lruHeap.peek().key);
}
return value;
},
remove(key) {
key += '';
delete this.$$promises[key];
if (this.$$storage) {
let itemJson = this.$$storage().getItem(`${this.$$prefix}.data.${key}`);
if (itemJson) {
let item = angular.fromJson(itemJson);
this.$$lruHeap.remove({
key: key,
accessed: item.accessed
});
this.$$expiresHeap.remove({
key: key,
expires: item.expires
});
this.$$storage().removeItem(`${this.$$prefix}.data.${key}`);
let keysJson = this.$$storage().getItem(`${this.$$prefix}.keys`);
let keys = keysJson ? angular.fromJson(keysJson) : [];
let index = keys.indexOf(key);
if (index >= 0) {
keys.splice(index, 1);
}
this.$$storage().setItem(`${this.$$prefix}.keys`, JSON.stringify(keys));
return item.value;
}
} else {
var value = this.$$data[key] ? this.$$data[key].value : undefined;
this.$$lruHeap.remove(this.$$data[key]);
this.$$expiresHeap.remove(this.$$data[key]);
this.$$data[key] = null;
delete this.$$data[key];
return value;
}
},
removeAll() {
if (this.$$storage) {
this.$$lruHeap.removeAll();
this.$$expiresHeap.removeAll();
let keysJson = this.$$storage().getItem(`${this.$$prefix}.keys`);
if (keysJson) {
let keys = angular.fromJson(keysJson);
for (var i = 0; i < keys.length; i++) {
this.remove(keys[i]);
}
}
this.$$storage().setItem(`${this.$$prefix}.keys`, JSON.stringify([]));
} else {
this.$$lruHeap.removeAll();
this.$$expiresHeap.removeAll();
for (var key in this.$$data) {
this.$$data[key] = null;
}
this.$$data = {};
}
},
removeExpired() {
let now = new Date().getTime();
let expired = {};
let key;
let expiredItem;
while ((expiredItem = this.$$expiresHeap.peek()) && expiredItem.expires <= now) {
expired[expiredItem.key] = expiredItem.value ? expiredItem.value : null;
this.$$expiresHeap.pop();
}
if (this.$$storage) {
for (key in expired) {
var itemJson = this.$$storage().getItem(`${this.$$prefix}.data.${key}`);
if (itemJson) {
expired[key] = angular.fromJson(itemJson).value;
this.remove(key);
}
}
} else {
for (key in expired) {
this.remove(key);
}
}
if (this.$$onExpire) {
for (key in expired) {
this.$$onExpire.call(this, key, expired[key]);
}
}
return expired;
},
setCacheFlushInterval(cacheFlushInterval) {
if (cacheFlushInterval === null) {
delete this.$$cacheFlushInterval;
} else if (!angular.isNumber(cacheFlushInterval)) {
throw new Error('cacheFlushInterval must be a number!');
} else if (cacheFlushInterval < 0) {
throw new Error('cacheFlushInterval must be greater than zero!');
} else if (cacheFlushInterval !== this.$$cacheFlushInterval) {
this.$$cacheFlushInterval = cacheFlushInterval;
clearInterval(this.$$cacheFlushIntervalId);
(function (self) {
self.$$cacheFlushIntervalId = setInterval(function () {
self.removeAll();
}, self.$$cacheFlushInterval);
})(this);
}
},
setCapacity(capacity) {
if (capacity === null) {
delete this.$$capacity;
} else if (!angular.isNumber(capacity)) {
throw new Error('capacity must be a number!');
} else if (capacity < 0) {
throw new Error('capacity must be greater than zero!');
} else {
this.$$capacity = capacity;
}
var removed = {};
while (this.$$lruHeap.size() > this.$$capacity) {
removed[this.$$lruHeap.peek().key] = this.remove(this.$$lruHeap.peek().key);
}
return removed;
},
setDeleteOnExpire(deleteOnExpire, setRecycleFreq) {
if (deleteOnExpire === null) {
delete this.$$deleteOnExpire;
} else if (!angular.isString(deleteOnExpire)) {
throw new Error('deleteOnExpire must be a string!');
} else if (deleteOnExpire !== 'none' && deleteOnExpire !== 'passive' && deleteOnExpire !== 'aggressive') {
throw new Error('deleteOnExpire must be "none", "passive" or "aggressive"!');
} else {
this.$$deleteOnExpire = deleteOnExpire;
}
if (setRecycleFreq !== false) {
this.setRecycleFreq(this.$$recycleFreq);
}
},
setMaxAge(maxAge) {
if (maxAge === null) {
this.$$maxAge = Number.MAX_VALUE;
} else if (!angular.isNumber(maxAge)) {
throw new Error('maxAge must be a number!');
} else if (maxAge < 0) {
throw new Error('maxAge must be greater than zero!');
} else {
this.$$maxAge = maxAge;
}
let i, keys, key;
this.$$expiresHeap.removeAll();
if (this.$$storage) {
let keysJson = this.$$storage().getItem(`${this.$$prefix}.keys`);
keys = keysJson ? angular.fromJson(keysJson) : [];
for (i = 0; i < keys.length; i++) {
key = keys[i];
let itemJson = this.$$storage().getItem(`${this.$$prefix}.data.${key}`);
if (itemJson) {
let item = angular.fromJson(itemJson);
if (this.$$maxAge === Number.MAX_VALUE) {
item.expires = Number.MAX_VALUE;
} else {
item.expires = item.created + this.$$maxAge;
}
this.$$expiresHeap.push({
key: key,
expires: item.expires
});
}
}
} else {
keys = _keys(this.$$data);
for (i = 0; i < keys.length; i++) {
key = keys[i];
if (this.$$maxAge === Number.MAX_VALUE) {
this.$$data[key].expires = Number.MAX_VALUE;
} else {
this.$$data[key].expires = this.$$data[key].created + this.$$maxAge;
}
this.$$expiresHeap.push(this.$$data[key]);
}
}
if (this.$$deleteOnExpire === 'aggressive') {
return this.removeExpired();
} else {
return {};
}
},
setOnExpire(onExpire) {
if (onExpire === null) {
delete this.$$onExpire;
} else if (!angular.isFunction(onExpire)) {
throw new Error('onExpire must be a function!');
} else {
this.$$onExpire = onExpire;
}
},
setOptions(cacheOptions, strict) {
cacheOptions = cacheOptions || {};
strict = !!strict;
if (!angular.isObject(cacheOptions)) {
throw new Error('cacheOptions must be an object!');
}
if ('storagePrefix' in cacheOptions) {
this.$$storagePrefix = !!cacheOptions.storagePrefix;
} else if (strict) {
this.$$storagePrefix = defaults.storagePrefix;
}
this.$$prefix = this.$$storagePrefix + this.$$id;
if ('disabled' in cacheOptions) {
this.$$disabled = !!cacheOptions.disabled;
} else if (strict) {
this.$$disabled = defaults.disabled;
}
if ('storageMode' in cacheOptions || 'storageImpl' in cacheOptions) {
this.setStorageMode(cacheOptions.storageMode, cacheOptions.storageImpl);
} else if (strict) {
this.setStorageMode(defaults.storageMode, defaults.storageImpl);
}
if ('storeOnResolve' in cacheOptions) {
this.$$storeOnResolve = !!cacheOptions.storeOnResolve;
} else if (strict) {
this.$$storeOnResolve = defaults.storeOnResolve;
}
if ('storeOnReject' in cacheOptions) {
this.$$storeOnReject = !!cacheOptions.storeOnReject;
} else if (strict) {
this.$$storeOnReject = defaults.storeOnReject;
}
if ('capacity' in cacheOptions) {
this.setCapacity(cacheOptions.capacity);
} else if (strict) {
this.setCapacity(defaults.capacity);
}
if ('deleteOnExpire' in cacheOptions) {
this.setDeleteOnExpire(cacheOptions.deleteOnExpire, false);
} else if (strict) {
this.setDeleteOnExpire(defaults.deleteOnExpire, false);
}
if ('maxAge' in cacheOptions) {
this.setMaxAge(cacheOptions.maxAge);
} else if (strict) {
this.setMaxAge(defaults.maxAge);
}
if ('recycleFreq' in cacheOptions) {
this.setRecycleFreq(cacheOptions.recycleFreq);
} else if (strict) {
this.setRecycleFreq(defaults.recycleFreq);
}
if ('cacheFlushInterval' in cacheOptions) {
this.setCacheFlushInterval(cacheOptions.cacheFlushInterval);
} else if (strict) {
this.setCacheFlushInterval(defaults.cacheFlushInterval);
}
if ('onExpire' in cacheOptions) {
this.setOnExpire(cacheOptions.onExpire);
} else if (strict) {
this.setOnExpire(defaults.onExpire);
}
},
setRecycleFreq(recycleFreq) {
if (recycleFreq === null) {
delete this.$$recycleFreq;
} else if (!angular.isNumber(recycleFreq)) {
throw new Error('recycleFreq must be a number!');
} else if (recycleFreq < 0) {
throw new Error('recycleFreq must be greater than zero!');
} else {
this.$$recycleFreq = recycleFreq;
}
clearInterval(this.$$recycleFreqId);
if (this.$$deleteOnExpire === 'aggressive') {
(function (self) {
self.$$recycleFreqId = setInterval(function () {
self.removeExpired();
}, self.$$recycleFreq);
})(this);
} else {
delete this.$$recycleFreqId;
}
},
setStorageMode(storageMode, storageImpl) {
if (!angular.isString(storageMode)) {
throw new Error('storageMode must be a string!');
} else if (storageMode !== 'memory' && storageMode !== 'localStorage' && storageMode !== 'sessionStorage') {
throw new Error('storageMode must be "memory", "localStorage" or "sessionStorage"!');
}
let shouldReInsert = false;
let items = {};
if (typeof this.$$storageMode === 'string' && this.$$storageMode !== storageMode) {
let keys = this.keys();
if (keys.length) {
for (var i = 0; i < keys.length; i++) {
items[keys[i]] = this.get(keys[i]);
}
for (i = 0; i < keys.length; i++) {
this.remove(keys[i]);
}
shouldReInsert = true;
}
}
this.$$storageMode = storageMode;
if (storageImpl) {
if (!angular.isObject(storageImpl)) {
throw new Error('storageImpl must be an object!');
} else if (!('setItem' in storageImpl) || typeof storageImpl.setItem !== 'function') {
throw new Error('storageImpl must implement "setItem(key, value)"!');
} else if (!('getItem' in storageImpl) || typeof storageImpl.getItem !== 'function') {
throw new Error('storageImpl must implement "getItem(key)"!');
} else if (!('removeItem' in storageImpl) || typeof storageImpl.removeItem !== 'function') {
throw new Error('storageImpl must implement "removeItem(key)"!');
}
this.$$storage = () => storageImpl;
} else if (this.$$storageMode === 'localStorage') {
try {
localStorage.setItem('angular-cache', 'angular-cache');
localStorage.removeItem('angular-cache');
this.$$storage = () => localStorage;
} catch (e) {
delete this.$$storage;
this.$$storageMode = 'memory';
}
} else if (this.$$storageMode === 'sessionStorage') {
try {
sessionStorage.setItem('angular-cache', 'angular-cache');
sessionStorage.removeItem('angular-cache');
this.$$storage = () => sessionStorage;
} catch (e) {
delete this.$$storage;
this.$$storageMode = 'memory';
}
}
if (shouldReInsert) {
for (var key in items) {
this.put(key, items[key]);
}
}
},
touch(key) {
if (key) {
let val = this.get(key, {
onExpire: (k, v) => this.put(k, v)
});
if (val) {
this.put(key, val);
}
} else {
let keys = this.keys();
for (var i = 0; i < keys.length; i++) {
this.touch(keys[i]);
}
}
}
};
cache.setOptions(options, true);
return cache;
};
function CacheFactory(cacheId, options) {
return createCache(cacheId, options);
}
return new Error(message);
};
};
CacheFactory.createCache = createCache;
CacheFactory.info = () => {
let keys = _keys(caches);
let info = {
size: keys.length,
caches: {}
};
angular.extend(info, this.defaults);
for (var i = 0; i < keys.length; i++) {
let key = keys[i];
info.caches[key] = caches[key].info();
}
return info;
};
angular.module('angular-data.DSBinaryHeap', [])
.provider('DSBinaryHeap', require('./DSBinaryHeap').DSBinaryHeapProvider);
CacheFactory.get = cacheId => {
return caches[cacheId];
};
/**
* @doc overview
* @id angular-cache
* @name Overview
* @description
* __Version:__ <%= pkg.version %>
*
* ## Install
*
* #### Bower
* ```text
* bower install angular-cache
* ```
*
* Load `dist/angular-cache.js` or `dist/angular-cache.min.js` onto your web page after Angular.js.
*
* #### Npm
* ```text
* npm install angular-cache
* ```
*
* Load `dist/angular-cache.js` or `dist/angular-cache.min.js` onto your web page after Angular.js. Angular-cache is
* also consumable by Browserify and you should be able to `require('angular-cache')`. The `main` file is `src/index.js`.
*
* #### Manual download
* Download angular-cache.<%= pkg.version %>.js from the [Releases](https://github.com/jmdobry/angular-cache/releases)
* section of the angular-cache GitHub project.
*
* ## Load into Angular
* Your Angular app must depend on the module `"angular-data.DSCacheFactory"` in order to use angular-cache. Loading
* angular-cache into your app allows you to inject the following:
*
* - `DSCacheFactory`
* - `DSBinaryHeap`
*
* [DSCacheFactory](/documentation/api/api/DSCacheFactory) is a factory function that produces instances of
* [DSCache](/documentation/api/api/DSCache), which is API compatible with caches produced by Angular's
* [$cacheFactory](http://docs.angularjs.org/api/ng/service/$cacheFactory).
*
* [DSBinaryHeap](/documentation/api/api/DSBinaryHeap) is a priority queue implemented as a Binary Heap.
*
* If you want to use angular-cache with [angular-data](/documentation/api/api/angular-data), then angular-cache must
* be loaded before angular-data.
*/
angular.module('angular-data.DSCacheFactory', ['ng', 'angular-data.DSBinaryHeap'])
.provider('DSCacheFactory', require('./DSCacheFactory'));
CacheFactory.keySet = () => {
return _keySet(caches);
};
})(window, window.angular);
CacheFactory.keys = () => _keys(caches);
CacheFactory.destroy = cacheId => {
if (caches[cacheId]) {
caches[cacheId].destroy();
delete caches[cacheId];
}
};
CacheFactory.destroyAll = () => {
for (var cacheId in caches) {
caches[cacheId].destroy();
}
caches = {};
};
CacheFactory.clearAll = () => {
for (var cacheId in caches) {
caches[cacheId].removeAll();
}
};
CacheFactory.removeExpiredFromAll = () => {
let expired = {};
for (var cacheId in caches) {
expired[cacheId] = caches[cacheId].removeExpired();
}
return expired;
};
CacheFactory.enableAll = () => {
for (var cacheId in caches) {
caches[cacheId].$$disabled = false;
}
};
CacheFactory.disableAll = () => {
for (var cacheId in caches) {
caches[cacheId].$$disabled = true;
}
};
CacheFactory.touchAll = () => {
for (var cacheId in caches) {
caches[cacheId].touch();
}
};
return CacheFactory;
}];
}
}
angular.module('angular-cache', [])
.provider('BinaryHeap', BinaryHeapProvider)
.provider('CacheFactory', CacheFactoryProvider);
export default 'angular-cache';

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc