shelving
Version:
Toolkit for using data in JavaScript.
104 lines (103 loc) • 3.77 kB
JavaScript
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 };
}