diff --git a/src/memorystorage.js b/src/memorystorage.js index f983b67..bdeb9e4 100644 --- a/src/memorystorage.js +++ b/src/memorystorage.js @@ -17,66 +17,90 @@ * @param id Optional string argument used to isolate this memory storage object from others. */ function MemoryStorage(id) { - // make sure id is assigned - id = id || 'global' - // try to get existing store - var result = storage[id] - // return it if found - if (result) {return result} + // make sure id is assigned + id = id || "global"; + // try to get existing store + var result = storage[id]; + // return it if found + if (result) { + return result; + } - // make sure there is no harm in leaving out new in invocations to MemoryStorage - if (! (this instanceof MemoryStorage)) {return new MemoryStorage(id);} + // make sure there is no harm in leaving out new in invocations to MemoryStorage + if (!(this instanceof MemoryStorage)) { + return new MemoryStorage(id); + } - // create a new store and save a ref to it so we can get it back later - result = storage[id] = this; - // create a space to store 'cloaked' key/values: items that have a key - // that collides with Web Storage API method names. - var cloak = {}; + // create a new store and save a ref to it so we can get it back later + result = storage[id] = this; + // create a space to store 'cloaked' key/values: items that have a key + // that collides with Web Storage API method names. + var cloak = {}; - // Allow client code to read the id - Object.defineProperty(result, 'id', {enumerable:true, configurable:true, value:id}) + // Allow client code to read the id + Object.defineProperty(result, "id", { enumerable: true, configurable: true, value: id }); - // Create the length property - Object.defineProperty(result, 'length', {enumerable:true, configurable:true, get:function(){ - return enumerableKeys().length - }}) + // Create the length property + Object.defineProperty(result, "length", { + enumerable: true, + configurable: true, + get: function () { + return enumerableKeys().length; + }, + }); - // Create API methods - result.getItem = function MemoryStorage_getItem(key) { - return (key in API ? cloak[key] : this[key]) || null - } - result.setItem = function MemoryStorage_setItem(key, val) { - key in API ? cloak[key] = val : this[key] = val - } - result.removeItem = function MemoryStorage_removeItem(key) { - key in API ? delete cloak[key] : delete this[key] - } - result.key = function MemoryStorage_key(idx) { - var keys = enumerableKeys() - return idx >= 0 && idx < keys.length ? keys[idx] : null - } - result.clear = function MemoryStorage_clear() { - var keys = uncloakedKeys() - for (var i=0,key; key=keys[i]; i++) { - delete this[key] - } - keys = cloakedKeys() - for (var i=0,key; key=keys[i]; i++) { - delete cloak[key] - } - } + // Create API methods + result.getItem = function MemoryStorage_getItem(key) { + var value = key in API ? cloak[key] : this[key]; + return value === undefined ? null : value; + }; + result.setItem = function MemoryStorage_setItem(key, val) { + val = String(val); + key in API ? (cloak[key] = val) : (this[key] = val); + }; + result.removeItem = function MemoryStorage_removeItem(key) { + key in API ? delete cloak[key] : delete this[key]; + }; + result.key = function MemoryStorage_key(idx) { + var keys = enumerableKeys(); + return idx >= 0 && idx < keys.length ? keys[idx] : null; + }; + result.clear = function MemoryStorage_clear() { + var keys = uncloakedKeys(); + for (var i = 0; i < keys.length; i++) { + delete this[keys[i]]; + } + keys = cloakedKeys(); + for (var i = 0; i < keys.length; i++) { + delete cloak[keys[i]]; + } + }; - // Wrap in ES6 Proxy if available to support Object.keys() on a MemoryStorage object - return typeof Proxy === 'undefined' ? result : new Proxy(result, {ownKeys: function() {return enumerableKeys()}}) + // Wrap in ES6 Proxy if available to support Object.keys() on a MemoryStorage object + return typeof Proxy === "undefined" + ? result + : new Proxy(result, { + ownKeys: function () { + return enumerableKeys(); + }, + }); - // helper functions - function uncloakedKeys() {return Object.keys(result).filter(function(x){return !(x in API)})} - function cloakedKeys() {return Object.keys(cloak)} - function enumerableKeys(){return uncloakedKeys().concat(cloakedKeys())} + // helper functions + function uncloakedKeys() { + return Object.keys(result).filter(function (x) { + return !(x in API); + }); + } + function cloakedKeys() { + return Object.keys(cloak); + } + function enumerableKeys() { + return uncloakedKeys().concat(cloakedKeys()); + } } // API methods and properties will be cloaked -var API = {clear:1, getItem:1, id:1, key:1, length:1, removeItem:1, setItem:1} +var API = { clear: 1, getItem: 1, id: 1, key: 1, length: 1, removeItem: 1, setItem: 1 }; // Used to store all memorystorage objects var storage = {}; diff --git a/tests/test.js b/tests/test.js index 58d1479..b2e1238 100644 --- a/tests/test.js +++ b/tests/test.js @@ -1,112 +1,152 @@ -QUnit.test("W3C Web Storage API Compliance Test", function( assert ) { - var store = new MemoryStorage('local'); - - store.clear(); - assert.ok(store.length===0, "store cleared"); - store.setItem('test0', 'data0'); - assert.ok(store.length===1, "first item added to store"); - assert.ok(store.key(0)==='test0', "key registered"); - assert.ok(store.key(99)===null, "key() should return null when index out of bounds") - assert.ok(store.getItem('test0')==='data0', "value retrieved with getItem matches stored value"); - assert.ok(store['test0']==='data0', "value retrieved with index operators matches stored value"); - store['test0'] = 'changed'; - assert.ok(store['test0']==='changed', "value updated correctly with index operators."); - store['test1'] = 'data1'; - assert.ok(store.length===2, 'value added correctly with index operators'); - store.setItem('test2', 'data2'); - assert.ok(store.length===3, 'three items added to store'); - if (typeof Proxy === "undefined") { - assert.ok(Object.keys(store).length == (7+3), "store has 10 enumerable properties (id, 6 api methods + 3 stored items)"); - } - else { - assert.ok(Object.keys(store).length === 3, "store has 3 enumerable properties (no api methods + 3 stored items)"); - assert.ok(Object.keys(store).sort().join(',') === "test0,test1,test2", - "keys are enumerable with Object.keys()"); - } - assert.ok(store.getItem('test1')==='data1' && store.getItem('test2')==='data2', "retrieved values matches stored values"); - var keyOrderBefore = ''; - for (var i=0; i