@bizjournals/js-storage 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/lib/storage.js +1 -0
  2. package/lib/storage.js.map +1 -0
  3. package/package.json +38 -23
  4. package/.gitlab-ci.yml +0 -15
  5. package/babel.config.cjs +0 -12
  6. package/jest.config.cjs +0 -3
  7. package/lib/abstract/__mocks__/mock-storage.js +0 -19
  8. package/lib/abstract/__tests__/storage.clear.spec.js +0 -25
  9. package/lib/abstract/__tests__/storage.constructor.spec.js +0 -46
  10. package/lib/abstract/__tests__/storage.expirationkey.spec.js +0 -22
  11. package/lib/abstract/__tests__/storage.getitem.spec.js +0 -80
  12. package/lib/abstract/__tests__/storage.hasitem.spec.js +0 -25
  13. package/lib/abstract/__tests__/storage.issupported.spec.js +0 -36
  14. package/lib/abstract/__tests__/storage.namespacekey.spec.js +0 -54
  15. package/lib/abstract/__tests__/storage.parser.spec.js +0 -40
  16. package/lib/abstract/__tests__/storage.removeitem.spec.js +0 -63
  17. package/lib/abstract/__tests__/storage.setitem.spec.js +0 -75
  18. package/lib/abstract/__tests__/storage.translator.spec.js +0 -24
  19. package/lib/abstract/constants/index.js +0 -3
  20. package/lib/abstract/exceptions/index.js +0 -1
  21. package/lib/abstract/index.js +0 -255
  22. package/lib/abstract/store/index.js +0 -10
  23. package/lib/local/__mocks__/local-storage.js +0 -28
  24. package/lib/local/__tests__/storage.local.spec.js +0 -8
  25. package/lib/local/index.js +0 -24
  26. package/lib/reference/__tests__/storagereference.general.spec.js +0 -47
  27. package/lib/reference/exceptions/index.js +0 -1
  28. package/lib/reference/index.js +0 -67
  29. package/lib/session/__tests__/storage.session.spec.js +0 -8
  30. package/lib/session/index.js +0 -24
  31. package/main.js +0 -5
