UNPKG

get-wild

Version:

Pluck nested properties from an object with support for wildcards

161 lines (129 loc) 4.92 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.GetWild = {})); })(this, (function (exports) { 'use strict'; const TOKEN = /(?:(?:\[(?:(?:(["'])((?:\\.|(?:(?!\1).))*)\1)|([-+]?\d+))\])|(?:(?:^|(?:(?!^)\.))([^\s"'\`\[\].\\]+))|(.))/g; const ESCAPED = /\\(.)/g; const parser = path => { const steps = []; for (const { index, 1: quote, 2: quoted, 3: integer, 4: name } of path.matchAll(TOKEN)) { let step; if (name) { step = name; } else if (integer) { step = +integer; } else if (quote) { step = quoted.replace(ESCAPED, (match, escaped) => escaped === quote ? quote : match); } else { throw new SyntaxError(`Invalid step @ ${index}: ${JSON.stringify(path)}`); } steps.push(step); } return steps; }; const { isArray: __isArray } = Array; const { defineProperty: __defineProperty, values: defaultCollect } = Object; const NO_MAP = Symbol(); const NO_FLAT_MAP = Symbol(); const getter$1 = (options = {}) => { const { collect = defaultCollect, default: $$default, flatMap: $flatMap = '*', map: $map = '**', parser: parser$1 = parser, split = parser$1 } = options; const flatMap = $flatMap === false ? NO_FLAT_MAP : $flatMap; const map = $map === false ? NO_MAP : $map; const parse = typeof split === 'string' ? path => path.split(split) : split; const toArray = (obj, ...args) => { // ignore this warning to avoid adding a redundant check to appease // TypeScript for something which works in JavaScript // // > A spread argument must either have a tuple type or be passed to a // > rest parameter. // // @ts-ignore return __isArray(obj) ? obj : collect(obj, ...args); }; // XXX the name is important; if omitted, the `get` referenced in the body // of this function refers to the default `get` export defined at the bottom // of the file rather than this `get`, which may have different options function get(obj, path, ...rest) { const $default = rest.length ? rest[0] : $$default; const coalesce = it => it === undefined ? $default : it; let props; if (__isArray(path)) { props = path; } else { const type = path === null ? 'null' : typeof path; if (type === 'string') { props = parse(path); } else if (type === 'number' || type === 'symbol') { props = [path]; } else { throw new TypeError(`Invalid path: expected a string, array, number, or symbol, got: ${type}`); } } const lastIndex = props.length - 1; for (let i = 0; i <= lastIndex; ++i) { if (!obj) { return $default; } const prop = props[i]; const isFlatMap = prop === flatMap; if (isFlatMap || prop === map) { const values = toArray(obj); let recurse; if (i === lastIndex) { recurse = coalesce; // base case } else { const tailProps = props.slice(i + 1); recurse = value => get(value, tailProps, $default); } return isFlatMap ? values.flatMap(recurse) : values.map(recurse); } else if (Number.isInteger(prop)) { const values = toArray(obj, prop); const index = prop < 0 ? values.length + prop : prop; obj = values[index]; } else { obj = obj[prop]; } } return coalesce(obj); } // expose the supplied/generated parser as a (read-only) property on the // function. this is for the currying wrappers and isn't exposed by the // curried functions return __defineProperty(get, 'parse', { value: parse }); }; const get$1 = getter$1(); const parse = (path, get) => { return typeof path === 'string' ? get.parse(path) : path; }; const _get = (get, $$default) => { return (_path, ...rest) => { const path = parse(_path, get); const $default = rest.length ? rest[0] : $$default; return value => get(value, path, $default); }; }; const get = _get(get$1); const getter = (options = {}) => _get(getter$1(options), options.default); exports.get = get; exports.getter = getter; Object.defineProperty(exports, '__esModule', { value: true }); }));