UNPKG

shelving

Version:

Toolkit for using data in JavaScript.

104 lines (103 loc) 3.77 kB
import { RequiredError } from "../error/RequiredError.js"; import { isIterable } from "./iterate.js"; /** Is an unknown value an unknown object? */ export function isObject(value) { return typeof value === "object" && value !== null; } /** Assert that a value is an object */ export function assertObject(value) { if (!isObject(value)) throw new RequiredError("Must be object", { received: value, caller: assertObject }); } /** Is an unknown value a plain object? */ export function isPlainObject(value) { if (isObject(value)) { const proto = getPrototype(value); return proto === null || proto === Object.prototype; } return false; } /** Assert that an unknown value is a plain object */ export function assertPlainObject(value) { if (!isPlainObject(value)) throw new RequiredError("Must be plain object", { received: value, caller: assertPlainObject }); } /** Is an unknown value the key for an own prop of an object. */ export const isProp = (obj, key) => Object.hasOwn(obj, key); /** Assert that an unknown value is the key for an own prop of an object. */ export function assertProp(obj, key) { if (!isProp(obj, key)) throw new RequiredError("Key must exist in object", { key, obj, caller: assertProp }); } /** Turn a possible object into an object. */ export function getObject(obj) { return isIterable(obj) ? Object.fromEntries(obj) : obj; } export function getProps(obj) { return isIterable(obj) ? obj : Object.entries(obj); } export function getKeys(obj) { return isIterable(obj) ? obj : Object.keys(obj); } /** Extract the value of a named prop from an object. */ export function getProp(obj, key) { return obj[key]; } /** Create an object from a single prop. */ export function fromProp(key, value) { return { [key]: value }; } /** Set a prop on an object (immutably) and return a new object including that prop. */ export function withProp(input, key, value) { return input[key] === value ? input : { __proto__: getPrototype(input), ...input, [key]: value }; } export function withProps(input, props) { for (const [k, v] of getProps(props)) if (input[k] !== v) return { __proto__: getPrototype(input), ...input, ...props }; return input; } export function omitProps(input, ...keys) { for (const key of keys) if (key in input) return Object.fromEntries(Object.entries(input).filter(_hasntKey, keys)); return input; } function _hasntKey([key]) { return !this.includes(key); } export function pickProps(input, ...keys) { return Object.fromEntries(Object.entries(input).filter(_hasKey, keys)); } function _hasKey([key]) { return this.includes(key); } /** Set a single named prop on an object (by reference) and return its value. */ export function setProp(obj, key, value) { obj[key] = value; return value; } /** Set several named props on an object (by reference). */ export function setProps(obj, entries) { for (const [k, v] of getProps(entries)) obj[k] = v; } /** Remove several key/value entries from an object (by reference). */ export function deleteProps(obj, ...keys) { for (const key of keys) delete obj[key]; } /** * Get the prototype of an object instance. * - Recommend to use this because Typescript's default lib specifies `Object.getPrototypeOf()` returning `any`. */ export function getPrototype(obj) { return Object.getPrototypeOf(obj); } /** Shallow clone an object with the same prototype. */ export function cloneObject(input) { return { __proto__: getPrototype(input), ...input }; } export function cloneObjectWith(input, key, value) { return input[key] === value ? input : { __proto__: getPrototype(input), ...input, [key]: value }; }