From f4e1118e283aaacb74908587044513525554962e Mon Sep 17 00:00:00 2001 From: Branden Horiuchi Date: Wed, 17 Jan 2018 09:22:43 -0800 Subject: [PATCH] enforcing strict lodash path strings, readme update --- .eslintignore | 5 ++- README.md | 45 ++++++++++++++++++++++---- index.js | 73 ++++++++++++++++++++++++------------------ package.json | 2 +- src/index.js | 80 +++++++++++++++++++++++++--------------------- test/issue9.html | 14 +++++++- vue-deepset.js | 73 ++++++++++++++++++++++++------------------ vue-deepset.min.js | 2 +- 8 files changed, 185 insertions(+), 109 deletions(-) diff --git a/.eslintignore b/.eslintignore index cb88c73..fe762a0 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,6 @@ dist archive -test \ No newline at end of file +test +index.js +vue-deepset.js +vue-deepset.min.js \ No newline at end of file diff --git a/README.md b/README.md index 0f85b91..91a02e8 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ # vue-deepset -Deep set Vue.js objects +Deep set Vue.js objects using dynamic paths --- Binding deeply nested data properties and vuex data to a form or component can be tricky. The following set of tools aims to simplify data bindings. Compatible with `Vue 1.x`, `Vue 2.x`, `Vuex 1.x`, and `Vuex 2.x` -**Note** `vueModel` and `vuexModel` use [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) objects if supported by the browser and fallback to an object with generated fields based on the target object. Because of this, it is always best to pre-define the properties of an object. +**Note** `vueModel` and `vuexModel` use [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) objects if supported by the browser and fallback to an object with generated fields based on the target object. Because of this, it is always best to pre-define the properties of an object when using older browsers. -Also note that models are flat and once built can set vue/vuex directly using `model[path] = value` +Also note that models are flat and once built can set vue/vuex directly using `model[path] = value` where path is a lodash formatted path string or path array. ### Examples @@ -18,9 +18,41 @@ Full examples can be found in the [tests](/~https://github.com/bhoriuchi/vue-deeps * `vue@>=1.0.0` * `vuex@>=1.0.0` (optional) +### Dynamic paths + +If you knew what every path you needed ahead of time you could (while tedious) create custom computed properties with getter and setter methods for each of those properties. But what if you have a dynamic and deeply nested property? This problem was actually what inspired the creation of this library. Using a Proxy, `vue-deepset` is able to dynamically create new, deep, reactive properties as well as return `undefined` for values that are not yet set. + ### Path Strings -The modeling methods use `lodash.toPath` format for path strings. Please ensure references use this format +The modeling methods use `lodash.toPath` format for path strings. Please ensure references use this format. You may also use `path Arrays` which can be easier to construct when using keys that include dots. + +The following 2 path values are the same +```js +const stringPath = 'a.b["c.d"].e[0]' +const arrayPath = [ 'a', 'b', 'c.d', 'e', 0 ] +``` + +#### Keys with dots + +Since dots prefix a nested path and are also valid characters for a key data that looks like the following can be tricky + +```js +const data = { + 'foo.bar': 'baz', + foo: { + bar: 'qux' + } +} +``` + +So care should be taken when building the path string (or just use an array path) as the following will be true + +```js +'foo.bar' // qux +'["foo.bar"]' // baz +'foo["bar"]' // qux +'["foo"].bar' // qux +``` ### Binding `v-model` to deeply nested objects @@ -35,7 +67,7 @@ Model objects returned by `$deepModel`, `vueModel`, and `vuexModel` are flat and ## Usage * Webpack `import * as VueDeepSet from 'vue-deepset'` -* Browser `` +* Browser `` ### As a Plugin @@ -212,9 +244,8 @@ import { vueSet } from 'vue-deepset' export default { methods: { - vueSet: vueSet, clearForm () { - this.vueSet(this.localForm, 'message', '') + vueSet(this.localForm, 'message', '') } }, data: { diff --git a/index.js b/index.js index df619c7..55fa3aa 100644 --- a/index.js +++ b/index.js @@ -37,8 +37,11 @@ var rePropName = RegExp( // Or match "" as the space between consecutive dots or empty brackets. '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))', 'g'); -// modified from lodash +// modified from lodash - /~https://github.com/lodash/lodash function toPath(string) { + if (Array.isArray(string)) { + return string; + } var result = []; if (string.charCodeAt(0) === charCodeOfDot) { result.push(''); @@ -57,6 +60,14 @@ function toPath(string) { function noop() {} +function hasOwnProperty(object, property) { + return Object.prototype.hasOwnProperty.call(object, property); +} + +function deepsetError(message) { + return new Error('[vue-deepset]: ' + message); +} + function isObjectLike(object) { return (typeof object === 'undefined' ? 'undefined' : _typeof(object)) === 'object' && object !== null; } @@ -117,12 +128,11 @@ function getPaths(object) { pushPaths(val, (current + '.' + key).replace(/^\./, ''), paths); pushPaths(val, (current + '[' + key + ']').replace(/^\./, ''), paths); pushPaths(val, (current + '["' + key + '"]').replace(/^\./, ''), paths); - } else if (key.match(invalidKey) !== null) { - // must quote - pushPaths(val, (current + '["' + key + '"]').replace(/^\./, ''), paths); - } else { + } else if (!key.match(invalidKey)) { pushPaths(val, (current + '.' + key).replace(/^\./, ''), paths); } + // always add the absolute array notation path + pushPaths(val, (current + '["' + key + '"]').replace(/^\./, ''), paths); }); } return [].concat(new Set(paths)); @@ -145,14 +155,6 @@ function _get(obj, path, defaultValue) { return defaultValue; } -function hasOwnProperty(object, property) { - return Object.prototype.hasOwnProperty.call(object, property); -} - -function getProp(object, property) { - return Object.keys(object).indexOf(property) === -1 ? _get(object, property) : object[property]; -} - function getProxy(vm, base, options) { noop(options); // for future potential options var isVuex = typeof base === 'string'; @@ -160,7 +162,7 @@ function getProxy(vm, base, options) { return new Proxy(object, { get: function get(target, property) { - return getProp(target, property); + return _get(target, property); }, set: function set(target, property, value) { isVuex ? vuexSet.call(vm, pathJoin(base, property), value) : vueSet(target, property, value); @@ -183,7 +185,7 @@ function getProxy(vm, base, options) { }, getOwnPropertyDescriptor: function getOwnPropertyDescriptor(target, property) { return { - value: getProp(target, property), + value: _get(target, property), writable: false, enumerable: true, configurable: true @@ -230,22 +232,30 @@ function buildVuexModel(vm, vuexPath, options) { } function vueSet(object, path, value) { - var parts = toPath(path); - var obj = object; - while (parts.length) { - var key = parts.shift(); - if (!parts.length) { - _vue2.default.set(obj, key, value); - } else if (!hasOwnProperty(obj, key) || obj[key] === null) { - _vue2.default.set(obj, key, typeof key === 'number' ? [] : {}); + try { + var parts = toPath(path); + var obj = object; + while (parts.length) { + var key = parts.shift(); + if (!parts.length) { + _vue2.default.set(obj, key, value); + } else if (!hasOwnProperty(obj, key) || obj[key] === null) { + _vue2.default.set(obj, key, typeof key === 'number' ? [] : {}); + } + obj = obj[key]; } - obj = obj[key]; + return object; + } catch (err) { + throw deepsetError('vueSet unable to set object (' + err.message + ')'); } } function vuexSet(path, value) { - if (!this.$store) throw new Error('[vue-deepset]: could not find vuex store object on instance'); - this.$store[this.$store.commit ? 'commit' : 'dispatch']('VUEX_DEEP_SET', { path: path, value: value }); + if (!isObjectLike(this.$store)) { + throw deepsetError('could not find vuex store object on instance'); + } + var method = this.$store.commit ? 'commit' : 'dispatch'; + this.$store[method]('VUEX_DEEP_SET', { path: path, value: value }); } function VUEX_DEEP_SET(state, _ref) { @@ -264,7 +274,7 @@ function extendMutation() { function vueModel(object, options) { var opts = Object.assign({}, options); if (!isObjectLike(object)) { - throw new Error('[vue-deepset]: invalid object specified for vue model'); + throw deepsetError('invalid object specified for vue model'); } else if (opts.useProxy === false || typeof Proxy === 'undefined') { return buildVueModel(this, object, opts); } @@ -274,9 +284,11 @@ function vueModel(object, options) { function vuexModel(vuexPath, options) { var opts = Object.assign({}, options); if (typeof vuexPath !== 'string' || vuexPath === '') { - throw new Error('[vue-deepset]: invalid vuex path string'); + throw deepsetError('invalid vuex path string'); + } else if (!isObjectLike(this.$store) || !isObjectLike(this.$store.state)) { + throw deepsetError('no vuex state found'); } else if (!has(this.$store.state, vuexPath)) { - throw new Error('[vue-deepset]: Cannot find path "' + vuexPath + '" in Vuex store'); + throw deepsetError('cannot find path "' + vuexPath + '" in Vuex store'); } else if (opts.useProxy === false || typeof Proxy === 'undefined') { return buildVuexModel(this, vuexPath, opts); } @@ -288,8 +300,7 @@ function deepModel(base, options) { } function install(VueInstance) { - VueInstance.prototype.$vueModel = vueModel; - VueInstance.prototype.$vuexModel = vuexModel; VueInstance.prototype.$deepModel = deepModel; VueInstance.prototype.$vueSet = vueSet; + VueInstance.prototype.$vuexSet = vuexSet; } diff --git a/package.json b/package.json index 07d78d8..f433b3e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vue-deepset", - "version": "0.6.0", + "version": "0.6.1", "description": "Deep set Vue.js objects", "main": "index.js", "scripts": { diff --git a/src/index.js b/src/index.js index c26792f..5a4b68c 100644 --- a/src/index.js +++ b/src/index.js @@ -18,8 +18,11 @@ const rePropName = RegExp( '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))' , 'g') -// modified from lodash +// modified from lodash - /~https://github.com/lodash/lodash function toPath (string) { + if (Array.isArray(string)) { + return string + } const result = [] if (string.charCodeAt(0) === charCodeOfDot) { result.push('') @@ -38,13 +41,21 @@ function toPath (string) { function noop () {} +function hasOwnProperty (object, property) { + return Object.prototype.hasOwnProperty.call(object, property) +} + +function deepsetError (message) { + return new Error(`[vue-deepset]: ${message}`); +} + function isObjectLike (object) { return typeof object === 'object' && object !== null } function pathJoin (base, path) { try { - let connector = path.match(/^\[/) ? '' : '.' + const connector = path.match(/^\[/) ? '' : '.' return `${base || ''}${base ? connector : ''}${path}` } catch (error) { return '' @@ -96,11 +107,11 @@ function getPaths (object, current = '', paths = []) { pushPaths(val, `${current}.${key}`.replace(/^\./, ''), paths) pushPaths(val, `${current}[${key}]`.replace(/^\./, ''), paths) pushPaths(val, `${current}["${key}"]`.replace(/^\./, ''), paths) - } else if (key.match(invalidKey) !== null) { // must quote - pushPaths(val, `${current}["${key}"]`.replace(/^\./, ''), paths) - } else { + } else if (!key.match(invalidKey)) { pushPaths(val, `${current}.${key}`.replace(/^\./, ''), paths) } + // always add the absolute array notation path + pushPaths(val, `${current}["${key}"]`.replace(/^\./, ''), paths) }) } return [ ...new Set(paths) ] @@ -109,9 +120,7 @@ function getPaths (object, current = '', paths = []) { function get (obj, path, defaultValue) { try { let o = obj - const fields = Array.isArray(path) - ? path - : toPath(path) + const fields = Array.isArray(path) ? path : toPath(path) while (fields.length) { const prop = fields.shift() o = o[prop] @@ -125,16 +134,6 @@ function get (obj, path, defaultValue) { return defaultValue } -function hasOwnProperty (object, property) { - return Object.prototype.hasOwnProperty.call(object, property) -} - -function getProp (object, property) { - return Object.keys(object).indexOf(property) === -1 - ? get(object, property) - : object[property] -} - function getProxy (vm, base, options) { noop(options) // for future potential options const isVuex = typeof base === 'string' @@ -142,7 +141,7 @@ function getProxy (vm, base, options) { return new Proxy(object, { get: (target, property) => { - return getProp(target, property) + return get(target, property) }, set: (target, property, value) => { isVuex @@ -167,7 +166,7 @@ function getProxy (vm, base, options) { }, getOwnPropertyDescriptor: (target, property) => { return { - value: getProp(target, property), + value: get(target, property), writable: false, enumerable: true, configurable: true @@ -206,22 +205,30 @@ function buildVuexModel (vm, vuexPath, options) { } export function vueSet (object, path, value) { - const parts = toPath(path) - let obj = object - while (parts.length) { - const key = parts.shift() - if (!parts.length) { - Vue.set(obj, key, value) - } else if (!hasOwnProperty(obj, key) || obj[key] === null) { - Vue.set(obj, key, typeof key === 'number' ? [] : {}) + try { + const parts = toPath(path) + let obj = object + while (parts.length) { + const key = parts.shift() + if (!parts.length) { + Vue.set(obj, key, value) + } else if (!hasOwnProperty(obj, key) || obj[key] === null) { + Vue.set(obj, key, typeof key === 'number' ? [] : {}) + } + obj = obj[key] } - obj = obj[key] + return object + } catch (err) { + throw deepsetError(`vueSet unable to set object (${err.message})`) } } export function vuexSet (path, value) { - if (!this.$store) throw new Error('[vue-deepset]: could not find vuex store object on instance') - this.$store[this.$store.commit ? 'commit' : 'dispatch']('VUEX_DEEP_SET', { path, value }) + if (!isObjectLike(this.$store)) { + throw deepsetError('could not find vuex store object on instance') + } + const method = this.$store.commit ? 'commit' : 'dispatch' + this.$store[method]('VUEX_DEEP_SET', { path, value }) } export function VUEX_DEEP_SET (state, { path, value }) { @@ -235,7 +242,7 @@ export function extendMutation (mutations = {}) { export function vueModel (object, options) { const opts = Object.assign({}, options) if (!isObjectLike(object)) { - throw new Error('[vue-deepset]: invalid object specified for vue model') + throw deepsetError('invalid object specified for vue model') } else if (opts.useProxy === false || typeof Proxy === 'undefined') { return buildVueModel(this, object, opts) } @@ -245,9 +252,11 @@ export function vueModel (object, options) { export function vuexModel (vuexPath, options) { const opts = Object.assign({}, options) if (typeof vuexPath !== 'string' || vuexPath === '') { - throw new Error('[vue-deepset]: invalid vuex path string') + throw deepsetError('invalid vuex path string') + } else if (!isObjectLike(this.$store) || !isObjectLike(this.$store.state)) { + throw deepsetError('no vuex state found') } else if (!has(this.$store.state, vuexPath)) { - throw new Error(`[vue-deepset]: Cannot find path "${vuexPath}" in Vuex store`) + throw deepsetError(`cannot find path "${vuexPath}" in Vuex store`) } else if (opts.useProxy === false || typeof Proxy === 'undefined') { return buildVuexModel(this, vuexPath, opts) } @@ -261,8 +270,7 @@ export function deepModel (base, options) { } export function install (VueInstance) { - VueInstance.prototype.$vueModel = vueModel - VueInstance.prototype.$vuexModel = vuexModel VueInstance.prototype.$deepModel = deepModel VueInstance.prototype.$vueSet = vueSet + VueInstance.prototype.$vuexSet = vuexSet } diff --git a/test/issue9.html b/test/issue9.html index 2de0026..4381ac1 100644 --- a/test/issue9.html +++ b/test/issue9.html @@ -12,6 +12,12 @@
+
+ +
+ +
+

 
 
