diff options
Diffstat (limited to 'src/util/sugar.js')
-rw-r--r-- | src/util/sugar.js | 106 |
1 files changed, 103 insertions, 3 deletions
diff --git a/src/util/sugar.js b/src/util/sugar.js index 0813c1d4..6ab70bc6 100644 --- a/src/util/sugar.js +++ b/src/util/sugar.js @@ -82,6 +82,14 @@ export const compareArrays = (arr1, arr2, {checkOrder = true} = {}) => export const withEntries = (obj, fn) => Object.fromEntries(fn(Object.entries(obj))); +export function filterProperties(obj, properties) { + const set = new Set(properties); + return Object.fromEntries( + Object + .entries(obj) + .filter(([key]) => set.has(key))); +} + export function queue(array, max = 50) { if (max === 0) { return array.map((fn) => fn()); @@ -146,10 +154,20 @@ export function bindOpts(fn, bind) { ]); }; - Object.defineProperty(bound, 'name', { - value: fn.name ? `(options-bound) ${fn.name}` : `(options-bound)`, + annotateFunction(bound, { + name: fn, + trait: 'options-bound', }); + for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(fn))) { + if (key === 'length') continue; + if (key === 'name') continue; + if (key === 'arguments') continue; + if (key === 'caller') continue; + if (key === 'prototype') continue; + Object.defineProperty(bound, key, descriptor); + } + return bound; } @@ -216,6 +234,10 @@ export function openAggregate({ ); }; + aggregate.push = (error) => { + errors.push(error); + }; + aggregate.call = (fn, ...args) => { return aggregate.wrap(fn)(...args); }; @@ -421,6 +443,7 @@ export function _withAggregate(mode, aggregateOpts, fn) { export function showAggregate(topError, { pathToFileURL = f => f, showTraces = true, + print = true, } = {}) { const recursive = (error, {level}) => { let header = showTraces @@ -465,7 +488,13 @@ export function showAggregate(topError, { } }; - console.error(recursive(topError, {level: 0})); + const message = recursive(topError, {level: 0}); + + if (print) { + console.error(message); + } else { + return message; + } } export function decorateErrorWithIndex(fn) { @@ -478,3 +507,74 @@ export function decorateErrorWithIndex(fn) { } }; } + +// Delicious function annotations, such as: +// +// (*bound) soWeAreBackInTheMine +// (data *unfulfilled) generateShrekTwo +// +export function annotateFunction(fn, { + name: nameOrFunction = null, + description: newDescription, + trait: newTrait, +}) { + let name; + + if (typeof nameOrFunction === 'function') { + name = nameOrFunction.name; + } else if (typeof nameOrFunction === 'string') { + name = nameOrFunction; + } + + name ??= fn.name ?? 'anonymous'; + + const match = name.match(/^ *(?<prefix>.*?) *\((?<description>.*)( #(?<trait>.*))?\) *(?<suffix>.*) *$/); + + let prefix, suffix, description, trait; + if (match) { + ({prefix, suffix, description, trait} = match.groups); + } + + prefix ??= ''; + suffix ??= name; + description ??= ''; + trait ??= ''; + + if (newDescription) { + if (description) { + description += '; ' + newDescription; + } else { + description = newDescription; + } + } + + if (newTrait) { + if (trait) { + trait += ' #' + newTrait; + } else { + trait = '#' + newTrait; + } + } + + let parenthesesPart; + + if (description && trait) { + parenthesesPart = `${description} ${trait}`; + } else if (description || trait) { + parenthesesPart = description || trait; + } else { + parenthesesPart = ''; + } + + let finalName; + + if (prefix && parenthesesPart) { + finalName = `${prefix} (${parenthesesPart}) ${suffix}`; + } else if (parenthesesPart) { + finalName = `(${parenthesesPart}) ${suffix}`; + } else { + finalName = suffix; + } + + Object.defineProperty(fn, 'name', {value: finalName}); +} |