diff --git a/index.js b/index.js
index 78f4903..c0a8931 100644
--- a/index.js
+++ b/index.js
@@ -23,39 +23,25 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
var invalidKey = /^\d|[^a-zA-Z0-9_]/gm;
var intKey = /^\d+$/;
-var charCodeOfDot = '.'.charCodeAt(0);
-var reEscapeChar = /\\(\\)?/g;
-var rePropName = RegExp(
-// Match anything that isn't a dot or bracket.
-'[^.[\\]]+' + '|' +
-// Or match property names within brackets.
-'\\[(?:' +
-// Match a non-string expression.
-'([^"\'].*)' + '|' +
-// Or match strings (supports escaping characters).
-'(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' + ')\\]' + '|' +
-// Or match "" as the space between consecutive dots or empty brackets.
-'(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))', 'g');
-
-// 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('');
- }
- string.replace(rePropName, function (match, expression, quote, subString) {
- var key = match;
- if (quote) {
- key = subString.replace(reEscapeChar, '$1');
- } else if (expression) {
- key = expression.trim();
- }
- result.push(key);
+
+function isNumberLike(value) {
+ return String(value).match(/^\d+$/);
+}
+
+function toPath(pathString) {
+ if (Array.isArray(pathString)) return pathString;
+ if (typeof pathString === 'number') return [pathString];
+ pathString = String(pathString);
+
+ // taken from lodash - /~https://github.com/lodash/lodash
+ var pathRx = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(\.|\[\])(?:\4|$))/g;
+ var pathArray = [];
+
+ pathString.replace(pathRx, function (match, number, quote, string) {
+ pathArray.push(quote ? string : number !== undefined ? Number(number) : match);
+ return pathArray[pathArray.length - 1];
});
- return result;
+ return pathArray;
}
function noop() {}
@@ -141,7 +127,7 @@ function getPaths(object) {
function _get(obj, path, defaultValue) {
try {
var o = obj;
- var fields = Array.isArray(path) ? path : toPath(path);
+ var fields = toPath(path);
while (fields.length) {
var prop = fields.shift();
o = o[prop];
@@ -231,23 +217,16 @@ function buildVuexModel(vm, vuexPath, options) {
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 vueSet(obj, path, value) {
+ var fields = Array.isArray(path) ? path : toPath(path);
+ var prop = fields.shift();
+
+ if (!fields.length) return _vue2.default.set(obj, prop, value);
+ if (!hasOwnProperty(obj, prop) || obj[prop] === null) {
+ var objVal = fields.length >= 1 && isNumberLike(fields[0]) ? [] : {};
+ _vue2.default.set(obj, prop, objVal);
}
+ vueSet(obj[prop], fields, value);
}
function vuexSet(path, value) {
diff --git a/package.json b/package.json
index 461ec93..5a56bf2 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "vue-deepset",
- "version": "0.6.2",
+ "version": "0.6.3",
"description": "Deep set Vue.js objects",
"main": "index.js",
"scripts": {
diff --git a/src/index.js b/src/index.js
index abe6db1..2cb0fab 100644
--- a/src/index.js
+++ b/src/index.js
@@ -2,41 +2,31 @@ import Vue from 'vue'
const invalidKey = /^\d|[^a-zA-Z0-9_]/gm
const intKey = /^\d+$/
-const charCodeOfDot = '.'.charCodeAt(0)
-const reEscapeChar = /\\(\\)?/g
-const rePropName = RegExp(
- // Match anything that isn't a dot or bracket.
- '[^.[\\]]+' + '|' +
- // Or match property names within brackets.
- '\\[(?:' +
- // Match a non-string expression.
- '([^"\'].*)' + '|' +
- // Or match strings (supports escaping characters).
- '(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' +
- ')\\]' + '|' +
- // Or match "" as the space between consecutive dots or empty brackets.
- '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))'
- , 'g')
-// 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('')
- }
- string.replace(rePropName, (match, expression, quote, subString) => {
- let key = match
- if (quote) {
- key = subString.replace(reEscapeChar, '$1')
- } else if (expression) {
- key = expression.trim()
- }
- result.push(key)
+function isNumberLike(value) {
+ return String(value).match(/^\d+$/);
+}
+
+function toPath (pathString) {
+ if (Array.isArray(pathString)) return pathString
+ if (typeof pathString === 'number') return [ pathString ]
+ pathString = String(pathString)
+
+ // taken from lodash - /~https://github.com/lodash/lodash
+ let pathRx = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(\.|\[\])(?:\4|$))/g
+ let pathArray = []
+
+ pathString.replace(pathRx, (match, number, quote, string) => {
+ pathArray.push(
+ quote
+ ? string
+ : number !== undefined
+ ? Number(number)
+ : match
+ )
+ return pathArray[pathArray.length - 1]
})
- return result
+ return pathArray
}
function noop () {}
@@ -120,7 +110,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 = toPath(path)
while (fields.length) {
const prop = fields.shift()
o = o[prop]
@@ -204,23 +194,20 @@ function buildVuexModel (vm, vuexPath, options) {
return model
}
-export function vueSet (object, path, value) {
- 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]
- }
- return object
- } catch (err) {
- throw deepsetError(`vueSet unable to set object (${err.message})`)
+export function vueSet (obj, path, value) {
+ let fields = Array.isArray(path)
+ ? path
+ : toPath(path)
+ let prop = fields.shift()
+
+ if (!fields.length) return Vue.set(obj, prop, value)
+ if (!hasOwnProperty(obj, prop) || obj[prop] === null) {
+ const objVal = fields.length >= 1 && isNumberLike(fields[0])
+ ? []
+ : {}
+ Vue.set(obj, prop, objVal)
}
+ vueSet(obj[prop], fields, value)
}
export function vuexSet (path, value) {
diff --git a/test/issue12.html b/test/issue12.html
new file mode 100644
index 0000000..bea847b
--- /dev/null
+++ b/test/issue12.html
@@ -0,0 +1,97 @@
+
+
+
+
+ Reproduce issue 12
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vue-deepset.js b/vue-deepset.js
index ade9ae6..8cd4aeb 100644
--- a/vue-deepset.js
+++ b/vue-deepset.js
@@ -24,39 +24,25 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
var invalidKey = /^\d|[^a-zA-Z0-9_]/gm;
var intKey = /^\d+$/;
-var charCodeOfDot = '.'.charCodeAt(0);
-var reEscapeChar = /\\(\\)?/g;
-var rePropName = RegExp(
-// Match anything that isn't a dot or bracket.
-'[^.[\\]]+' + '|' +
-// Or match property names within brackets.
-'\\[(?:' +
-// Match a non-string expression.
-'([^"\'].*)' + '|' +
-// Or match strings (supports escaping characters).
-'(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' + ')\\]' + '|' +
-// Or match "" as the space between consecutive dots or empty brackets.
-'(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))', 'g');
-
-// 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('');
- }
- string.replace(rePropName, function (match, expression, quote, subString) {
- var key = match;
- if (quote) {
- key = subString.replace(reEscapeChar, '$1');
- } else if (expression) {
- key = expression.trim();
- }
- result.push(key);
+
+function isNumberLike(value) {
+ return String(value).match(/^\d+$/);
+}
+
+function toPath(pathString) {
+ if (Array.isArray(pathString)) return pathString;
+ if (typeof pathString === 'number') return [pathString];
+ pathString = String(pathString);
+
+ // taken from lodash - /~https://github.com/lodash/lodash
+ var pathRx = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(\.|\[\])(?:\4|$))/g;
+ var pathArray = [];
+
+ pathString.replace(pathRx, function (match, number, quote, string) {
+ pathArray.push(quote ? string : number !== undefined ? Number(number) : match);
+ return pathArray[pathArray.length - 1];
});
- return result;
+ return pathArray;
}
function noop() {}
@@ -142,7 +128,7 @@ function getPaths(object) {
function _get(obj, path, defaultValue) {
try {
var o = obj;
- var fields = Array.isArray(path) ? path : toPath(path);
+ var fields = toPath(path);
while (fields.length) {
var prop = fields.shift();
o = o[prop];
@@ -232,23 +218,16 @@ function buildVuexModel(vm, vuexPath, options) {
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 vueSet(obj, path, value) {
+ var fields = Array.isArray(path) ? path : toPath(path);
+ var prop = fields.shift();
+
+ if (!fields.length) return _vue2.default.set(obj, prop, value);
+ if (!hasOwnProperty(obj, prop) || obj[prop] === null) {
+ var objVal = fields.length >= 1 && isNumberLike(fields[0]) ? [] : {};
+ _vue2.default.set(obj, prop, objVal);
}
+ vueSet(obj[prop], fields, value);
}
function vuexSet(path, value) {
diff --git a/vue-deepset.min.js b/vue-deepset.min.js
index fb95d6b..2e58ffa 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)){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)});
+(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=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(obj,path,value){var fields=Array.isArray(path)?path:toPath(path);var prop=fields.shift();if(!fields.length)return _vue2.default.set(obj,prop,value);if(!hasOwnProperty(obj,prop)||obj[prop]===null){var objVal=fields.length>=1&&isNumberLike(fields[0])?[]:{};_vue2.default.set(obj,prop,objVal)}vueSet(obj[prop],fields,value)}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)});