@@ -23,6 +29,9 @@
       return {
         path1: '["test.a"].a.c',
         path2: '["propertygroup.a"]',
+        path3: '["propertygroup.b"]',
+        path4: 'propertygroup["b"]',
+        path5: ['propertygroup.b'],
         data: {
           'test.a': {
             a: {
@@ -30,7 +39,10 @@
             }
           },
           'propertygroup.a': 'value-a',
-          'propertygroup.b': 'balue-b'
+          'propertygroup.b': 'value-b',
+          propertygroup: {
+            b: 'x'
+          }
         }
       }
     },
diff --git a/vue-deepset.js b/vue-deepset.js
index 2102491..ea0450c 100644
--- a/vue-deepset.js
+++ b/vue-deepset.js
@@ -38,8 +38,11 @@ var rePropName = RegExp(
 // Or match "" as the space between consecutive dots or empty brackets.
 '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))', 'g');
 
-// modified from lodash
+// modified from lodash - /~https://github.com/lodash/lodash
 function toPath(string) {
+  if (Array.isArray(string)) {
+    return string;
+  }
   var result = [];
   if (string.charCodeAt(0) === charCodeOfDot) {
     result.push('');
@@ -58,6 +61,14 @@ function toPath(string) {
 
 function noop() {}
 
+function hasOwnProperty(object, property) {
+  return Object.prototype.hasOwnProperty.call(object, property);
+}
+
+function deepsetError(message) {
+  return new Error('[vue-deepset]: ' + message);
+}
+
 function isObjectLike(object) {
   return (typeof object === 'undefined' ? 'undefined' : _typeof(object)) === 'object' && object !== null;
 }
@@ -118,12 +129,11 @@ function getPaths(object) {
         pushPaths(val, (current + '.' + key).replace(/^\./, ''), paths);
         pushPaths(val, (current + '[' + key + ']').replace(/^\./, ''), paths);
         pushPaths(val, (current + '["' + key + '"]').replace(/^\./, ''), paths);
-      } else if (key.match(invalidKey) !== null) {
-        // must quote
-        pushPaths(val, (current + '["' + key + '"]').replace(/^\./, ''), paths);
-      } else {
+      } else if (!key.match(invalidKey)) {
         pushPaths(val, (current + '.' + key).replace(/^\./, ''), paths);
       }
+      // always add the absolute array notation path
+      pushPaths(val, (current + '["' + key + '"]').replace(/^\./, ''), paths);
     });
   }
   return [].concat(new Set(paths));
