UNPKG

ow

Version:

Function argument validation for humans

97 lines (92 loc) 3.54 kB
import is from '@sindresorhus/is'; import test from '../test.js'; import { isPredicate, optionalSymbol, absentSymbol } from '../predicates/base-predicate.js'; /** Test if the `object` matches the `shape` partially. @hidden @param object - Object to test against the provided shape. @param shape - Shape to test the object against. @param parent - Name of the parent property. */ export function partial(object, shape, parent) { try { for (const key of Object.keys(shape)) { const label = parent ? `${parent}.${key}` : key; const shapeValue = shape[key]; if (isPredicate(shapeValue)) { const predicate = shapeValue; // Skip absent properties that don't exist in the object if (predicate[absentSymbol] && !(key in object)) { continue; } // Skip optional properties that don't exist in the object if (predicate[optionalSymbol] && !(key in object)) { continue; } test(object[key], label, predicate); } else if (is.plainObject(shapeValue)) { // Skip nested shapes if the key doesn't exist and it's optional // (though nested shapes themselves aren't predicates, so this is for consistency) if (!(key in object)) { continue; } const result = partial(object[key], shapeValue, label); if (result !== true) { return result; } } } return true; } catch (error) { return error.message; } } /** Test if the `object` matches the `shape` exactly. @hidden @param object - Object to test against the provided shape. @param shape - Shape to test the object against. @param parent - Name of the parent property. */ export function exact(object, shape, parent, isArray) { try { const objectKeys = new Set(Object.keys(object)); for (const key of Object.keys(shape)) { objectKeys.delete(key); const label = parent ? `${parent}.${key}` : key; const shapeValue = shape[key]; if (isPredicate(shapeValue)) { const predicate = shapeValue; // Skip absent properties that don't exist in the object if (predicate[absentSymbol] && !(key in object)) { continue; } // Skip optional properties that don't exist in the object if (predicate[optionalSymbol] && !(key in object)) { continue; } test(object[key], label, predicate); } else if (is.plainObject(shapeValue)) { if (!Object.hasOwn(object, key)) { return `Expected \`${label}\` to exist`; } const result = exact(object[key], shapeValue, label); if (result !== true) { return result; } } } if (objectKeys.size > 0) { const firstKey = [...objectKeys.keys()][0]; const label = parent ? `${parent}.${firstKey}` : firstKey; return `Did not expect ${isArray ? 'element' : 'property'} \`${label}\` to exist, got \`${object[firstKey]}\``; } return true; } catch (error) { return error.message; } }