diff options
-rw-r--r-- | src/content-function.js | 16 | ||||
-rw-r--r-- | src/util/sugar.js | 76 |
2 files changed, 86 insertions, 6 deletions
diff --git a/src/content-function.js b/src/content-function.js index 51383793..654a294c 100644 --- a/src/content-function.js +++ b/src/content-function.js @@ -1,4 +1,4 @@ -import {empty} from './util/sugar.js'; +import {annotateFunction, empty} from './util/sugar.js'; export default function contentFunction({ contentDependencies = [], @@ -54,6 +54,7 @@ export function expectDependencies({ throw new Error(`Generate invalidated because unfulfilled dependencies provided: ${invalidatingDependencyKeys.join(', ')}`); }; + annotateFunction(wrappedGenerate, {name: generate, trait: 'invalidated'}); wrappedGenerate.fulfilled ??= false; } @@ -62,17 +63,19 @@ export function expectDependencies({ return generate(data, fulfilledDependencies); }; + annotateFunction(wrappedGenerate, {name: generate, trait: 'fulfilled'}); + wrappedGenerate.fulfilled ??= true; + wrappedGenerate.fulfill = function() { throw new Error(`All dependencies already fulfilled`); }; - - wrappedGenerate.fulfilled ??= true; } wrappedGenerate ??= function() { throw new Error(`Dependencies still needed: ${missingContentDependencyKeys.concat(missingExtraDependencyKeys).join(', ')}`); }; + annotateFunction(wrappedGenerate, {name: generate, trait: 'unfulfilled'}); wrappedGenerate.fulfilled ??= false; wrappedGenerate[contentFunction.identifyingSymbol] = true; @@ -84,6 +87,7 @@ export function expectDependencies({ throw new Error(`Expected call to this dependency's .data()`); }; + annotateFunction(wrappedGenerate, {name: fulfilledDependencies[key], description: 'data only'}); wrappedDependency.data = fulfilledDependencies[key].data; dataDependencies[key] = wrappedDependency; } @@ -91,13 +95,17 @@ export function expectDependencies({ wrappedGenerate.data = function(...args) { return data(...args, dataDependencies); }; + + annotateFunction(wrappedGenerate.data, {name: data, trait: 'fulfilled'}); } wrappedGenerate.data ??= function() { throw new Error(`Dependencies still needed: ${missingContentDependencyKeys.join(', ')}`); }; - wrappedGenerate.fulfill ??= function(dependencies) { + annotateFunction(wrappedGenerate.data, {name: data, trait: 'unfulfilled'}); + + wrappedGenerate.fulfill ??= function fulfill(dependencies) { return expectDependencies({ generate, data, diff --git a/src/util/sugar.js b/src/util/sugar.js index c60bddb6..ad36d16b 100644 --- a/src/util/sugar.js +++ b/src/util/sugar.js @@ -146,8 +146,9 @@ 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))) { @@ -487,3 +488,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}); +} |