diff --git a/.gitignore b/.gitignore index 3c3629e..09ad9b7 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,9 @@ node_modules + +# OS generated files # +.DS_Store +.DS_Store? +.Trashes + +# PhpStorm project files # +.idea \ No newline at end of file diff --git a/.jshintrc b/.jshintrc index 307db79..3f8ac31 100644 --- a/.jshintrc +++ b/.jshintrc @@ -16,6 +16,7 @@ "browser": true, "shadow": true, "devel": true, + "esnext": true, "globals": { "define": false, diff --git a/dist/memorystorage.min.js b/dist/memorystorage.min.js index 47881a0..639f864 100644 --- a/dist/memorystorage.min.js +++ b/dist/memorystorage.min.js @@ -1,3 +1,3 @@ -/*! [memorystorage 0.9.10](http://download.github.io/memorystorage) Copyright 2015 by [Stijn de Witt](http://StijnDeWitt.com). Some rights reserved. License: [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/) */ -!function(u,m,d){"function"==typeof define&&define.amd?define("memorystorage",[],function(){return d()}):"object"==typeof exports?module.exports=d():u[m]=d()}(this,"MemoryStorage",function(){"use strict";function MemoryStorage(f){f=f||"global";var g=e[f];if(g)return g;if(!(this instanceof MemoryStorage))return new MemoryStorage(f);g=e[f]=this;var h={};return Object.defineProperty(g,c,{enumerable:!1,get:function(){return h}}),Object.defineProperty(g,"id",{enumerable:!0,get:function(){return f}}),Object.defineProperty(g,"length",{enumerable:!0,get:function(){return Object.keys(this).length+Object.keys(this[c]).length-b}}),g.getItem=function(b){return b in a?this[c][b]:this[b]},g.setItem=function(b,e){b in a?this[c][b]=e:this[b]=e},g.removeItem=function(b){b in a?delete this[c][b]:delete this[b]},g.key=function(b){var e=Object.keys(this).concat(Object.keys(this[c]));return e=e.filter(function(b){return!(b in a)}),b>=0&&b=0&&a} + */ + function enumerableKeys(){ + var keys = Object.keys(result).filter(function(x){return !(x in API);}); + return keys.concat(Object.keys(cloaked)); + } + // Allow client code to read the id Object.defineProperty(result, 'id', { enumerable: true, + configurable: true, get: function(){return id;} }); // Create the length property Object.defineProperty(result, 'length', { enumerable: true, + configurable: true, get: function(){ - return Object.keys(this).length + Object.keys(this[CLOAK]).length - API_LENGTH; + return enumerableKeys().length; } }); // Create API methods @@ -79,9 +90,13 @@ function MemoryStorage(id) {// jshint ignore:line if (key in API) {delete this[CLOAK][key];} else {delete this[key];} }; + /** + * Needed to enumerate over all items in the collection + * @param {Number} idx - the index + * @returns {null|string} - the name of the nth key in the storage + */ result.key = function MemoryStorage_key(idx) { - var keys = Object.keys(this).concat(Object.keys(this[CLOAK])); - keys = keys.filter(function(x){return !(x in API);}); + var keys = enumerableKeys(); return idx >= 0 && idx < keys.length ? keys[idx] : null; }; result.clear = function MemoryStorage_clear() { @@ -94,7 +109,17 @@ function MemoryStorage(id) {// jshint ignore:line delete this[CLOAK][key]; } }; - return result; + + if (typeof Proxy === 'undefined') + { + return result; + } + // ES6 Proxy to support Object.keys() on a MemoryStorage object + return new Proxy(result, { + ownKeys: function() { + return enumerableKeys(); + } + }); } diff --git a/package.json b/package.json index ec041ef..6fdefc7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "memorystorage", - "version": "0.9.10", + "version": "0.9.12", "description": "Memory-backed implementation of the Web Storage API", "src": "src/memorystorage.js", "main": "dist/memorystorage.umd.js", @@ -40,7 +40,7 @@ }, "homepage": "http://download.github.io/memorystorage", "devDependencies": { - "grunt": "~0.4.5", + "grunt": "^0.4.5", "grunt-contrib-jshint": "~0.10.0", "grunt-contrib-uglify": "~0.6.0", "grunt-jsdoc": "~0.6.7", diff --git a/src/memorystorage.js b/src/memorystorage.js index 13a044f..d258f3b 100644 --- a/src/memorystorage.js +++ b/src/memorystorage.js @@ -6,7 +6,6 @@ */ // API methods and properties will be cloaked var API = {'clear':1, 'getItem':1, 'id':1, 'key':1, 'length':1, 'removeItem':1, 'setItem':1}, - API_LENGTH = Object.keys(API).length, CLOAK = '__memorystorage_cloaked_items__'; // Used to store all memorystorage objects @@ -47,18 +46,30 @@ function MemoryStorage(id) {// jshint ignore:line var cloaked = {}; Object.defineProperty(result, CLOAK, { enumerable: false, + configurable: true, get: function(){return cloaked;} }); + /** + * private method to find all enumerable keys + * @returns {Array.} + */ + function enumerableKeys(){ + var keys = Object.keys(result).filter(function(x){return !(x in API);}); + return keys.concat(Object.keys(cloaked)); + } + // Allow client code to read the id Object.defineProperty(result, 'id', { enumerable: true, + configurable: true, get: function(){return id;} }); // Create the length property Object.defineProperty(result, 'length', { enumerable: true, + configurable: true, get: function(){ - return Object.keys(this).length + Object.keys(this[CLOAK]).length - API_LENGTH; + return enumerableKeys().length; } }); // Create API methods @@ -73,9 +84,13 @@ function MemoryStorage(id) {// jshint ignore:line if (key in API) {delete this[CLOAK][key];} else {delete this[key];} }; + /** + * Needed to enumerate over all items in the collection + * @param {Number} idx - the index + * @returns {null|string} - the name of the nth key in the storage + */ result.key = function MemoryStorage_key(idx) { - var keys = Object.keys(this).concat(Object.keys(this[CLOAK])); - keys = keys.filter(function(x){return !(x in API);}); + var keys = enumerableKeys(); return idx >= 0 && idx < keys.length ? keys[idx] : null; }; result.clear = function MemoryStorage_clear() { @@ -88,5 +103,15 @@ function MemoryStorage(id) {// jshint ignore:line delete this[CLOAK][key]; } }; - return result; + + if (typeof Proxy === 'undefined') + { + return result; + } + // ES6 Proxy to support Object.keys() on a MemoryStorage object + return new Proxy(result, { + ownKeys: function() { + return enumerableKeys(); + } + }); } diff --git a/tests/index.html b/tests/index.html index 92b52ee..64e1c1c 100644 --- a/tests/index.html +++ b/tests/index.html @@ -3,6 +3,7 @@ MemoryStorage Tests + Restart | Next Test diff --git a/tests/test.js b/tests/test.js index 19d5e46..a8203ca 100644 --- a/tests/test.js +++ b/tests/test.js @@ -15,7 +15,14 @@ QUnit.test("W3C Web Storage API Compliance Test", function( assert ) { 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'); - assert.ok(Object.keys(store).length == (7+3), "store has 10 enumerable properties (id, 6 api methods + 3 stored items)"); + 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