vue-deepset
Version:
Deep set Vue.js objects
286 lines (248 loc) • 8.55 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
exports.vueSet = vueSet;
exports.vuexSet = vuexSet;
exports.VUEX_DEEP_SET = VUEX_DEEP_SET;
exports.extendMutation = extendMutation;
exports.vueModel = vueModel;
exports.vuexModel = vuexModel;
exports.deepModel = deepModel;
exports.install = install;
var _vue = require('vue');
var _vue2 = _interopRequireDefault(_vue);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var invalidKey = /^\d|[^a-zA-Z0-9_]/gm;
var intKey = /^\d+$/;
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 pathArray;
}
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;
}
function pathJoin(base, path) {
try {
var connector = path.match(/^\[/) ? '' : '.';
return '' + (base || '') + (base ? connector : '') + path;
} catch (error) {
return '';
}
}
function pushPaths(object, current, paths) {
paths.push(current);
if (isObjectLike(object)) {
getPaths(object, current, paths);
}
}
function forEach(object, iteratee) {
var isArray = Array.isArray(object);
var keys = isArray ? object : Object.keys(object);
keys.forEach(function (value, index) {
return isArray ? iteratee(value, index) : iteratee(object[value], value);
});
}
function has(object, path) {
var obj = object;
var parts = toPath(path);
while (parts.length) {
var key = parts.shift();
if (!hasOwnProperty(obj, key)) {
return false;
} else if (!parts.length) {
return true;
}
obj = obj[key];
}
return false;
}
function getPaths(object) {
var current = arguments.length > 1 && 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) {
// is index
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);
}
// always add the absolute array notation path
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); // for future potential 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;
}