package/lib/storage.js ADDED
@@ -0,0 +1 @@
1
+ const store={supported:null};class StorageAbstract{constructor(options={}){this.namespace=options.namespace||"bizj",this.expires=options.expires||3600,this.namespace=this.namespace.toLowerCase(),this.storage={}}getItem(key,parse=!0){let response;if(this.isSupported()&&!this.isItemExpired(key)){try{if(response=this.storage.getItem(this.namespaceKey(key)),null===response)return;response=parse?this.parser(response):response}catch(e){}return response}}parser(data){try{"string"==typeof data&&(data=JSON.parse(data))}catch(e){}return data}translator(value){return"string"==typeof value?value:JSON.stringify(value)}setItem(key,value,expires=!0){if(!this.isSupported())return;const generatedKey=this.namespaceKey(key);try{this.storage.setItem(generatedKey,this.translator(value)),expires&&this.storage.setItem(this.expirationKey(key),String(this.timestamp(this.expires)))}catch(e){}}removeItem(key){if(this.isSupported())try{this.storage.removeItem(this.namespaceKey(key)),this.storage.removeItem(this.expirationKey(key))}catch(e){}}clear(){try{this.storage.clear()}catch(e){}}hasItem(key){return void 0!==this.getItem(key,!1)}timestamp(offset=0){return Math.ceil(Date.now()/1e3)+offset}namespaceKey(key){if("string"!=typeof key)throw new Error("A key must be provided to obtain data from the store.");return 0===key.indexOf(`${this.namespace}.`)&&(key=key.slice(this.namespace.length+1)),`${this.namespace}.${key.toLowerCase()}`}expirationKey(key){return`${this.namespaceKey(key)}.expires`}isItemExpired(key){if(!this.isSupported())return!1;try{let value=this.storage.getItem(this.expirationKey(key));if("string"==typeof value&&value.length>0){if(parseInt(value,10)-this.timestamp()<=0)return this.removeItem(key),!0}}catch(e){}return!1}isSupported(){if("boolean"==typeof store.supported)return store.supported;const test="biz.storage.test";try{this.storage.setItem(test,"1"),this.storage.removeItem(test),store.supported=!0}catch(e){store.supported=e instanceof DOMException&&(22===e.code||1014===e.code||"QuotaExceededError"===e.name||"NS_ERROR_DOM_QUOTA_REACHED"===e.name)&&this.storage&&0!==this.storage.length}return store.supported}}class LocalStorage extends StorageAbstract{constructor(options={}){super(options),this.storage=window.localStorage}}class SessionStorage extends StorageAbstract{constructor(options){super(options),this.storage=window.sessionStorage}}class StorageReference{constructor(cacheKey,storageSystem){if("string"!=typeof cacheKey||!(storageSystem instanceof StorageAbstract))throw new Error("Invalid construction of cache system. Please refer to documentation.");this.cacheKey=cacheKey,this.storageSystem=storageSystem}obtain(){return this.storageSystem.getItem(this.cacheKey)}bust(){this.storageSystem.removeItem(this.cacheKey)}saveAs(data){return data&&this.storageSystem.setItem(this.cacheKey,data),this}}export{LocalStorage,SessionStorage,StorageReference};
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sources":["../src/abstract/constants/index.js","../src/abstract/exceptions/index.js","../src/abstract/store/index.js","../src/abstract/index.js","../src/local/index.js","../src/session/index.js","../src/reference/exceptions/index.js","../src/reference/index.js"],"sourcesContent":["export const DEFAULT_EXPIRATION = 3600;\nexport const DEFAULT_NAMESPACE = 'bizj';\nexport const EXPIRES_KEY_SUFFIX = 'expires';","export const KEY_IS_REQUIRED_TO_FETCH_DATA = 'A key must be provided to obtain data from the store.';\n","/**\n * The data store for global variables\n *\n */\nconst store = {\n supported: null,\n}\n\n// --\nexport default store;","import { DEFAULT_EXPIRATION, DEFAULT_NAMESPACE, EXPIRES_KEY_SUFFIX } from './constants';\nimport { KEY_IS_REQUIRED_TO_FETCH_DATA } from './exceptions';\nimport store from './store';\n\n/*\n|--------------------------------------------------------------------------\n| Storage Abstract / Contract\n|--------------------------------------------------------------------------\n|\n| This is the base storage class that is extended for localStorage and\n| sessionStorage. In time we may look to use this for InnoDB as well.\n|\n|\n*/\nexport default class StorageAbstract {\n /**\n * Constructor takes in options for namespace and expiration.\n * Session storage is the default storage type.\n *\n * @param {object} options\n * @constructor\n */\n constructor (options = {}) {\n this.namespace = options.namespace || DEFAULT_NAMESPACE;\n this.expires = options.expires || DEFAULT_EXPIRATION;\n\n this.namespace = this.namespace.toLowerCase();\n\n this.storage = {};\n }\n\n /**\n * Gets an item from storage and runs the parser unless explicitly\n * disabled in the method request.\n *\n * @param {String} key\n * @param {Boolean} parse\n * @returns {(Array|Number|Object|String|Null)}\n */\n getItem (key, parse = true) {\n let response;\n\n if (! this.isSupported() || this.isItemExpired(key)) {\n return undefined;\n }\n\n try {\n response = this.storage.getItem(this.namespaceKey(key));\n\n if (response === null) return undefined;\n\n response = parse ? this.parser(response) : response;\n } catch (e) {\n // fall through\n }\n\n return response;\n }\n\n /**\n * Parses the data returned from the storage system\n *\n * @param data\n * @returns {*}\n */\n parser (data) {\n try {\n if (typeof data === 'string') {\n data = JSON.parse(data);\n }\n } catch (e) {\n // fall through\n }\n\n return data;\n }\n\n /**\n * Translates the data before setting to the storage system\n *\n * @param value\n * @returns {any}\n */\n translator (value) {\n return typeof value === 'string' ? value : JSON.stringify(value);\n }\n\n /**\n * Sets an item in the storage system.\n *\n * @param {string} key\n * @param {(array|object|number|string)} value\n * @param {boolean} expires\n */\n setItem (key, value, expires = true) {\n if (! this.isSupported()) {\n return;\n }\n\n const generatedKey = this.namespaceKey(key);\n\n try {\n this.storage.setItem(generatedKey, this.translator(value));\n\n if (expires) {\n this.storage.setItem(\n this.expirationKey(key),\n String(this.timestamp(this.expires)),\n );\n }\n } catch (e) {\n // fall through\n }\n }\n\n /**\n * Removes an item from the storage system.\n *\n * @param {string} key\n */\n removeItem (key) {\n if (! this.isSupported()) {\n return;\n }\n\n try {\n this.storage.removeItem(this.namespaceKey(key));\n this.storage.removeItem(this.expirationKey(key));\n } catch (e) {\n // fall through\n }\n }\n\n /**\n * Clears all items from storage.\n */\n clear () {\n try {\n this.storage.clear();\n } catch (e) {\n // fall through\n }\n }\n\n /**\n * Checks to see if an item exists in local storage.\n *\n * @param {string} key\n * @returns {boolean}\n */\n hasItem (key) {\n return this.getItem(key, false) !== undefined;\n }\n\n /**\n * Calculates the expires for an item.\n *\n * @param {number} offset\n * @returns {number}\n */\n timestamp (offset = 0) {\n return Math.ceil(Date.now() / 1000) + offset;\n }\n\n /**\n * Creates the key used for storing information in the storage\n *\n * @param {string} key\n * @returns {string}\n */\n namespaceKey (key) {\n if (typeof key !== 'string') {\n throw new Error(KEY_IS_REQUIRED_TO_FETCH_DATA);\n }\n\n if (key.indexOf(`${ this.namespace }.`) === 0) {\n key = key.slice(this.namespace.length + 1);\n }\n\n return `${ this.namespace }.${ key.toLowerCase() }`;\n }\n\n /**\n * Creates the expires key used for testing storage usage\n *\n * @returns {string}\n */\n expirationKey (key) {\n return `${ this.namespaceKey(key) }.${ EXPIRES_KEY_SUFFIX }`;\n }\n\n /**\n * Checks to see if an item is expired and removes it if so.\n *\n * @param {string} key\n * @returns {boolean}\n */\n isItemExpired (key) {\n if (! this.isSupported()) {\n return false;\n }\n\n try {\n let value = this.storage.getItem(this.expirationKey(key));\n\n if (typeof value === 'string' && value.length > 0) {\n let expires = parseInt(value, 10);\n\n if (expires - this.timestamp() <= 0) {\n this.removeItem(key);\n return true;\n }\n }\n } catch (e) {\n // fall through\n }\n\n return false;\n }\n\n /**\n * Checks to see if the storage system is supported\n *\n * @returns {boolean}\n */\n isSupported () {\n if (typeof store.supported === 'boolean') {\n return store.supported;\n }\n\n const test = 'biz.storage.test';\n\n try {\n this.storage.setItem(test, '1');\n this.storage.removeItem(test);\n\n store.supported = true;\n } catch (e) {\n store.supported = e instanceof DOMException && (\n // everything except Firefox\n e.code === 22 ||\n // Firefox\n e.code === 1014 ||\n // test name field too, because code might not be present\n // everything except Firefox\n e.name === 'QuotaExceededError' ||\n // Firefox\n e.name === 'NS_ERROR_DOM_QUOTA_REACHED'\n ) && (this.storage && this.storage.length !== 0);\n }\n\n return store.supported;\n }\n}\n","import StorageAbstract from \"../abstract\";\n\n/*\n|--------------------------------------------------------------------------\n| Local Storage\n|--------------------------------------------------------------------------\n| This is the base class for hooking into local storage. There isn't much\n| overlap here if you just keep instantiating, so there isn't much need\n| to singleton this.\n|\n|\n*/\nexport default class LocalStorage extends StorageAbstract {\n /**\n * Create a local storage adapter.\n *\n * @param {object} [options]\n */\n constructor(options = {}) {\n super(options);\n\n this.storage = window.localStorage;\n }\n}\n","import StorageAbstract from \"../abstract\";\n\n/*\n|--------------------------------------------------------------------------\n| Session Storage\n|--------------------------------------------------------------------------\n| This is the base class for hooking into session storage. There isn't much\n| overlap here if you just keep instantiating, so there isn't much need\n| to singleton this.\n|\n|\n*/\nexport default class SessionStorage extends StorageAbstract {\n /**\n * Create a session storage adapter.\n *\n * @param {object} [options]\n */\n constructor(options) {\n super(options);\n\n this.storage = window.sessionStorage;\n }\n}\n","export const INVALID_CONSTRUCTOR_PARAMETERS = 'Invalid construction of cache system. Please refer to documentation.';\n","import StorageAbstract from \"../abstract\";\nimport { INVALID_CONSTRUCTOR_PARAMETERS } from \"./exceptions\";\n\n/*\n|--------------------------------------------------------------------------\n| Storage Reference\n|--------------------------------------------------------------------------\n| This is a reference to something in storage. Each item has a key\n| belonging to a specific storage system. These storage systems have a\n| common abstract / contract that gives them the same expected pattern.\n| This is the adapter.\n|\n|\n*/\nexport default class StorageReference {\n /**\n * Creates an instance of a StorageReference system, which needs a cacheKey and\n * a Storage system (StorageAbstract).\n *\n * @param {string} cacheKey\n * @param {StorageAbstract} storageSystem\n * @constructor\n * @return {StorageReference}\n */\n constructor(cacheKey, storageSystem) {\n if (typeof cacheKey !== \"string\" || !(storageSystem instanceof StorageAbstract)) {\n throw new Error(INVALID_CONSTRUCTOR_PARAMETERS);\n }\n\n this.cacheKey = cacheKey;\n this.storageSystem = storageSystem;\n }\n\n /**\n * Pulls data from the local store or cached resource.\n *\n * @returns {*}\n */\n obtain() {\n return this.storageSystem.getItem(this.cacheKey);\n }\n\n /**\n * Destroys the cache reference with the cache key\n *\n * @returns {void}\n */\n bust() {\n this.storageSystem.removeItem(this.cacheKey);\n }\n\n /**\n * Saves the locally stored cache to the caching system. This is\n * differed via a Promise because the timing of this can be\n * performed asynchronously.\n *\n * @param data\n * @returns {StorageReference}\n */\n saveAs(data) {\n if (data) {\n this.storageSystem.setItem(this.cacheKey, data);\n }\n\n return this;\n }\n}\n"],"names":["DEFAULT_EXPIRATION","DEFAULT_NAMESPACE","EXPIRES_KEY_SUFFIX","KEY_IS_REQUIRED_TO_FETCH_DATA","store","supported","StorageAbstract","constructor","options","namespace","expires","toLowerCase","storage","getItem","key","parse","response","isSupported","isItemExpired","undefined","namespaceKey","parser","e","data","JSON","translator","value","stringify","setItem","generatedKey","expirationKey","String","timestamp","removeItem","clear","hasItem","offset","Math","ceil","Date","now","Error","indexOf","slice","length","parseInt","test","DOMException","code","name","LocalStorage","window","localStorage","SessionStorage","sessionStorage","INVALID_CONSTRUCTOR_PARAMETERS","StorageReference","cacheKey","storageSystem","obtain","bust","saveAs"],"mappings":"AAAO,MAAMA,kBAAkB,GAAG,IAA3B;AACA,MAAMC,iBAAiB,GAAG,MAA1B;AACA,MAAMC,kBAAkB,GAAG,SAA3B;;ACFA,MAAMC,6BAA6B,GAAG,uDAAtC;;ACAP;;;;AAIA,MAAMC,KAAK,GAAG;AACZC,EAAAA,SAAS,EAAE;AADC,CAAd;;ACAA;;;;;;;;;;;AAUe,MAAMC,eAAN,CAAsB;AACjC;;;;;;;AAOAC,EAAAA,WAAW,CAAEC,OAAO,GAAG,EAAZ,EAAgB;AACvB,SAAKC,SAAL,GAAiBD,OAAO,CAACC,SAAR,IAAqBR,iBAAtC;AACA,SAAKS,OAAL,GAAeF,OAAO,CAACE,OAAR,IAAmBV,kBAAlC;AAEA,SAAKS,SAAL,GAAiB,KAAKA,SAAL,CAAeE,WAAf,EAAjB;AAEA,SAAKC,OAAL,GAAe,EAAf;AACH;AAED;;;;;;;;;;AAQAC,EAAAA,OAAO,CAAEC,GAAF,EAAOC,KAAK,GAAG,IAAf,EAAqB;AACxB,QAAIC,QAAJ;;AAEA,QAAI,CAAE,KAAKC,WAAL,EAAF,IAAwB,KAAKC,aAAL,CAAmBJ,GAAnB,CAA5B,EAAqD;AACjD,aAAOK,SAAP;AACH;;AAED,QAAI;AACAH,MAAAA,QAAQ,GAAG,KAAKJ,OAAL,CAAaC,OAAb,CAAqB,KAAKO,YAAL,CAAkBN,GAAlB,CAArB,CAAX;AAEA,UAAIE,QAAQ,KAAK,IAAjB,EAAuB,OAAOG,SAAP;AAEvBH,MAAAA,QAAQ,GAAGD,KAAK,GAAG,KAAKM,MAAL,CAAYL,QAAZ,CAAH,GAA2BA,QAA3C;AACH,KAND,CAME,OAAOM,CAAP,EAAU;AAEX;;AAED,WAAON,QAAP;AACH;AAED;;;;;;;;AAMAK,EAAAA,MAAM,CAAEE,IAAF,EAAQ;AACV,QAAI;AACA,UAAI,OAAOA,IAAP,KAAgB,QAApB,EAA8B;AAC1BA,QAAAA,IAAI,GAAGC,IAAI,CAACT,KAAL,CAAWQ,IAAX,CAAP;AACH;AACJ,KAJD,CAIE,OAAOD,CAAP,EAAU;AAEX;;AAED,WAAOC,IAAP;AACH;AAED;;;;;;;;AAMAE,EAAAA,UAAU,CAAEC,KAAF,EAAS;AACf,WAAO,OAAOA,KAAP,KAAiB,QAAjB,GAA4BA,KAA5B,GAAoCF,IAAI,CAACG,SAAL,CAAeD,KAAf,CAA3C;AACH;AAED;;;;;;;;;AAOAE,EAAAA,OAAO,CAAEd,GAAF,EAAOY,KAAP,EAAchB,OAAO,GAAG,IAAxB,EAA8B;AACjC,QAAI,CAAE,KAAKO,WAAL,EAAN,EAA0B;AACtB;AACH;;AAED,UAAMY,YAAY,GAAG,KAAKT,YAAL,CAAkBN,GAAlB,CAArB;;AAEA,QAAI;AACA,WAAKF,OAAL,CAAagB,OAAb,CAAqBC,YAArB,EAAmC,KAAKJ,UAAL,CAAgBC,KAAhB,CAAnC;;AAEA,UAAIhB,OAAJ,EAAa;AACT,aAAKE,OAAL,CAAagB,OAAb,CACI,KAAKE,aAAL,CAAmBhB,GAAnB,CADJ,EAEIiB,MAAM,CAAC,KAAKC,SAAL,CAAe,KAAKtB,OAApB,CAAD,CAFV;AAIH;AACJ,KATD,CASE,OAAOY,CAAP,EAAU;AAEX;AACJ;AAED;;;;;;;AAKAW,EAAAA,UAAU,CAAEnB,GAAF,EAAO;AACb,QAAI,CAAE,KAAKG,WAAL,EAAN,EAA0B;AACtB;AACH;;AAED,QAAI;AACA,WAAKL,OAAL,CAAaqB,UAAb,CAAwB,KAAKb,YAAL,CAAkBN,GAAlB,CAAxB;AACA,WAAKF,OAAL,CAAaqB,UAAb,CAAwB,KAAKH,aAAL,CAAmBhB,GAAnB,CAAxB;AACH,KAHD,CAGE,OAAOQ,CAAP,EAAU;AAEX;AACJ;AAED;;;;;AAGAY,EAAAA,KAAK,GAAI;AACL,QAAI;AACA,WAAKtB,OAAL,CAAasB,KAAb;AACH,KAFD,CAEE,OAAOZ,CAAP,EAAU;AAEX;AACJ;AAED;;;;;;;;AAMAa,EAAAA,OAAO,CAAErB,GAAF,EAAO;AACV,WAAO,KAAKD,OAAL,CAAaC,GAAb,EAAkB,KAAlB,MAA6BK,SAApC;AACH;AAED;;;;;;;;AAMAa,EAAAA,SAAS,CAAEI,MAAM,GAAG,CAAX,EAAc;AACnB,WAAOC,IAAI,CAACC,IAAL,CAAUC,IAAI,CAACC,GAAL,KAAa,IAAvB,IAA+BJ,MAAtC;AACH;AAED;;;;;;;;AAMAhB,EAAAA,YAAY,CAAEN,GAAF,EAAO;AACf,QAAI,OAAOA,GAAP,KAAe,QAAnB,EAA6B;AACzB,YAAM,IAAI2B,KAAJ,CAAUtC,6BAAV,CAAN;AACH;;AAED,QAAIW,GAAG,CAAC4B,OAAJ,CAAa,GAAG,KAAKjC,SAAW,GAAhC,MAAwC,CAA5C,EAA+C;AAC3CK,MAAAA,GAAG,GAAGA,GAAG,CAAC6B,KAAJ,CAAU,KAAKlC,SAAL,CAAemC,MAAf,GAAwB,CAAlC,CAAN;AACH;;AAED,WAAQ,GAAG,KAAKnC,SAAW,IAAIK,GAAG,CAACH,WAAJ,EAAmB,EAAlD;AACH;AAED;;;;;;;AAKAmB,EAAAA,aAAa,CAAEhB,GAAF,EAAO;AAChB,WAAQ,GAAG,KAAKM,YAAL,CAAkBN,GAAlB,CAAwB,IAAIZ,kBAAoB,EAA3D;AACH;AAED;;;;;;;;AAMAgB,EAAAA,aAAa,CAAEJ,GAAF,EAAO;AAChB,QAAI,CAAE,KAAKG,WAAL,EAAN,EAA0B;AACtB,aAAO,KAAP;AACH;;AAED,QAAI;AACA,UAAIS,KAAK,GAAG,KAAKd,OAAL,CAAaC,OAAb,CAAqB,KAAKiB,aAAL,CAAmBhB,GAAnB,CAArB,CAAZ;;AAEA,UAAI,OAAOY,KAAP,KAAiB,QAAjB,IAA6BA,KAAK,CAACkB,MAAN,GAAe,CAAhD,EAAmD;AAC/C,YAAIlC,OAAO,GAAGmC,QAAQ,CAACnB,KAAD,EAAQ,EAAR,CAAtB;;AAEA,YAAIhB,OAAO,GAAG,KAAKsB,SAAL,EAAV,IAA8B,CAAlC,EAAqC;AACjC,eAAKC,UAAL,CAAgBnB,GAAhB;AACA,iBAAO,IAAP;AACH;AACJ;AACJ,KAXD,CAWE,OAAOQ,CAAP,EAAU;AAEX;;AAED,WAAO,KAAP;AACH;AAED;;;;;;;AAKAL,EAAAA,WAAW,GAAI;AACX,QAAI,OAAOb,KAAK,CAACC,SAAb,KAA2B,SAA/B,EAA0C;AACtC,aAAOD,KAAK,CAACC,SAAb;AACH;;AAED,UAAMyC,IAAI,GAAG,kBAAb;;AAEA,QAAI;AACA,WAAKlC,OAAL,CAAagB,OAAb,CAAqBkB,IAArB,EAA2B,GAA3B;AACA,WAAKlC,OAAL,CAAaqB,UAAb,CAAwBa,IAAxB;AAEA1C,MAAAA,KAAK,CAACC,SAAN,GAAkB,IAAlB;AACH,KALD,CAKE,OAAOiB,CAAP,EAAU;AACRlB,MAAAA,KAAK,CAACC,SAAN,GAAkBiB,CAAC,YAAYyB,YAAb;AAEdzB,MAAAA,CAAC,CAAC0B,IAAF,KAAW,EAAX;AAEA1B,MAAAA,CAAC,CAAC0B,IAAF,KAAW,IAFX;AAIA;AACA1B,MAAAA,CAAC,CAAC2B,IAAF,KAAW,oBALX;AAOA3B,MAAAA,CAAC,CAAC2B,IAAF,KAAW,4BATG,KAUZ,KAAKrC,OAAL,IAAgB,KAAKA,OAAL,CAAagC,MAAb,KAAwB,CAV9C;AAWH;;AAED,WAAOxC,KAAK,CAACC,SAAb;AACH;;AA9OgC;;ACZrC;;;;;;;;;;;AAUe,MAAM6C,YAAN,SAA2B5C,eAA3B,CAA2C;AACtD;;;;;AAKAC,EAAAA,WAAW,CAACC,OAAO,GAAG,EAAX,EAAe;AACtB,UAAMA,OAAN;AAEA,SAAKI,OAAL,GAAeuC,MAAM,CAACC,YAAtB;AACH;;AAVqD;;ACV1D;;;;;;;;;;;AAUe,MAAMC,cAAN,SAA6B/C,eAA7B,CAA6C;AACxD;;;;;AAKAC,EAAAA,WAAW,CAACC,OAAD,EAAU;AACjB,UAAMA,OAAN;AAEA,SAAKI,OAAL,GAAeuC,MAAM,CAACG,cAAtB;AACH;;AAVuD;;ACZrD,MAAMC,8BAA8B,GAAG,sEAAvC;;ACGP;;;;;;;;;;;;AAWe,MAAMC,gBAAN,CAAuB;AAClC;;;;;;;;;AASAjD,EAAAA,WAAW,CAACkD,QAAD,EAAWC,aAAX,EAA0B;AACjC,QAAI,OAAOD,QAAP,KAAoB,QAApB,IAAgC,EAAEC,aAAa,YAAYpD,eAA3B,CAApC,EAAiF;AAC7E,YAAM,IAAImC,KAAJ,CAAUc,8BAAV,CAAN;AACH;;AAED,SAAKE,QAAL,GAAgBA,QAAhB;AACA,SAAKC,aAAL,GAAqBA,aAArB;AACH;AAED;;;;;;;AAKAC,EAAAA,MAAM,GAAG;AACL,WAAO,KAAKD,aAAL,CAAmB7C,OAAnB,CAA2B,KAAK4C,QAAhC,CAAP;AACH;AAED;;;;;;;AAKAG,EAAAA,IAAI,GAAG;AACH,SAAKF,aAAL,CAAmBzB,UAAnB,CAA8B,KAAKwB,QAAnC;AACH;AAED;;;;;;;;;;AAQAI,EAAAA,MAAM,CAACtC,IAAD,EAAO;AACT,QAAIA,IAAJ,EAAU;AACN,WAAKmC,aAAL,CAAmB9B,OAAnB,CAA2B,KAAK6B,QAAhC,EAA0ClC,IAA1C;AACH;;AAED,WAAO,IAAP;AACH;;AAnDiC;;;;"}
package/package.json CHANGED
@@ -1,25 +1,40 @@
1
1
  {
2
- "name": "@bizjournals/js-storage",
3
- "version": "0.1.1",
4
- "description": "ACBJ javascript storage classes",
5
- "repository": {
6
- "git": "https://gitlab.bizjournals.com/bizjournals/js-storage"
7
- },
8
- "main": "main.js",
9
- "type": "module",
10
- "sideEffects": false,
11
- "scripts": {
12
- "test": "jest",
13
- "preversion": "npm test",
14
- "postversion": "git push && git push --tags && npm publish"
15
- },
16
- "keywords": [],
17
- "author": "DPD",
18
- "license": "UNLICENSED",
19
- "devDependencies": {
20
- "@babel/preset-env": "^7.10.3",
21
- "babel-jest": "^25.4.0",
22
- "jest": "^25.4.0"
23
- },
24
- "dependencies": {}
2
+ "name": "@bizjournals/js-storage",
3
+ "version": "0.2.0",
4
+ "description": "ACBJ javascript storage classes",
5
+ "repository": {
6
+ "git": "https://gitlab.bizjournals.com/bizjournals/js-storage"
7
+ },
8
+ "main": "lib/storage.js",
9
+ "sideEffects": false,
10
+ "files": [
11
+ "lib/**"
12
+ ],
13
+ "scripts": {
14
+ "test": "jest",
15
+ "dev": "npm-run-all --parallel link watch",
16
+ "link": "npm link",
17
+ "build": "rollup -c",
18
+ "watch": "rollup -c -w",
19
+ "preversion": "npm test",
20
+ "version": "npm run build",
21
+ "postversion": "git push && git push --tags && npm publish"
22
+ },
23
+ "keywords": [],
24
+ "author": "DPD",
25
+ "license": "UNLICENSED",
26
+ "devDependencies": {
27
+ "@babel/preset-env": "^7.10.3",
28
+ "@rollup/plugin-babel": "^5.3.0",
29
+ "@rollup/plugin-commonjs": "^17.0.0",
30
+ "@rollup/plugin-node-resolve": "^11.1.0",
31
+ "babel-jest": "^25.4.0",
32
+ "jest": "^25.4.0",
33
+ "npm-run-all": "^4.1.5",
34
+ "rollup": "^2.36.2",
35
+ "rollup-plugin-delete": "^2.0.0",
36
+ "rollup-plugin-terser": "^7.0.2",
37
+ "serve": "^11.3.2"
38
+ },
39
+ "dependencies": {}
25
40
  }
