basant307/AI_Governance_Project
048
1/* !2 * Chai - pathval utility3 * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>4 * @see https://github.com/logicalparadox/filtr5 * MIT Licensed6 */7 8/**9 * ### .hasProperty(object, name)10 *11 * This allows checking whether an object has own12 * or inherited from prototype chain named property.13 *14 * Basically does the same thing as the `in`15 * operator but works properly with null/undefined values16 * and other primitives.17 *18 * var obj = {19 * arr: ['a', 'b', 'c']20 * , str: 'Hello'21 * }22 *23 * The following would be the results.24 *25 * hasProperty(obj, 'str'); // true26 * hasProperty(obj, 'constructor'); // true27 * hasProperty(obj, 'bar'); // false28 *29 * hasProperty(obj.str, 'length'); // true30 * hasProperty(obj.str, 1); // true31 * hasProperty(obj.str, 5); // false32 *33 * hasProperty(obj.arr, 'length'); // true34 * hasProperty(obj.arr, 2); // true35 * hasProperty(obj.arr, 3); // false36 *37 * @param {Object} object38 * @param {String|Symbol} name39 * @returns {Boolean} whether it exists40 * @namespace Utils41 * @name hasProperty42 * @api public43 */44 45export function hasProperty(obj, name) {46 if (typeof obj === 'undefined' || obj === null) {47 return false;48 }49 50 // The `in` operator does not work with primitives.51 return name in Object(obj);52}53 54/* !55 * ## parsePath(path)56 *57 * Helper function used to parse string object58 * paths. Use in conjunction with `internalGetPathValue`.59 *60 * var parsed = parsePath('myobject.property.subprop');61 *62 * ### Paths:63 *64 * * Can be infinitely deep and nested.65 * * Arrays are also valid using the formal `myobject.document[3].property`.66 * * Literal dots and brackets (not delimiter) must be backslash-escaped.67 *68 * @param {String} path69 * @returns {Object} parsed70 * @api private71 */72 73function parsePath(path) {74 const str = path.replace(/([^\\])\[/g, '$1.[');75 const parts = str.match(/(\\\.|[^.]+?)+/g);76 return parts.map((value) => {77 if (78 value === 'constructor' ||79 value === '__proto__' ||80 value === 'prototype'81 ) {82 return {};83 }84 const regexp = /^\[(\d+)\]$/;85 const mArr = regexp.exec(value);86 let parsed = null;87 if (mArr) {88 parsed = { i: parseFloat(mArr[1]) };89 } else {90 parsed = { p: value.replace(/\\([.[\]])/g, '$1') };91 }92 93 return parsed;94 });95}96 97/* !98 * ## internalGetPathValue(obj, parsed[, pathDepth])99 *100 * Helper companion function for `.parsePath` that returns101 * the value located at the parsed address.102 *103 * var value = getPathValue(obj, parsed);104 *105 * @param {Object} object to search against106 * @param {Object} parsed definition from `parsePath`.107 * @param {Number} depth (nesting level) of the property we want to retrieve108 * @returns {Object|Undefined} value109 * @api private110 */111 112function internalGetPathValue(obj, parsed, pathDepth) {113 let temporaryValue = obj;114 let res = null;115 pathDepth = typeof pathDepth === 'undefined' ? parsed.length : pathDepth;116 117 for (let i = 0; i < pathDepth; i++) {118 const part = parsed[i];119 if (temporaryValue) {120 if (typeof part.p === 'undefined') {121 temporaryValue = temporaryValue[part.i];122 } else {123 temporaryValue = temporaryValue[part.p];124 }125 126 if (i === pathDepth - 1) {127 res = temporaryValue;128 }129 }130 }131 132 return res;133}134 135/* !136 * ## internalSetPathValue(obj, value, parsed)137 *138 * Companion function for `parsePath` that sets139 * the value located at a parsed address.140 *141 * internalSetPathValue(obj, 'value', parsed);142 *143 * @param {Object} object to search and define on144 * @param {*} value to use upon set145 * @param {Object} parsed definition from `parsePath`146 * @api private147 */148 149function internalSetPathValue(obj, val, parsed) {150 let tempObj = obj;151 const pathDepth = parsed.length;152 let part = null;153 // Here we iterate through every part of the path154 for (let i = 0; i < pathDepth; i++) {155 let propName = null;156 let propVal = null;157 part = parsed[i];158 159 // If it's the last part of the path, we set the 'propName' value with the property name160 if (i === pathDepth - 1) {161 propName = typeof part.p === 'undefined' ? part.i : part.p;162 // Now we set the property with the name held by 'propName' on object with the desired val163 tempObj[propName] = val;164 } else if (typeof part.p !== 'undefined' && tempObj[part.p]) {165 tempObj = tempObj[part.p];166 } else if (typeof part.i !== 'undefined' && tempObj[part.i]) {167 tempObj = tempObj[part.i];168 } else {169 // If the obj doesn't have the property we create one with that name to define it170 const next = parsed[i + 1];171 // Here we set the name of the property which will be defined172 propName = typeof part.p === 'undefined' ? part.i : part.p;173 // Here we decide if this property will be an array or a new object174 propVal = typeof next.p === 'undefined' ? [] : {};175 tempObj[propName] = propVal;176 tempObj = tempObj[propName];177 }178 }179}180 181/**182 * ### .getPathInfo(object, path)183 *184 * This allows the retrieval of property info in an185 * object given a string path.186 *187 * The path info consists of an object with the188 * following properties:189 *190 * * parent - The parent object of the property referenced by `path`191 * * name - The name of the final property, a number if it was an array indexer192 * * value - The value of the property, if it exists, otherwise `undefined`193 * * exists - Whether the property exists or not194 *195 * @param {Object} object196 * @param {String} path197 * @returns {Object} info198 * @namespace Utils199 * @name getPathInfo200 * @api public201 */202 203export function getPathInfo(obj, path) {204 const parsed = parsePath(path);205 const last = parsed[parsed.length - 1];206 const info = {207 parent:208 parsed.length > 1 ?209 internalGetPathValue(obj, parsed, parsed.length - 1) :210 obj,211 name: last.p || last.i,212 value: internalGetPathValue(obj, parsed),213 };214 info.exists = hasProperty(info.parent, info.name);215 216 return info;217}218 219/**220 * ### .getPathValue(object, path)221 *222 * This allows the retrieval of values in an223 * object given a string path.224 *225 * var obj = {226 * prop1: {227 * arr: ['a', 'b', 'c']228 * , str: 'Hello'229 * }230 * , prop2: {231 * arr: [ { nested: 'Universe' } ]232 * , str: 'Hello again!'233 * }234 * }235 *236 * The following would be the results.237 *238 * getPathValue(obj, 'prop1.str'); // Hello239 * getPathValue(obj, 'prop1.att[2]'); // b240 * getPathValue(obj, 'prop2.arr[0].nested'); // Universe241 *242 * @param {Object} object243 * @param {String} path244 * @returns {Object} value or `undefined`245 * @namespace Utils246 * @name getPathValue247 * @api public248 */249 250export function getPathValue(obj, path) {251 const info = getPathInfo(obj, path);252 return info.value;253}254 255/**256 * ### .setPathValue(object, path, value)257 *258 * Define the value in an object at a given string path.259 *260 * ```js261 * var obj = {262 * prop1: {263 * arr: ['a', 'b', 'c']264 * , str: 'Hello'265 * }266 * , prop2: {267 * arr: [ { nested: 'Universe' } ]268 * , str: 'Hello again!'269 * }270 * };271 * ```272 *273 * The following would be acceptable.274 *275 * ```js276 * var properties = require('tea-properties');277 * properties.set(obj, 'prop1.str', 'Hello Universe!');278 * properties.set(obj, 'prop1.arr[2]', 'B');279 * properties.set(obj, 'prop2.arr[0].nested.value', { hello: 'universe' });280 * ```281 *282 * @param {Object} object283 * @param {String} path284 * @param {Mixed} value285 * @api private286 */287 288export function setPathValue(obj, path, val) {289 const parsed = parsePath(path);290 internalSetPathValue(obj, val, parsed);291 return obj;292}293 