@@ -146,14 +156,6 @@ function _get(obj, path, defaultValue) {
   return defaultValue;
 }
 
-function hasOwnProperty(object, property) {
-  return Object.prototype.hasOwnProperty.call(object, property);
-}
-
-function getProp(object, property) {
-  return Object.keys(object).indexOf(property) === -1 ? _get(object, property) : object[property];
-}
-
 function getProxy(vm, base, options) {
   noop(options); // for future potential options
   var isVuex = typeof base === 'string';
@@ -161,7 +163,7 @@ function getProxy(vm, base, options) {
 
   return new Proxy(object, {
     get: function get(target, property) {
-      return getProp(target, property);
+      return _get(target, property);
     },
     set: function set(target, property, value) {
       isVuex ? vuexSet.call(vm, pathJoin(base, property), value) : vueSet(target, property, value);
@@ -184,7 +186,7 @@ function getProxy(vm, base, options) {
     },
     getOwnPropertyDescriptor: function getOwnPropertyDescriptor(target, property) {
       return {
-        value: getProp(target, property),
+        value: _get(target, property),
         writable: false,
         enumerable: true,
         configurable: true
@@ -231,22 +233,30 @@ function buildVuexModel(vm, vuexPath, options) {
 }
 
 function vueSet(object, path, value) {
-  var parts = toPath(path);
-  var obj = object;
-  while (parts.length) {
-    var key = parts.shift();
-    if (!parts.length) {
-      _vue2.default.set(obj, key, value);
-    } else if (!hasOwnProperty(obj, key) || obj[key] === null) {
-      _vue2.default.set(obj, key, typeof key === 'number' ? [] : {});
+  try {
+    var parts = toPath(path);
+    var obj = object;
+    while (parts.length) {
+      var key = parts.shift();
+      if (!parts.length) {
+        _vue2.default.set(obj, key, value);
+      } else if (!hasOwnProperty(obj, key) || obj[key] === null) {
+        _vue2.default.set(obj, key, typeof key === 'number' ? [] : {});
+      }
+      obj = obj[key];
     }
-    obj = obj[key];
+    return object;
+  } catch (err) {
+    throw deepsetError('vueSet unable to set object (' + err.message + ')');
   }
 }
 
 function vuexSet(path, value) {
-  if (!this.$store) throw new Error('[vue-deepset]: could not find vuex store object on instance');
-  this.$store[this.$store.commit ? 'commit' : 'dispatch']('VUEX_DEEP_SET', { path: path, value: value });
+  if (!isObjectLike(this.$store)) {
+    throw deepsetError('could not find vuex store object on instance');
+  }
+  var method = this.$store.commit ? 'commit' : 'dispatch';
+  this.$store[method]('VUEX_DEEP_SET', { path: path, value: value });
 }
 
 function VUEX_DEEP_SET(state, _ref) {
@@ -265,7 +275,7 @@ function extendMutation() {
 function vueModel(object, options) {
   var opts = Object.assign({}, options);
   if (!isObjectLike(object)) {
-    throw new Error('[vue-deepset]: invalid object specified for vue model');
+    throw deepsetError('invalid object specified for vue model');
   } else if (opts.useProxy === false || typeof Proxy === 'undefined') {
     return buildVueModel(this, object, opts);
   }
@@ -275,9 +285,11 @@ function vueModel(object, options) {
 function vuexModel(vuexPath, options) {
   var opts = Object.assign({}, options);
   if (typeof vuexPath !== 'string' || vuexPath === '') {
-    throw new Error('[vue-deepset]: invalid vuex path string');
+    throw deepsetError('invalid vuex path string');
+  } else if (!isObjectLike(this.$store) || !isObjectLike(this.$store.state)) {
+    throw deepsetError('no vuex state found');
   } else if (!has(this.$store.state, vuexPath)) {
-    throw new Error('[vue-deepset]: Cannot find path "' + vuexPath + '" in Vuex store');
+    throw deepsetError('cannot find path "' + vuexPath + '" in Vuex store');
   } else if (opts.useProxy === false || typeof Proxy === 'undefined') {
     return buildVuexModel(this, vuexPath, opts);
   }
@@ -289,10 +301,9 @@ function deepModel(base, options) {
 }
 
 function install(VueInstance) {
-  VueInstance.prototype.$vueModel = vueModel;
-  VueInstance.prototype.$vuexModel = vuexModel;
   VueInstance.prototype.$deepModel = deepModel;
   VueInstance.prototype.$vueSet = vueSet;
+  VueInstance.prototype.$vuexSet = vuexSet;
 }
 
 },{}]},{},[1])(1)
diff --git a/vue-deepset.min.js b/vue-deepset.min.js
index 9cd8bb5..c84fc22 100644
--- a/vue-deepset.min.js
+++ b/vue-deepset.min.js
@@ -1 +1 @@
-(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.VueDeepSet=f()}})(function(){var define,module,exports;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o1&&arguments[1]!==undefined?arguments[1]:"";var paths=arguments.length>2&&arguments[2]!==undefined?arguments[2]:[];if(Array.isArray(object)){forEach(object,function(val,idx){pushPaths(val,(current+"."+idx).replace(/^\./,""),paths);pushPaths(val,(current+"["+idx+"]").replace(/^\./,""),paths);pushPaths(val,(current+'["'+idx+'"]').replace(/^\./,""),paths)})}else if(isObjectLike(object)){forEach(object,function(val,key){if(key.match(intKey)!==null){pushPaths(val,(current+"."+key).replace(/^\./,""),paths);pushPaths(val,(current+"["+key+"]").replace(/^\./,""),paths);pushPaths(val,(current+'["'+key+'"]').replace(/^\./,""),paths)}else if(key.match(invalidKey)!==null){pushPaths(val,(current+'["'+key+'"]').replace(/^\./,""),paths)}else{pushPaths(val,(current+"."+key).replace(/^\./,""),paths)}})}return[].concat(new Set(paths))}function _get(obj,path,defaultValue){try{var o=obj;var fields=Array.isArray(path)?path:toPath(path);while(fields.length){var prop=fields.shift();o=o[prop];if(!fields.length){return o}}}catch(err){return defaultValue}return defaultValue}function hasOwnProperty(object,property){return Object.prototype.hasOwnProperty.call(object,property)}function getProp(object,property){return Object.keys(object).indexOf(property)===-1?_get(object,property):object[property]}function getProxy(vm,base,options){noop(options);var isVuex=typeof base==="string";var object=isVuex?_get(vm.$store.state,base):base;return new Proxy(object,{get:function get(target,property){return getProp(target,property)},set:function set(target,property,value){isVuex?vuexSet.call(vm,pathJoin(base,property),value):vueSet(target,property,value);return true},deleteProperty:function deleteProperty(){return true},enumerate:function enumerate(target){return Object.keys(target)},ownKeys:function ownKeys(target){return Object.keys(target)},has:function has(target,property){return true},defineProperty:function defineProperty(target){return target},getOwnPropertyDescriptor:function getOwnPropertyDescriptor(target,property){return{value:getProp(target,property),writable:false,enumerable:true,configurable:true}}})}function buildVueModel(vm,object,options){var model={};forEach(getPaths(object),function(path){Object.defineProperty(model,path,{configurable:true,enumerable:true,get:function get(){return _get(object,path)},set:function set(value){return vueSet(object,path,value)}})});return model}function buildVuexModel(vm,vuexPath,options){var model=Object.create(null);var object=_get(vm.$store.state,vuexPath);var paths=getPaths(object);forEach(paths,function(path){var propPath=pathJoin(vuexPath,path);Object.defineProperty(model,path,{configurable:true,enumerable:true,get:function get(){return _get(vm.$store.state,propPath)},set:function set(value){return vuexSet.call(vm,propPath,value)}})});return model}function vueSet(object,path,value){var parts=toPath(path);var obj=object;while(parts.length){var key=parts.shift();if(!parts.length){_vue2.default.set(obj,key,value)}else if(!hasOwnProperty(obj,key)||obj[key]===null){_vue2.default.set(obj,key,typeof key==="number"?[]:{})}obj=obj[key]}}function vuexSet(path,value){if(!this.$store)throw new Error("[vue-deepset]: could not find vuex store object on instance");this.$store[this.$store.commit?"commit":"dispatch"]("VUEX_DEEP_SET",{path:path,value:value})}function VUEX_DEEP_SET(state,_ref){var path=_ref.path,value=_ref.value;vueSet(state,path,value)}function extendMutation(){var mutations=arguments.length>0&&arguments[0]!==undefined?arguments[0]:{};return Object.assign(mutations,{VUEX_DEEP_SET:VUEX_DEEP_SET})}function vueModel(object,options){var opts=Object.assign({},options);if(!isObjectLike(object)){throw new Error("[vue-deepset]: invalid object specified for vue model")}else if(opts.useProxy===false||typeof Proxy==="undefined"){return buildVueModel(this,object,opts)}return getProxy(this,object,opts)}function vuexModel(vuexPath,options){var opts=Object.assign({},options);if(typeof vuexPath!=="string"||vuexPath===""){throw new Error("[vue-deepset]: invalid vuex path string")}else if(!has(this.$store.state,vuexPath)){throw new Error('[vue-deepset]: Cannot find path "'+vuexPath+'" in Vuex store')}else if(opts.useProxy===false||typeof Proxy==="undefined"){return buildVuexModel(this,vuexPath,opts)}return getProxy(this,vuexPath,opts)}function deepModel(base,options){return typeof base==="string"?vuexModel.call(this,base,options):vueModel.call(this,base,options)}function install(VueInstance){VueInstance.prototype.$vueModel=vueModel;VueInstance.prototype.$vuexModel=vuexModel;VueInstance.prototype.$deepModel=deepModel;VueInstance.prototype.$vueSet=vueSet}},{}]},{},[1])(1)});
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.VueDeepSet=f()}})(function(){var define,module,exports;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o1&&arguments[1]!==undefined?arguments[1]:"";var paths=arguments.length>2&&arguments[2]!==undefined?arguments[2]:[];if(Array.isArray(object)){forEach(object,function(val,idx){pushPaths(val,(current+"."+idx).replace(/^\./,""),paths);pushPaths(val,(current+"["+idx+"]").replace(/^\./,""),paths);pushPaths(val,(current+'["'+idx+'"]').replace(/^\./,""),paths)})}else if(isObjectLike(object)){forEach(object,function(val,key){if(key.match(intKey)!==null){pushPaths(val,(current+"."+key).replace(/^\./,""),paths);pushPaths(val,(current+"["+key+"]").replace(/^\./,""),paths);pushPaths(val,(current+'["'+key+'"]').replace(/^\./,""),paths)}else if(!key.match(invalidKey)){pushPaths(val,(current+"."+key).replace(/^\./,""),paths)}pushPaths(val,(current+'["'+key+'"]').replace(/^\./,""),paths)})}return[].concat(new Set(paths))}function _get(obj,path,defaultValue){try{var o=obj;var fields=Array.isArray(path)?path:toPath(path);while(fields.length){var prop=fields.shift();o=o[prop];if(!fields.length){return o}}}catch(err){return defaultValue}return defaultValue}function getProxy(vm,base,options){noop(options);var isVuex=typeof base==="string";var object=isVuex?_get(vm.$store.state,base):base;return new Proxy(object,{get:function get(target,property){return _get(target,property)},set:function set(target,property,value){isVuex?vuexSet.call(vm,pathJoin(base,property),value):vueSet(target,property,value);return true},deleteProperty:function deleteProperty(){return true},enumerate:function enumerate(target){return Object.keys(target)},ownKeys:function ownKeys(target){return Object.keys(target)},has:function has(target,property){return true},defineProperty:function defineProperty(target){return target},getOwnPropertyDescriptor:function getOwnPropertyDescriptor(target,property){return{value:_get(target,property),writable:false,enumerable:true,configurable:true}}})}function buildVueModel(vm,object,options){var model={};forEach(getPaths(object),function(path){Object.defineProperty(model,path,{configurable:true,enumerable:true,get:function get(){return _get(object,path)},set:function set(value){return vueSet(object,path,value)}})});return model}function buildVuexModel(vm,vuexPath,options){var model=Object.create(null);var object=_get(vm.$store.state,vuexPath);var paths=getPaths(object);forEach(paths,function(path){var propPath=pathJoin(vuexPath,path);Object.defineProperty(model,path,{configurable:true,enumerable:true,get:function get(){return _get(vm.$store.state,propPath)},set:function set(value){return vuexSet.call(vm,propPath,value)}})});return model}function vueSet(object,path,value){try{var parts=toPath(path);var obj=object;while(parts.length){var key=parts.shift();if(!parts.length){_vue2.default.set(obj,key,value)}else if(!hasOwnProperty(obj,key)||obj[key]===null){_vue2.default.set(obj,key,typeof key==="number"?[]:{})}obj=obj[key]}return object}catch(err){throw deepsetError("vueSet unable to set object ("+err.message+")")}}function vuexSet(path,value){if(!isObjectLike(this.$store)){throw deepsetError("could not find vuex store object on instance")}var method=this.$store.commit?"commit":"dispatch";this.$store[method]("VUEX_DEEP_SET",{path:path,value:value})}function VUEX_DEEP_SET(state,_ref){var path=_ref.path,value=_ref.value;vueSet(state,path,value)}function extendMutation(){var mutations=arguments.length>0&&arguments[0]!==undefined?arguments[0]:{};return Object.assign(mutations,{VUEX_DEEP_SET:VUEX_DEEP_SET})}function vueModel(object,options){var opts=Object.assign({},options);if(!isObjectLike(object)){throw deepsetError("invalid object specified for vue model")}else if(opts.useProxy===false||typeof Proxy==="undefined"){return buildVueModel(this,object,opts)}return getProxy(this,object,opts)}function vuexModel(vuexPath,options){var opts=Object.assign({},options);if(typeof vuexPath!=="string"||vuexPath===""){throw deepsetError("invalid vuex path string")}else if(!isObjectLike(this.$store)||!isObjectLike(this.$store.state)){throw deepsetError("no vuex state found")}else if(!has(this.$store.state,vuexPath)){throw deepsetError('cannot find path "'+vuexPath+'" in Vuex store')}else if(opts.useProxy===false||typeof Proxy==="undefined"){return buildVuexModel(this,vuexPath,opts)}return getProxy(this,vuexPath,opts)}function deepModel(base,options){return typeof base==="string"?vuexModel.call(this,base,options):vueModel.call(this,base,options)}function install(VueInstance){VueInstance.prototype.$deepModel=deepModel;VueInstance.prototype.$vueSet=vueSet;VueInstance.prototype.$vuexSet=vuexSet}},{}]},{},[1])(1)});