package/.gitlab-ci.yml DELETED
@@ -1,15 +0,0 @@
1
- npmrunner:
2
- tags:
3
- - php73
4
- script:
5
- - date
6
- - node --version
7
- - npm --version
8
- - rm -f .npmrc
9
- - mv build/.npmrc .npmrc
10
- - npm install --loglevel=error
11
- - npm test
12
- - rm -rf node_modules
13
- - rm -f .npmrc
14
- except:
15
- - tags
package/babel.config.cjs DELETED
@@ -1,12 +0,0 @@
1
- module.exports = {
2
- presets: [
3
- [
4
- "@babel/preset-env",
5
- {
6
- targets: {
7
- node: "current",
8
- },
9
- },
10
- ],
11
- ],
12
- };
package/jest.config.cjs DELETED
@@ -1,3 +0,0 @@
1
- module.exports = {
2
- transformIgnorePatterns: ["/node_modules/(?!(@bizjournals))/"]
3
- };
@@ -1,19 +0,0 @@
1
- let store = {};
2
-
3
- export default {
4
- clear: jest.fn().mockImplementation(() => {
5
- store = {};
6
- }),
7
-
8
- getItem: jest.fn().mockImplementation((key) => {
9
- return store[key];
10
- }),
11
-
12
- setItem: jest.fn().mockImplementation((key, value) => {
13
- store[key] = value;
14
- }),
15
-
16
- removeItem: jest.fn().mockImplementation((key) => {
17
- delete store[key];
18
- })
19
- };
@@ -1,25 +0,0 @@
1
- import StorageAbstract from '../';
2
-
3
- describe('core:class >> storageabstract:clear', () => {
4
- let storageAbstract;
5
-
6
- beforeAll(() => {
7
- storageAbstract = new StorageAbstract();
8
- });
9
-
10
- it('never fails or throws when storage is not set', () => {
11
- delete storageAbstract.storage;
12
- expect(() => {
13
- storageAbstract.clear();
14
- }).not.toThrow();
15
- });
16
-
17
- it('runs the clear method on the storage system when defined', () => {
18
- storageAbstract.storage = {
19
- clear: jest.fn()
20
- };
21
-
22
- storageAbstract.clear();
23
- expect(storageAbstract.storage.clear).toHaveBeenCalledTimes(1);
24
- });
25
- });
@@ -1,46 +0,0 @@
1
- import StorageAbstract from '../';
2
- import { DEFAULT_EXPIRATION, DEFAULT_NAMESPACE } from '../constants';
3
-
4
- describe('core:class >> storageabstract:constructor', () => {
5
- it('defaults to constant as it\'s namespace when none provided', () => {
6
- const storageAbstract = new StorageAbstract();
7
- expect(storageAbstract.namespace).toMatch(DEFAULT_NAMESPACE);
8
- });
9
-
10
- it('accepts an object parameter with key namespace and sets it to this.namespace', () => {
11
- const namespace = 'test';
12
- const storageAbstract = new StorageAbstract({ namespace });
13
- expect(storageAbstract.namespace).toMatch(namespace);
14
- });
15
-
16
- it('coercies the namespace to lower case before setting', () => {
17
- const namespace = 'TeSt';
18
- const storageAbstract = new StorageAbstract({ namespace });
19
- expect(storageAbstract.namespace).toMatch(namespace.toLowerCase());
20
- });
21
-
22
- it('throws error when namespace provided is not a string', () => {
23
- const namespaces = [true, {}, [], 12];
24
- for (const namespace of namespaces) {
25
- expect(() => {
26
- new StorageAbstract({ namespace });
27
- }).toThrow();
28
- }
29
- });
30
-
31
- it('defaults to constant as it\'s expiration when none provided', () => {
32
- const storageAbstract = new StorageAbstract();
33
- expect(storageAbstract.expires).toEqual(DEFAULT_EXPIRATION);
34
- });
35
-
36
- it('accepts an object parameter with key expires and sets it to this.expires', () => {
37
- const expires = 3600 * 4;
38
- const storageAbstract = new StorageAbstract({ expires });
39
- expect(storageAbstract.expires).toEqual(expires);
40
- });
41
-
42
- it('sets the storage to a default of null', () => {
43
- const storageAbstract = new StorageAbstract();
44
- expect(storageAbstract.storage).toEqual({});
45
- });
46
- });
@@ -1,22 +0,0 @@
1
- import StorageAbstract from '../';
2
- import { EXPIRES_KEY_SUFFIX } from '../constants';
3
-
4
- describe('core:class >> storageabstract:namespacekey', () => {
5
- let storageAbstract;
6
-
7
- beforeEach(() => {
8
- storageAbstract = new StorageAbstract();
9
- });
10
-
11
- it('calls the namespaceKey to generate the prefix', () => {
12
- storageAbstract.namespaceKey = jest.fn();
13
- storageAbstract.expirationKey('hey');
14
- expect(storageAbstract.namespaceKey).toHaveBeenCalledTimes(1);
15
- });
16
-
17
- it('returns a concatenated variation of the namespace and string key', () => {
18
- let key = 'key';
19
- expect(storageAbstract.expirationKey(key))
20
- .toEqual(`${ storageAbstract.namespaceKey(key) }.${ EXPIRES_KEY_SUFFIX }`);
21
- });
22
- });
@@ -1,80 +0,0 @@
1
- import StorageAbstract from '../';
2
-
3
- describe('core:class >> storageabstract:getitem', () => {
4
- let storageClassMock, mockStorage, key = 'test';
5
-
6
- beforeAll(() => {
7
- storageClassMock = new StorageAbstract();
8
- });
9
-
10
- beforeEach(() => {
11
- storageClassMock.namespaceKey = jest.fn().mockImplementation(key => key);
12
- storageClassMock.parser = jest.fn().mockImplementation(data => data);
13
- storageClassMock.cache = jest.fn().mockImplementation(data => data);
14
- storageClassMock.isSupported = jest.fn().mockImplementation(() => true);
15
- storageClassMock.isItemExpired = jest.fn().mockImplementation(() => false);
16
-
17
- mockStorage = {
18
- getItem: jest.fn()
19
- };
20
-
21
- storageClassMock.storage = mockStorage;
22
- StorageAbstract.supported = undefined;
23
- });
24
-
25
- it('returns undefined when it is not supported', () => {
26
- storageClassMock.isSupported = jest.fn().mockImplementation(() => false);
27
-
28
- expect(storageClassMock.getItem()).toEqual(undefined);
29
- expect(storageClassMock.namespaceKey).not.toHaveBeenCalled();
30
- });
31
-
32
- it('returns undefined when the item is expired', () => {
33
- storageClassMock.isItemExpired = jest.fn().mockImplementation(() => true);
34
-
35
- expect(storageClassMock.getItem()).toEqual(undefined);
36
- expect(storageClassMock.namespaceKey).not.toHaveBeenCalled();
37
- });
38
-
39
- it('calls `namespace` key to get a dynamically generated key', () => {
40
- storageClassMock.namespaceKey = jest.fn().mockImplementation(() => {
41
- throw new Error('Just a test fall through.');
42
- });
43
-
44
- storageClassMock.getItem();
45
- expect(storageClassMock.namespaceKey).toHaveBeenCalledTimes(1);
46
- });
47
-
48
- it('calls getItem on the storage system when suspended data not available', () => {
49
- storageClassMock.getItem(key);
50
- expect(storageClassMock.storage.getItem).toHaveBeenCalledTimes(1);
51
- expect(storageClassMock.storage.getItem).toHaveBeenCalledWith(key);
52
- });
53
-
54
- it('calls the `parser` method with the data fetched from suspend or getItem', () => {
55
- const data = { hey: 'you' };
56
-
57
- const localStorage = {
58
- getItem: jest.fn().mockImplementation(() => data)
59
- };
60
-
61
- storageClassMock.storage = localStorage;
62
-
63
- storageClassMock.getItem(key);
64
- expect(storageClassMock.parser).toHaveBeenCalled();
65
- expect(storageClassMock.parser).toHaveBeenCalledWith(data);
66
- });
67
-
68
- it('does not call the `parser` method with the data fetched from suspend or getItem', () => {
69
- const data = { hey: 'you' };
70
-
71
- const localStorage = {
72
- getItem: jest.fn().mockImplementation(() => data)
73
- };
74
-
75
- storageClassMock.storage = localStorage;
76
-
77
- storageClassMock.getItem(key, false);
78
- expect(storageClassMock.parser).not.toHaveBeenCalled();
79
- });
80
- });
@@ -1,25 +0,0 @@
1
- import StorageAbstract from '../';
2
-
3
- describe('core:class >> storageabstract:hasitem', () => {
4
- let storageClassMock, key = 'test';
5
-
6
- beforeAll(() => {
7
- storageClassMock = new StorageAbstract();
8
- });
9
-
10
- beforeEach(() => {
11
- storageClassMock.getItem = jest.fn().mockImplementation(key => key);
12
- });
13
-
14
- it('calls getItem to fetch the item from the storage system', () => {
15
- storageClassMock.hasItem(key);
16
-
17
- expect(storageClassMock.getItem).toHaveBeenCalledTimes(1);
18
- });
19
-
20
- it('returns false when the obtained item is undefined', () => {
21
- storageClassMock.getItem = jest.fn().mockImplementation(() => undefined);
22
-
23
- expect(storageClassMock.hasItem(key)).toBeFalsy();
24
- });
25
- });
@@ -1,36 +0,0 @@
1
- import StorageAbstract from '../';
2
- import mockStorage from '../__mocks__/mock-storage';
3
- import store from '../store';
4
-
5
- describe('core:class >> storageabstract:issupported', () => {
6
- let storageAbstract;
7
-
8
- beforeEach(() => {
9
- storageAbstract = new StorageAbstract();
10
- mockStorage.setItem.mockClear();
11
- mockStorage.removeItem.mockClear();
12
-
13
- storageAbstract.storage = mockStorage;
14
- store.supported = undefined;
15
- });
16
-
17
- it('returns false when the storage system is defaulted', () => {
18
- storageAbstract.storage = {};
19
- expect(storageAbstract.isSupported()).toBeFalsy();
20
- });
21
-
22
- it('returns true when the storage system is valid and usable', () => {
23
- storageAbstract.storage = mockStorage;
24
- expect(storageAbstract.isSupported()).toBeTruthy();
25
- expect(mockStorage.setItem).toHaveBeenCalledTimes(1);
26
- expect(mockStorage.removeItem).toHaveBeenCalledTimes(1);
27
- });
28
-
29
- it('returns a stored answer once the storage system has been checked', () => {
30
- storageAbstract.storage = mockStorage;
31
- let isSupported = storageAbstract.isSupported();
32
- isSupported = storageAbstract.isSupported();
33
- expect(mockStorage.setItem).toHaveBeenCalledTimes(1);
34
- expect(mockStorage.removeItem).toHaveBeenCalledTimes(1);
35
- });
36
- });
@@ -1,54 +0,0 @@
1
- import StorageAbstract from '../';
2
- import { KEY_IS_REQUIRED_TO_FETCH_DATA } from '../exceptions';
3
-
4
- describe('core:class >> storageabstract:namespacekey', () => {
5
- let storageAbstract;
6
-
7
- beforeEach(() => {
8
- storageAbstract = new StorageAbstract();
9
- });
10
-
11
- it('throws an exception when a non-string is passed', () => {
12
- let keys = [true, [], {}, 1];
13
- for (const key of keys) {
14
- expect(() => {
15
- storageAbstract.namespaceKey(key);
16
- }).toThrow(KEY_IS_REQUIRED_TO_FETCH_DATA);
17
- }
18
- });
19
-
20
- it('returns a concatenated variation of the namespace and string key', () => {
21
- let key = 'key';
22
- expect(storageAbstract.namespaceKey(key))
23
- .toEqual(`${ storageAbstract.namespace }.${ key }`);
24
- });
25
-
26
- it('coerces the key to lower case before returning', () => {
27
- let key = 'KEy';
28
- expect(storageAbstract.namespaceKey(key))
29
- .toEqual(`${ storageAbstract.namespace }.${ key.toLowerCase() }`);
30
- });
31
-
32
- it('extracts the namespace and key separator when present at the beginning of the string', () => {
33
- const theRealKey = 'myrealkey';
34
- let key = `${ storageAbstract.namespace }.${ theRealKey }`;
35
- expect(storageAbstract.namespaceKey(key))
36
- .toEqual(`${ storageAbstract.namespace }.${ theRealKey.toLowerCase() }`);
37
- });
38
-
39
- it('does not extract the namespace and key separator when present anywhere else in the string', () => {
40
- const theRealKey = 'myrealkey';
41
- let key = `a${ storageAbstract.namespace }.${ theRealKey }`;
42
- expect(storageAbstract.namespaceKey(key))
43
- .not.toEqual(`${ storageAbstract.namespace }.${ theRealKey.toLowerCase() }`);
44
- expect(storageAbstract.namespaceKey(key))
45
- .toEqual(`${ storageAbstract.namespace }.${ key.toLowerCase() }`);
46
- });
47
-
48
- it('does not extract the namespace when missing the key separator', () => {
49
- const theRealKey = 'myrealkey';
50
- let key = `${ storageAbstract.namespace }${ theRealKey }`;
51
- expect(storageAbstract.namespaceKey(key))
52
- .toEqual(`${ storageAbstract.namespace }.${ key.toLowerCase() }`);
53
- });
54
- });
@@ -1,40 +0,0 @@
1
- import StorageAbstract from '../';
2
-
3
- describe('core:class >> storageabstract:parser', () => {
4
- let storageAbstract;
5
- const copyParse = JSON.parse;
6
- delete JSON.parse;
7
-
8
- beforeEach(() => {
9
- storageAbstract = new StorageAbstract();
10
- JSON.parse = jest.fn();
11
- JSON.parse.mockClear();
12
- });
13
-
14
- it('returns the raw data when not a string', () => {
15
- const data = {
16
- my: 'value'
17
- };
18
-
19
- expect(storageAbstract.parser(data)).toEqual(data);
20
- expect(JSON.parse).not.toBeCalled();
21
- });
22
-
23
- it('attempts to parse the item when it is a string', () => {
24
- const data = 'somestuff';
25
-
26
- storageAbstract.parser(data);
27
- expect(JSON.parse).toHaveBeenCalledTimes(1);
28
- });
29
-
30
- it('returns the provided string if it could not be JSON parsed', () => {
31
- JSON.parse = copyParse;
32
- let response;
33
-
34
- expect(() => {
35
- response = storageAbstract.parser('wowowow');
36
- }).not.toThrow();
37
-
38
- expect(response).toEqual('wowowow');
39
- });
40
- });
@@ -1,63 +0,0 @@
1
- import StorageAbstract from '../';
2
-
3
- import store from '../store';
4
-
5
- describe('core:class >> storageabstract:removeitem', () => {
6
- let storageClassMock, mockStorage, key = 'test';
7
-
8
- beforeAll(() => {
9
- storageClassMock = new StorageAbstract();
10
- });
11
-
12
- beforeEach(() => {
13
- storageClassMock.isSupported = jest.fn().mockImplementation(() => true);
14
- storageClassMock.namespaceKey = jest.fn().mockImplementation(key => key);
15
- storageClassMock.expirationKey = jest.fn().mockImplementation(key => `${key}.expires`);
16
- storageClassMock.resetAttempts = jest.fn().mockImplementation(() => {
17
- storageClassMock.attempts = 0;
18
- });
19
-
20
- mockStorage = {
21
- removeItem: jest.fn()
22
- };
23
-
24
- storageClassMock.storage = mockStorage;
25
- store.supported = undefined;
26
- });
27
-
28
- it('halts when it is not supported', () => {
29
- storageClassMock.isSupported = jest.fn().mockImplementation(() => false);
30
-
31
- storageClassMock.removeItem(key);
32
-
33
- expect(storageClassMock.isSupported).toHaveBeenCalledTimes(1);
34
- expect(storageClassMock.storage.removeItem).not.toHaveBeenCalled();
35
- });
36
-
37
- it('falls through when encountering an exception', () => {
38
- store.supported = true;
39
-
40
- const badStorage = {
41
- removeItem: jest.fn().mockImplementation(() => {
42
- throw new Error('testing code');
43
- })
44
- };
45
-
46
- storageClassMock.storage = badStorage;
47
-
48
- expect(() => {
49
- storageClassMock.removeItem();
50
- }).not.toThrow();
51
-
52
- expect(storageClassMock.storage.removeItem).toHaveBeenCalledTimes(1);
53
- });
54
-
55
- it('removes both the item at namespace and expiration keys', () => {
56
- store.supported = true;
57
- storageClassMock.removeItem();
58
-
59
- expect(storageClassMock.namespaceKey).toHaveBeenCalledTimes(1);
60
- expect(storageClassMock.expirationKey).toHaveBeenCalledTimes(1);
61
- expect(storageClassMock.storage.removeItem).toHaveBeenCalledTimes(2);
62
- });
63
- });
@@ -1,75 +0,0 @@
1
- import StorageAbstract from '../';
2
- import store from '../store';
3
-
4
- describe('core:class >> storageabstract:setitem', () => {
5
- let storageClassMock, mockStorage, key = 'test';
6
-
7
- beforeAll(() => {
8
- storageClassMock = new StorageAbstract();
9
- });
10
-
11
- beforeEach(() => {
12
- storageClassMock.isSupported = jest.fn().mockImplementation(() => true);
13
- storageClassMock.namespaceKey = jest.fn().mockImplementation(key => key);
14
- storageClassMock.expirationKey = jest.fn().mockImplementation(key => key);
15
- storageClassMock.translator = jest.fn().mockImplementation(data => data);
16
- storageClassMock.timestamp = jest.fn().mockImplementation(() => 12345);
17
- storageClassMock.cache = jest.fn().mockImplementation(data => data);
18
- storageClassMock.clear = jest.fn().mockImplementation(() => storageClassMock);
19
- storageClassMock.resetAttempts = jest.fn().mockImplementation(() => {
20
- storageClassMock.attempts = 0;
21
- return storageClassMock;
22
- });
23
-
24
- mockStorage = {
25
- setItem: jest.fn()
26
- };
27
-
28
- storageClassMock.attempts = 0;
29
- storageClassMock.storage = mockStorage;
30
- store.supported = undefined;
31
- });
32
-
33
- it('resets the attempts and returns when it is not supported without continuing', () => {
34
- storageClassMock.isSupported = jest.fn().mockImplementation(() => false);
35
- storageClassMock.setItem();
36
-
37
- expect(storageClassMock.isSupported).toHaveBeenCalledTimes(1);
38
- expect(storageClassMock.namespaceKey).not.toHaveBeenCalled();
39
- expect(mockStorage.setItem).not.toHaveBeenCalled();
40
- });
41
-
42
- it('uses a dynamically generated namespaceKey to set the item', () => {
43
- storageClassMock.setItem(key, { data: true });
44
- expect(storageClassMock.namespaceKey).toHaveBeenCalledTimes(1);
45
- });
46
-
47
- it('calls the translator prior to attempting to set the item', () => {
48
- storageClassMock.translator = jest.fn().mockImplementation(() => {
49
- throw new Error('testing script error');
50
- });
51
-
52
- storageClassMock.setItem(key, { data: true });
53
- expect(storageClassMock.translator).toHaveBeenCalled();
54
- expect(storageClassMock.storage.setItem).not.toHaveBeenCalled();
55
- });
56
-
57
- it('calls to set the item one time when not expiring', () => {
58
- const data = { it: true };
59
-
60
- storageClassMock.setItem(key, data, false);
61
-
62
- expect(storageClassMock.storage.setItem).toHaveBeenCalledTimes(1);
63
- expect(storageClassMock.storage.setItem).toHaveBeenCalledWith(key, data);
64
- expect(storageClassMock.expirationKey).not.toHaveBeenCalled();
65
- });
66
-
67
- it('calls set item again with the expiration key if defaulted to expire', () => {
68
- const data = { it: true };
69
-
70
- storageClassMock.setItem(key, data);
71
-
72
- expect(storageClassMock.storage.setItem).toHaveBeenCalledTimes(2);
73
- expect(storageClassMock.expirationKey).toHaveBeenCalledTimes(1);
74
- });
75
- });
@@ -1,24 +0,0 @@
1
- import StorageAbstract from '../';
2
-
3
- describe('core:class >> storageabstract:translator', () => {
4
- let storageAbstract;
5
-
6
- beforeEach(() => {
7
- storageAbstract = new StorageAbstract();
8
- });
9
-
10
- it('calls json stringify when passed an object', () => {
11
- const data = {
12
- my: 'value'
13
- };
14
-
15
- expect(storageAbstract.translator(data))
16
- .toEqual(JSON.stringify(data));
17
- });
18
-
19
- it('returns a string back exactly as is', () => {
20
- const data = 'somestuff';
21
-
22
- expect(storageAbstract.translator(data)).toEqual(data);
23
- });
24
- });
@@ -1,3 +0,0 @@
1
- export const DEFAULT_EXPIRATION = 3600;
2
- export const DEFAULT_NAMESPACE = 'bizj';
3
- export const EXPIRES_KEY_SUFFIX = 'expires';
@@ -1 +0,0 @@
1
- export const KEY_IS_REQUIRED_TO_FETCH_DATA = 'A key must be provided to obtain data from the store.';
@@ -1,255 +0,0 @@
1
- import { DEFAULT_EXPIRATION, DEFAULT_NAMESPACE, EXPIRES_KEY_SUFFIX } from "./constants";
2
- import { KEY_IS_REQUIRED_TO_FETCH_DATA } from "./exceptions";
3
- import store from './store';
4
-
5
- /*
6
- |--------------------------------------------------------------------------
7
- | Storage Abstract / Contract
8
- |--------------------------------------------------------------------------
9
- |
10
- | This is the base storage class that is extended for localStorage and
11
- | sessionStorage. In time we may look to use this for InnoDB as well.
12
- |
13
- |
14
- */
15
- export default class StorageAbstract {
16
- /**
17
- * Constructor takes in options for namespace and expiration.
18
- * Session storage is the default storage type.
19
- *
20
- * @param {object} options
21
- * @constructor
22
- */
23
- constructor (options = {}) {
24
- this.namespace = options.namespace || DEFAULT_NAMESPACE;
25
- this.expires = options.expires || DEFAULT_EXPIRATION;
26
-
27
- this.namespace = this.namespace.toLowerCase();
28
-
29
- this.storage = {};
30
- }
31
-
32
- /**
33
- * Gets an item from storage and runs the parser unless explicitly
34
- * disabled in the method request.
35
- *
36
- * @param {String} key
37
- * @param {Boolean} parse
38
- * @returns {(Array|Number|Object|String|Null)}
39
- */
40
- getItem (key, parse = true) {
41
- let response;
42
-
43
- if (!this.isSupported() || this.isItemExpired(key)) {
44
- return response;
45
- }
46
-
47
- try {
48
- response = this.storage.getItem(this.namespaceKey(key));
49
-
50
- if (response === null) return undefined;
51
-
52
- response = parse ? this.parser(response) : response;
53
- } catch (e) {
54
- // fall through
55
- }
56
-
57
- return response;
58
- }
59
-
60
- /**
61
- * Parses the data returned from the storage system
62
- *
63
- * @param data
64
- * @returns {*}
65
- */
66
- parser (data) {
67
- try {
68
- if (typeof data === "string") {
69
- data = JSON.parse(data);
70
- }
71
- } catch (e) {
72
- // fall through
73
- }
74
-
75
- return data;
76
- }
77
-
78
- /**
79
- * Translates the data before setting to the storage system
80
- *
81
- * @param value
82
- * @returns {any}
83
- */
84
- translator (value) {
85
- return typeof value === 'string' ? value : JSON.stringify(value);
86
- }
87
-
88
- /**
89
- * Sets an item in the storage system.
90
- *
91
- * @param {string} key
92
- * @param {(array|object|number|string)} value
93
- * @param {boolean} expires
94
- */
95
- setItem (key, value, expires = true) {
96
- if (!this.isSupported()) {
97
- return;
98
- }
99
-
100
- const generatedKey = this.namespaceKey(key);
101
-
102
- try {
103
- this.storage.setItem(generatedKey, this.translator(value));
104
-
105
- if (expires) {
106
- this.storage.setItem(
107
- this.expirationKey(key),
108
- String(this.timestamp(this.expires))
109
- );
110
- }
111
- } catch (e) {
112
- // fall through
113
- }
114
- }
115
-
116
- /**
117
- * Removes an item from the storage system.
118
- *
119
- * @param {string} key
120
- */
121
- removeItem (key) {
122
- if (!this.isSupported()) {
123
- return;
124
- }
125
-
126
- try {
127
- this.storage.removeItem(this.namespaceKey(key));
128
- this.storage.removeItem(this.expirationKey(key));
129
- } catch (e) {
130
- // fall through
131
- }
132
- }
133
-
134
- /**
135
- * Clears all items from storage.
136
- */
137
- clear () {
138
- try {
139
- this.storage.clear();
140
- } catch (e) {
141
- // fall through
142
- }
143
- }
144
-
145
- /**
146
- * Checks to see if an item exists in local storage.
147
- *
148
- * @param {string} key
149
- * @returns {boolean}
150
- */
151
- hasItem (key) {
152
- return this.getItem(key, false) !== undefined;
153
- }
154
-
155
- /**
156
- * Calculates the expires for an item.
157
- *
158
- * @param {number} offset
159
- * @returns {number}
160
- */
161
- timestamp (offset = 0) {
162
- return Math.ceil(Date.now() / 1000) + offset;
163
- }
164
-
165
- /**
166
- * Creates the key used for storing information in the storage
167
- *
168
- * @param {string} key
169
- * @returns {string}
170
- */
171
- namespaceKey (key) {
172
- if (typeof key !== "string") {
173
- throw new Error(KEY_IS_REQUIRED_TO_FETCH_DATA);
174
- }
175
-
176
- if (key.indexOf(`${ this.namespace }.`) === 0) {
177
- key = key.slice(this.namespace.length + 1);
178
- }
179
-
180
- return `${ this.namespace }.${ key.toLowerCase() }`;
181
- }
182
-
183
- /**
184
- * Creates the expires key used for testing storage usage
185
- *
186
- * @returns {string}
187
- */
188
- expirationKey (key) {
189
- return `${ this.namespaceKey(key) }.${ EXPIRES_KEY_SUFFIX }`;
190
- }
191
-
192
- /**
193
- * Checks to see if an item is expired and removes it if so.
194
- *
195
- * @param {string} key
196
- * @returns {boolean}
197
- */
198
- isItemExpired (key) {
199
- if (!this.isSupported()) {
200
- return false;
201
- }
202
-
203
- try {
204
- let value = this.storage.getItem(this.expirationKey(key));
205
-
206
- if (value && "length" in value && value.length) {
207
- let expires = parseInt(value, 10);
208
-
209
- if (expires - this.timestamp() <= 0) {
210
- this.removeItem(key);
211
- return true;
212
- }
213
- }
214
- } catch (e) {
215
- // fall through
216
- }
217
-
218
- return false;
219
- }
220
-
221
- /**
222
- * Checks to see if the storage system is supported
223
- *
224
- * @returns {boolean}
225
- */
226
- isSupported () {
227
- if (typeof store.supported === "boolean") {
228
- return store.supported;
229
- }
230
-
231
- const test = 'biz.storage.test';
232
-
233
- try {
234
- this.storage.setItem(test, '1');
235
- this.storage.removeItem(test);
236
-
237
- store.supported = true;
238
- } catch (e) {
239
- store.supported = e instanceof DOMException &&
240
- (
241
- // everything except Firefox
242
- e.code === 22 ||
243
- // Firefox
244
- e.code === 1014 ||
245
- // test name field too, because code might not be present
246
- // everything except Firefox
247
- e.name === 'QuotaExceededError' ||
248
- // Firefox
249
- e.name === 'NS_ERROR_DOM_QUOTA_REACHED'
250
- ) && (this.storage && this.storage.length !== 0);
251
- }
252
-
253
- return store.supported;
254
- }
255
- }
@@ -1,10 +0,0 @@
1
- /**
2
- * The data store for global variables
3
- *
4
- */
5
- const store = {
6
- supported: null,
7
- }
8
-
9
- // --
10
- export default store;
@@ -1,28 +0,0 @@
1
- import StorageAbstract from '../../abstract';
2
-
3
- export default class LocalStorageMock extends StorageAbstract {
4
- constructor (options) {
5
- super(options);
6
- this.store = {};
7
- }
8
-
9
- clear () {
10
- this.store = {};
11
- }
12
-
13
- getItem (key) {
14
- return this.store[key] || null;
15
- }
16
-
17
- setItem (key, value, expires = true) {
18
- this.store[key] = value;
19
- return this;
20
- }
21
-
22
- removeItem (key) {
23
- delete this.store[key];
24
- return this;
25
- }
26
- }
27
-
28
- export class InvalidStorageMock {}
@@ -1,8 +0,0 @@
1
- import LocalStorage from '../';
2
-
3
- describe('bizjournals / core:class >> localstorage:constructor', () => {
4
- it('builds the object with localStorage set as the storage system', () => {
5
- const localStorage = new LocalStorage();
6
- expect(localStorage.storage).toEqual(window.localStorage);
7
- });
8
- });
@@ -1,24 +0,0 @@
1
- import StorageAbstract from "../abstract";
2
-
3
- /*
4
- |--------------------------------------------------------------------------
5
- | Local Storage
6
- |--------------------------------------------------------------------------
7
- | This is the base class for hooking into local storage. There isn't much
8
- | overlap here if you just keep instantiating, so there isn't much need
9
- | to singleton this.
10
- |
11
- |
12
- */
13
- export default class LocalStorage extends StorageAbstract {
14
- /**
15
- * Create a local storage adapter.
16
- *
17
- * @param {object} [options]
18
- */
19
- constructor(options = {}) {
20
- super(options);
21
-
22
- this.storage = window.localStorage;
23
- }
24
- }
@@ -1,47 +0,0 @@
1
- import StorageReference from '../';
2
- import LocalStorageMock, { InvalidStorageMock } from '../../local/__mocks__/local-storage';
3
- import { INVALID_CONSTRUCTOR_PARAMETERS } from '../exceptions';
4
-
5
- describe('bizjournals / core:class >> storagereference', () => {
6
- it('throws error when the cachekey is not a string', () => {
7
- expect(() => {
8
- new StorageReference([], new LocalStorageMock());
9
- }).toThrow(INVALID_CONSTRUCTOR_PARAMETERS);
10
- });
11
-
12
- it('throws an error when the storage system does not adhere to contract', () => {
13
- expect(() => {
14
- new StorageReference('astring', new InvalidStorageMock());
15
- }).toThrow(INVALID_CONSTRUCTOR_PARAMETERS);
16
- });
17
-
18
- it('does not throw an error when constructor parameters are valid', () => {
19
- expect(() => {
20
- new StorageReference('astring', new LocalStorageMock());
21
- }).not.toThrow();
22
- });
23
-
24
- it('assigns the constructor parameters to variables for reference', () => {
25
- const cacheKey = 'astring';
26
- const localStorage = new LocalStorageMock();
27
-
28
- const storage = new StorageReference(cacheKey, localStorage);
29
-
30
- expect(storage.cacheKey).toEqual(cacheKey);
31
- expect(storage.storageSystem).toEqual(localStorage);
32
- });
33
-
34
- it('can save and obtain the data using the key from storage', () => {
35
- const cacheKey = 'astring';
36
- const localStorage = new LocalStorageMock();
37
- const mockData = { luke: 'skywalker', plot: 'ruined' };
38
-
39
- const storage = new StorageReference(cacheKey, localStorage);
40
-
41
- expect(() => {
42
- storage.saveAs(mockData);
43
- }).not.toThrow();
44
-
45
- expect(storage.obtain()).toEqual(mockData);
46
- });
47
- });
@@ -1 +0,0 @@
1
- export const INVALID_CONSTRUCTOR_PARAMETERS = 'Invalid construction of cache system. Please refer to documentation.';
@@ -1,67 +0,0 @@
1
- import StorageAbstract from "../abstract";
2
- import { INVALID_CONSTRUCTOR_PARAMETERS } from "./exceptions";
3
-
4
- /*
5
- |--------------------------------------------------------------------------
6
- | Storage Reference
7
- |--------------------------------------------------------------------------
8
- | This is a reference to something in storage. Each item has a key
9
- | belonging to a specific storage system. These storage systems have a
10
- | common abstract / contract that gives them the same expected pattern.
11
- | This is the adapter.
12
- |
13
- |
14
- */
15
- export default class StorageReference {
16
- /**
17
- * Creates an instance of a StorageReference system, which needs a cacheKey and
18
- * a Storage system (StorageAbstract).
19
- *
20
- * @param {string} cacheKey
21
- * @param {StorageAbstract} storageSystem
22
- * @constructor
23
- * @return {StorageReference}
24
- */
25
- constructor(cacheKey, storageSystem) {
26
- if (typeof cacheKey !== "string" || !(storageSystem instanceof StorageAbstract)) {
27
- throw new Error(INVALID_CONSTRUCTOR_PARAMETERS);
28
- }
29
-
30
- this.cacheKey = cacheKey;
31
- this.storageSystem = storageSystem;
32
- }
33
-
34
- /**
35
- * Pulls data from the local store or cached resource.
36
- *
37
- * @returns {*}
38
- */
39
- obtain() {
40
- return this.storageSystem.getItem(this.cacheKey);
41
- }
42
-
43
- /**
44
- * Destroys the cache reference with the cache key
45
- *
46
- * @returns {void}
47
- */
48
- bust() {
49
- this.storageSystem.removeItem(this.cacheKey);
50
- }
51
-
52
- /**
53
- * Saves the locally stored cache to the caching system. This is
54
- * differed via a Promise because the timing of this can be
55
- * performed asynchronously.
56
- *
57
- * @param data
58
- * @returns {StorageReference}
59
- */
60
- saveAs(data) {
61
- if (data) {
62
- this.storageSystem.setItem(this.cacheKey, data);
63
- }
64
-
65
- return this;
66
- }
67
- }
@@ -1,8 +0,0 @@
1
- import SessionStorage from "../";
2
-
3
- describe("bizjournals / core:class >> sessionstorage:constructor", () => {
4
- it("builds the object with sessionStorage set as the storage system", () => {
5
- const sessionStorage = new SessionStorage();
6
- expect(sessionStorage.storage).toEqual(window.sessionStorage);
7
- });
8
- });
@@ -1,24 +0,0 @@
1
- import StorageAbstract from "../abstract";
2
-
3
- /*
4
- |--------------------------------------------------------------------------
5
- | Session Storage
6
- |--------------------------------------------------------------------------
7
- | This is the base class for hooking into session storage. There isn't much
8
- | overlap here if you just keep instantiating, so there isn't much need
9
- | to singleton this.
10
- |
11
- |
12
- */
13
- export default class SessionStorage extends StorageAbstract {
14
- /**
15
- * Create a session storage adapter.
16
- *
17
- * @param {object} [options]
18
- */
19
- constructor(options) {
20
- super(options);
21
-
22
- this.storage = window.sessionStorage;
23
- }
24
- }
package/main.js DELETED
@@ -1,5 +0,0 @@
1
- import LocalStorage from "./lib/local";
2
- import SessionStorage from "./lib/session";
3
- import StorageReference from "./lib/reference";
4
-
5
- export { LocalStorage, SessionStorage, StorageReference };