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