You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							142 lines
						
					
					
						
							2.7 KiB
						
					
					
				
			
		
		
	
	
							142 lines
						
					
					
						
							2.7 KiB
						
					
					
				'use strict'; | 
						|
const isObj = require('is-obj'); | 
						|
 | 
						|
const disallowedKeys = [ | 
						|
	'__proto__', | 
						|
	'prototype', | 
						|
	'constructor' | 
						|
]; | 
						|
 | 
						|
const isValidPath = pathSegments => !pathSegments.some(segment => disallowedKeys.includes(segment)); | 
						|
 | 
						|
function getPathSegments(path) { | 
						|
	const pathArray = path.split('.'); | 
						|
	const parts = []; | 
						|
 | 
						|
	for (let i = 0; i < pathArray.length; i++) { | 
						|
		let p = pathArray[i]; | 
						|
 | 
						|
		while (p[p.length - 1] === '\\' && pathArray[i + 1] !== undefined) { | 
						|
			p = p.slice(0, -1) + '.'; | 
						|
			p += pathArray[++i]; | 
						|
		} | 
						|
 | 
						|
		parts.push(p); | 
						|
	} | 
						|
 | 
						|
	if (!isValidPath(parts)) { | 
						|
		return []; | 
						|
	} | 
						|
 | 
						|
	return parts; | 
						|
} | 
						|
 | 
						|
module.exports = { | 
						|
	get(object, path, value) { | 
						|
		if (!isObj(object) || typeof path !== 'string') { | 
						|
			return value === undefined ? object : value; | 
						|
		} | 
						|
 | 
						|
		const pathArray = getPathSegments(path); | 
						|
		if (pathArray.length === 0) { | 
						|
			return; | 
						|
		} | 
						|
 | 
						|
		for (let i = 0; i < pathArray.length; i++) { | 
						|
			if (!Object.prototype.propertyIsEnumerable.call(object, pathArray[i])) { | 
						|
				return value; | 
						|
			} | 
						|
 | 
						|
			object = object[pathArray[i]]; | 
						|
 | 
						|
			if (object === undefined || object === null) { | 
						|
				// `object` is either `undefined` or `null` so we want to stop the loop, and | 
						|
				// if this is not the last bit of the path, and | 
						|
				// if it did't return `undefined` | 
						|
				// it would return `null` if `object` is `null` | 
						|
				// but we want `get({foo: null}, 'foo.bar')` to equal `undefined`, or the supplied value, not `null` | 
						|
				if (i !== pathArray.length - 1) { | 
						|
					return value; | 
						|
				} | 
						|
 | 
						|
				break; | 
						|
			} | 
						|
		} | 
						|
 | 
						|
		return object; | 
						|
	}, | 
						|
 | 
						|
	set(object, path, value) { | 
						|
		if (!isObj(object) || typeof path !== 'string') { | 
						|
			return object; | 
						|
		} | 
						|
 | 
						|
		const root = object; | 
						|
		const pathArray = getPathSegments(path); | 
						|
 | 
						|
		for (let i = 0; i < pathArray.length; i++) { | 
						|
			const p = pathArray[i]; | 
						|
 | 
						|
			if (!isObj(object[p])) { | 
						|
				object[p] = {}; | 
						|
			} | 
						|
 | 
						|
			if (i === pathArray.length - 1) { | 
						|
				object[p] = value; | 
						|
			} | 
						|
 | 
						|
			object = object[p]; | 
						|
		} | 
						|
 | 
						|
		return root; | 
						|
	}, | 
						|
 | 
						|
	delete(object, path) { | 
						|
		if (!isObj(object) || typeof path !== 'string') { | 
						|
			return false; | 
						|
		} | 
						|
 | 
						|
		const pathArray = getPathSegments(path); | 
						|
 | 
						|
		for (let i = 0; i < pathArray.length; i++) { | 
						|
			const p = pathArray[i]; | 
						|
 | 
						|
			if (i === pathArray.length - 1) { | 
						|
				delete object[p]; | 
						|
				return true; | 
						|
			} | 
						|
 | 
						|
			object = object[p]; | 
						|
 | 
						|
			if (!isObj(object)) { | 
						|
				return false; | 
						|
			} | 
						|
		} | 
						|
	}, | 
						|
 | 
						|
	has(object, path) { | 
						|
		if (!isObj(object) || typeof path !== 'string') { | 
						|
			return false; | 
						|
		} | 
						|
 | 
						|
		const pathArray = getPathSegments(path); | 
						|
		if (pathArray.length === 0) { | 
						|
			return false; | 
						|
		} | 
						|
 | 
						|
		// eslint-disable-next-line unicorn/no-for-loop | 
						|
		for (let i = 0; i < pathArray.length; i++) { | 
						|
			if (isObj(object)) { | 
						|
				if (!(pathArray[i] in object)) { | 
						|
					return false; | 
						|
				} | 
						|
 | 
						|
				object = object[pathArray[i]]; | 
						|
			} else { | 
						|
				return false; | 
						|
			} | 
						|
		} | 
						|
 | 
						|
		return true; | 
						|
	} | 
						|
};
 | 
						|
 |