1// Copyright 2023 The Pigweed Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); you may not 4// use this file except in compliance with the License. You may obtain a copy of 5// the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12// License for the specific language governing permissions and limitations under 13// the License. 14 15type ObjectType = { 16 [index: number | string]: any; 17}; 18 19function hasOwnProperty(obj: ObjectType, prop: number | string) { 20 if (obj == null) { 21 return false; 22 } 23 //to handle objects with null prototypes (too edge case?) 24 return Object.prototype.hasOwnProperty.call(obj, prop); 25} 26function hasShallowProperty(obj: ObjectType, prop: number | string) { 27 return ( 28 (typeof prop === 'number' && Array.isArray(obj)) || 29 hasOwnProperty(obj, prop) 30 ); 31} 32 33function getShallowProperty(obj: ObjectType, prop: number | string) { 34 if (hasShallowProperty(obj, prop)) { 35 return obj[prop]; 36 } 37} 38function getKey(key: string) { 39 const intKey = parseInt(key); 40 if (intKey.toString() === key) { 41 return intKey; 42 } 43 return key; 44} 45 46export function setPathOnObject( 47 obj: ObjectType, 48 path: number | string | Array<number | string>, 49 value: any, 50 doNotReplace = false, 51) { 52 if (typeof path === 'number') { 53 path = [path]; 54 } 55 if (!path || path.length === 0) { 56 return obj; 57 } 58 if (typeof path === 'string') { 59 return setPathOnObject( 60 obj, 61 path.split('.').map(getKey), 62 value, 63 doNotReplace, 64 ); 65 } 66 const currentPath = path[0]; 67 const currentValue = getShallowProperty(obj, currentPath); 68 if (path.length === 1) { 69 if (currentValue === void 0 || !doNotReplace) { 70 obj[currentPath] = value; 71 } 72 return currentValue; 73 } 74 75 if (currentValue === void 0) { 76 //check if we assume an array 77 if (typeof path[1] === 'number') { 78 obj[currentPath] = []; 79 } else { 80 obj[currentPath] = {}; 81 } 82 } 83 84 return setPathOnObject(obj[currentPath], path.slice(1), value, doNotReplace); 85} 86