286 lines
11 KiB
JavaScript
286 lines
11 KiB
JavaScript
/**
|
|
* @license nested-property https://github.com/cosmosio/nested-property
|
|
*
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2014-2020 Olivier Scherrer <pode.fr@gmail.com>
|
|
*/
|
|
"use strict";
|
|
|
|
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
|
|
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
|
|
|
|
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
|
|
|
|
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
|
|
|
|
function _wrapNativeSuper(Class) { var _cache = typeof Map === "function" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (Class === null || !_isNativeFunction(Class)) return Class; if (typeof Class !== "function") { throw new TypeError("Super expression must either be null or a function"); } if (typeof _cache !== "undefined") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); } Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, Class); }; return _wrapNativeSuper(Class); }
|
|
|
|
function _construct(Parent, args, Class) { if (_isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); }
|
|
|
|
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
|
|
|
|
function _isNativeFunction(fn) { return Function.toString.call(fn).indexOf("[native code]") !== -1; }
|
|
|
|
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
|
|
|
|
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
|
|
|
|
var ARRAY_WILDCARD = "+";
|
|
var PATH_DELIMITER = ".";
|
|
|
|
var ObjectPrototypeMutationError = /*#__PURE__*/function (_Error) {
|
|
_inherits(ObjectPrototypeMutationError, _Error);
|
|
|
|
function ObjectPrototypeMutationError(params) {
|
|
var _this;
|
|
|
|
_classCallCheck(this, ObjectPrototypeMutationError);
|
|
|
|
_this = _possibleConstructorReturn(this, _getPrototypeOf(ObjectPrototypeMutationError).call(this, params));
|
|
_this.name = "ObjectPrototypeMutationError";
|
|
return _this;
|
|
}
|
|
|
|
return ObjectPrototypeMutationError;
|
|
}(_wrapNativeSuper(Error));
|
|
|
|
module.exports = {
|
|
set: setNestedProperty,
|
|
get: getNestedProperty,
|
|
has: hasNestedProperty,
|
|
hasOwn: function hasOwn(object, property, options) {
|
|
return this.has(object, property, options || {
|
|
own: true
|
|
});
|
|
},
|
|
isIn: isInNestedProperty,
|
|
ObjectPrototypeMutationError: ObjectPrototypeMutationError
|
|
};
|
|
/**
|
|
* Get the property of an object nested in one or more objects or array
|
|
* Given an object such as a.b.c.d = 5, getNestedProperty(a, "b.c.d") will return 5.
|
|
* It also works through arrays. Given a nested array such as a[0].b = 5, getNestedProperty(a, "0.b") will return 5.
|
|
* For accessing nested properties through all items in an array, you may use the array wildcard "+".
|
|
* For instance, getNestedProperty([{a:1}, {a:2}, {a:3}], "+.a") will return [1, 2, 3]
|
|
* @param {Object} object the object to get the property from
|
|
* @param {String} property the path to the property as a string
|
|
* @returns the object or the the property value if found
|
|
*/
|
|
|
|
function getNestedProperty(object, property) {
|
|
if (_typeof(object) != "object" || object === null) {
|
|
return object;
|
|
}
|
|
|
|
if (typeof property == "undefined") {
|
|
return object;
|
|
}
|
|
|
|
if (typeof property == "number") {
|
|
return object[property];
|
|
}
|
|
|
|
try {
|
|
return traverse(object, property, function _getNestedProperty(currentObject, currentProperty) {
|
|
return currentObject[currentProperty];
|
|
});
|
|
} catch (err) {
|
|
return object;
|
|
}
|
|
}
|
|
/**
|
|
* Tell if a nested object has a given property (or array a given index)
|
|
* given an object such as a.b.c.d = 5, hasNestedProperty(a, "b.c.d") will return true.
|
|
* It also returns true if the property is in the prototype chain.
|
|
* @param {Object} object the object to get the property from
|
|
* @param {String} property the path to the property as a string
|
|
* @param {Object} options:
|
|
* - own: set to reject properties from the prototype
|
|
* @returns true if has (property in object), false otherwise
|
|
*/
|
|
|
|
|
|
function hasNestedProperty(object, property) {
|
|
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
|
|
if (_typeof(object) != "object" || object === null) {
|
|
return false;
|
|
}
|
|
|
|
if (typeof property == "undefined") {
|
|
return false;
|
|
}
|
|
|
|
if (typeof property == "number") {
|
|
return property in object;
|
|
}
|
|
|
|
try {
|
|
var has = false;
|
|
traverse(object, property, function _hasNestedProperty(currentObject, currentProperty, segments, index) {
|
|
if (isLastSegment(segments, index)) {
|
|
if (options.own) {
|
|
has = currentObject.hasOwnProperty(currentProperty);
|
|
} else {
|
|
has = currentProperty in currentObject;
|
|
}
|
|
} else {
|
|
return currentObject && currentObject[currentProperty];
|
|
}
|
|
});
|
|
return has;
|
|
} catch (err) {
|
|
return false;
|
|
}
|
|
}
|
|
/**
|
|
* Set the property of an object nested in one or more objects
|
|
* If the property doesn't exist, it gets created.
|
|
* @param {Object} object
|
|
* @param {String} property
|
|
* @param value the value to set
|
|
* @returns object if no assignment was made or the value if the assignment was made
|
|
*/
|
|
|
|
|
|
function setNestedProperty(object, property, value) {
|
|
if (_typeof(object) != "object" || object === null) {
|
|
return object;
|
|
}
|
|
|
|
if (typeof property == "undefined") {
|
|
return object;
|
|
}
|
|
|
|
if (typeof property == "number") {
|
|
object[property] = value;
|
|
return object[property];
|
|
}
|
|
|
|
try {
|
|
return traverse(object, property, function _setNestedProperty(currentObject, currentProperty, segments, index) {
|
|
if (currentObject === Reflect.getPrototypeOf({})) {
|
|
throw new ObjectPrototypeMutationError("Attempting to mutate Object.prototype");
|
|
}
|
|
|
|
if (!currentObject[currentProperty]) {
|
|
var nextPropIsNumber = Number.isInteger(Number(segments[index + 1]));
|
|
var nextPropIsArrayWildcard = segments[index + 1] === ARRAY_WILDCARD;
|
|
|
|
if (nextPropIsNumber || nextPropIsArrayWildcard) {
|
|
currentObject[currentProperty] = [];
|
|
} else {
|
|
currentObject[currentProperty] = {};
|
|
}
|
|
}
|
|
|
|
if (isLastSegment(segments, index)) {
|
|
currentObject[currentProperty] = value;
|
|
}
|
|
|
|
return currentObject[currentProperty];
|
|
});
|
|
} catch (err) {
|
|
if (err instanceof ObjectPrototypeMutationError) {
|
|
// rethrow
|
|
throw err;
|
|
} else {
|
|
return object;
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Tell if an object is on the path to a nested property
|
|
* If the object is on the path, and the path exists, it returns true, and false otherwise.
|
|
* @param {Object} object to get the nested property from
|
|
* @param {String} property name of the nested property
|
|
* @param {Object} objectInPath the object to check
|
|
* @param {Object} options:
|
|
* - validPath: return false if the path is invalid, even if the object is in the path
|
|
* @returns {boolean} true if the object is on the path
|
|
*/
|
|
|
|
|
|
function isInNestedProperty(object, property, objectInPath) {
|
|
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
|
|
if (_typeof(object) != "object" || object === null) {
|
|
return false;
|
|
}
|
|
|
|
if (typeof property == "undefined") {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
var isIn = false,
|
|
pathExists = false;
|
|
traverse(object, property, function _isInNestedProperty(currentObject, currentProperty, segments, index) {
|
|
isIn = isIn || currentObject === objectInPath || !!currentObject && currentObject[currentProperty] === objectInPath;
|
|
pathExists = isLastSegment(segments, index) && _typeof(currentObject) === "object" && currentProperty in currentObject;
|
|
return currentObject && currentObject[currentProperty];
|
|
});
|
|
|
|
if (options.validPath) {
|
|
return isIn && pathExists;
|
|
} else {
|
|
return isIn;
|
|
}
|
|
} catch (err) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function traverse(object, path) {
|
|
var callback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {};
|
|
var segments = path.split(PATH_DELIMITER);
|
|
var length = segments.length;
|
|
|
|
var _loop = function _loop(idx) {
|
|
var currentSegment = segments[idx];
|
|
|
|
if (!object) {
|
|
return {
|
|
v: void 0
|
|
};
|
|
}
|
|
|
|
if (currentSegment === ARRAY_WILDCARD) {
|
|
if (Array.isArray(object)) {
|
|
return {
|
|
v: object.map(function (value, index) {
|
|
var remainingSegments = segments.slice(idx + 1);
|
|
|
|
if (remainingSegments.length > 0) {
|
|
return traverse(value, remainingSegments.join(PATH_DELIMITER), callback);
|
|
} else {
|
|
return callback(object, index, segments, idx);
|
|
}
|
|
})
|
|
};
|
|
} else {
|
|
var pathToHere = segments.slice(0, idx).join(PATH_DELIMITER);
|
|
throw new Error("Object at wildcard (".concat(pathToHere, ") is not an array"));
|
|
}
|
|
} else {
|
|
object = callback(object, currentSegment, segments, idx);
|
|
}
|
|
};
|
|
|
|
for (var idx = 0; idx < length; idx++) {
|
|
var _ret = _loop(idx);
|
|
|
|
if (_typeof(_ret) === "object") return _ret.v;
|
|
}
|
|
|
|
return object;
|
|
}
|
|
|
|
function isLastSegment(segments, index) {
|
|
return segments.length === index + 1;
|
|
}
|