« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/data/things/composite.js333
1 files changed, 0 insertions, 333 deletions
diff --git a/src/data/things/composite.js b/src/data/things/composite.js
index 7e068dce..51525bc1 100644
--- a/src/data/things/composite.js
+++ b/src/data/things/composite.js
@@ -15,339 +15,6 @@ import {
   withAggregate,
 } from '#sugar';
 
-// Composes multiple compositional "steps" and a "base" to form a property
-// descriptor out of modular building blocks. This is an extension to the
-// more general-purpose CacheableObject property descriptor syntax, and
-// aims to make modular data processing - which lends to declarativity -
-// much easier, without fundamentally altering much of the typical syntax
-// or terminology, nor building on it to an excessive degree.
-//
-// Think of a composition as being a chain of steps which lead into a final
-// base property, which is usually responsible for returning the value that
-// will actually get exposed when the property being described is accessed.
-//
-// == The compositional base: ==
-//
-// The final item in a compositional list is its base, and it identifies
-// the essential qualities of the property descriptor. The compositional
-// steps preceding it may exit early, in which case the expose function
-// defined on the base won't be called; or they will provide dependencies
-// that the base may use to compute the final value that gets exposed for
-// this property.
-//
-// The base indicates the capabilities of the composition as a whole.
-// It should be {expose: true}, since that's the only area that preceding
-// compositional steps (currently) can actually influence. If it's also
-// {update: true}, then the composition as a whole accepts an update value
-// just like normal update-flag property descriptors - meaning it can be
-// set with `thing.someProperty = value` and that value will be paseed
-// into each (implementing) step's transform() function, as well as the
-// base. Bases usually aren't {compose: true}, but can be - check out the
-// section on "nesting compositions" for details about that.
-//
-// Every composition always has exactly one compositional base, and it's
-// always the last item in the composition list. All items preceding it
-// are compositional steps, described below.
-//
-// == Compositional steps: ==
-//
-// Compositional steps are, in essence, typical property descriptors with
-// the extra flag {compose: true}. They operate on existing dependencies,
-// and are typically dynamically constructed by "utility" functions (but
-// can also be manually declared within the step list of a composition).
-// Compositional steps serve two purposes:
-//
-//  1. exit early, if some condition is matched, returning and exposing
-//     some value directly from that step instead of continuing further
-//     down the step list;
-//
-//  2. and/or provide new, dynamically created "private" dependencies which
-//     can be accessed by further steps down the list, or at the base at
-//     the bottom, modularly supplying information that will contribute to
-//     the final value exposed for this property.
-//
-// Usually it's just one of those two, but it's fine for a step to perform
-// both jobs if the situation benefits.
-//
-// Compositional steps are the real "modular" or "compositional" part of
-// this data processing style - they're designed to be combined together
-// in dynamic, versatile ways, as each property demands it. You usually
-// define a compositional step to be returned by some ordinary static
-// property-descriptor-returning function (customarily namespaced under
-// the relevant Thing class's static `composite` field) - that lets you
-// reuse it in multiple compositions later on.
-//
-// Compositional steps are implemented with "continuation passing style",
-// meaning the connection to the next link on the chain is passed right to
-// each step's compute (or transform) function, and the implementation gets
-// to decide whether to continue on that chain or exit early by returning
-// some other value.
-//
-// Every step along the chain, apart from the base at the bottom, has to
-// have the {compose: true} step. That means its compute() or transform()
-// function will be passed an extra argument at the end, `continuation`.
-// To provide new dependencies to items further down the chain, just pass
-// them directly to this continuation() function, customarily with a hash
-// ('#') prefixing each name - for example:
-//
-//   compute({..some dependencies..}, continuation) {
-//     return continuation({
-//       '#excitingProperty': (..a value made from dependencies..),
-//     });
-//   }
-//
-// Performing an early exit is as simple as returning some other value,
-// instead of the continuation. You may also use `continuation.exit(value)`
-// to perform the exact same kind of early exit - it's just a different
-// syntax that might fit in better in certain longer compositions.
-//
-// It may be fine to simply provide new dependencies under a hard-coded
-// name, such as '#excitingProperty' above, but if you're writing a utility
-// that dynamically returns the compositional step and you suspect you
-// might want to use this step multiple times in a single composition,
-// it's customary to accept a name for the result.
-//
-// Here's a detailed example showing off early exit, dynamically operating
-// on a provided dependency name, and then providing a result in another
-// also-provided dependency name:
-//
-//   withResolvedContribs = ({
-//     from: contribsByRefDependency,
-//     into: outputDependency,
-//   }) => ({
-//     flags: {expose: true, compose: true},
-//     expose: {
-//       dependencies: [contribsByRefDependency, 'artistData'],
-//       compute({
-//         [contribsByRefDependency]: contribsByRef,
-//         artistData,
-//       }, continuation) {
-//         if (!artistData) return null;  /* early exit! */
-//         return continuation({
-//           [outputDependency]:  /* this is the important part */
-//             (..resolve contributions one way or another..),
-//         });
-//       },
-//     },
-//   });
-//
-// And how you might work that into a composition:
-//
-//   Track.coverArtists =
-//     compositeFrom([
-//       doSomethingWhichMightEarlyExit(),
-//
-//       withResolvedContribs({
-//         from: 'coverArtistContribsByRef',
-//         into: '#coverArtistContribs',
-//       }),
-//
-//       {
-//         flags: {expose: true},
-//         expose: {
-//           dependencies: ['#coverArtistContribs'],
-//           compute: ({'#coverArtistContribs': coverArtistContribs}) =>
-//             coverArtistContribs.map(({who}) => who),
-//         },
-//       },
-//     ]);
-//
-// One last note! A super common code pattern when creating more complex
-// compositions is to have several steps which *only* expose and compose.
-// As a syntax shortcut, you can skip the outer section. It's basically
-// like writing out just the {expose: {...}} part. Remember that this
-// indicates that the step you're defining is compositional, so you have
-// to specify the flags manually for the base, even if this property isn't
-// going to get an {update: true} flag.
-//
-// == Cache-safe dependency names: ==
-//
-// [Disclosure: The caching engine hasn't actually been implemented yet.
-//  As such, this section is subject to change, and simply provides sound
-//  forward-facing advice and interfaces.]
-//
-// It's a good idea to write individual compositional steps in such a way
-// that they're "cache-safe" - meaning the same input (dependency) values
-// will always result in the same output (continuation or early exit).
-//
-// In order to facilitate this, compositional step descriptors may specify
-// unique `mapDependencies`, `mapContinuation`, and `options` values.
-//
-// Consider the `withResolvedContribs` example adjusted to make use of
-// two of these options below:
-//
-//   withResolvedContribs = ({
-//     from: contribsByRefDependency,
-//     into: outputDependency,
-//   }) => ({
-//     flags: {expose: true, compose: true},
-//     expose: {
-//       dependencies: ['artistData'],
-//       mapDependencies: {contribsByRef: contribsByRefDependency},
-//       mapContinuation: {outputDependency},
-//       compute({
-//         contribsByRef, /* no longer in square brackets */
-//         artistData,
-//       }, continuation) {
-//         if (!artistData) return null;
-//         return continuation({
-//           outputDependency: /* no longer in square brackets */
-//             (..resolve contributions one way or another..),
-//         });
-//       },
-//     },
-//   });
-//
-// With a little destructuring and restructuring JavaScript sugar, the
-// above can be simplified some more:
-//
-//   withResolvedContribs = ({from, to}) => ({
-//     flags: {expose: true, compose: true},
-//     expose: {
-//       dependencies: ['artistData'],
-//       mapDependencies: {from},
-//       mapContinuation: {into},
-//       compute({artistData, from: contribsByRef}, continuation) {
-//         if (!artistData) return null;
-//         return continuation({
-//           into: (..resolve contributions one way or another..),
-//         });
-//       },
-//     },
-//   });
-//
-// These two properties let you separate the name-mapping behavior (for
-// dependencies and the continuation) from the main body of the compute
-// function. That means the compute function will *always* get inputs in
-// the same form (dependencies 'artistData' and 'from' above), and will
-// *always* provide its output in the same form (early return or 'to').
-//
-// Thanks to that, this `compute` function is cache-safe! Its outputs can
-// be cached corresponding to each set of mapped inputs. So it won't matter
-// whether the `from` dependency is named `coverArtistContribsByRef` or
-// `contributorContribsByRef` or something else - the compute function
-// doesn't care, and only expects that value to be provided via its `from`
-// argument. Likewise, it doesn't matter if the output should be sent to
-// '#coverArtistContribs` or `#contributorContribs` or some other name;
-// the mapping is handled automatically outside, and compute will always
-// output its value to the continuation's `to`.
-//
-// Note that `mapDependencies` and `mapContinuation` should be objects of
-// the same "shape" each run - that is, the values will change depending on
-// outside context, but the keys are always the same. You shouldn't use
-// `mapDependencies` to dynamically select more or fewer dependencies.
-// If you need to dynamically select a range of dependencies, just specify
-// them in the `dependencies` array like usual. The caching engine will
-// understand that differently named `dependencies` indicate separate
-// input-output caches should be used.
-//
-// The 'options' property makes it possible to specify external arguments
-// that fundamentally change the behavior of the `compute` function, while
-// still remaining cache-safe. It indicates that the caching engine should
-// use a completely different input-to-output cache for each permutation
-// of the 'options' values. This way, those functions are still cacheable
-// at all; they'll just be cached separately for each set of option values.
-// Values on the 'options' property will always be provided in compute's
-// dependencies under '#options' (to avoid name conflicts with other
-// dependencies).
-//
-// == To compute or to transform: ==
-//
-// A compositional step can work directly on a property's stored update
-// value, transforming it in place and either early exiting with it or
-// passing it on (via continuation) to the next item(s) in the
-// compositional step list. (If needed, these can provide dependencies
-// the same way as compute functions too - just pass that object after
-// the updated (or same) transform value in your call to continuation().)
-//
-// But in order to make them more versatile, compositional steps have an
-// extra trick up their sleeve. If a compositional step implements compute
-// and *not* transform, it can still be used in a composition targeting a
-// property which updates! These retain their full dependency-providing and
-// early exit functionality - they just won't be provided the update value.
-// If a compute-implementing step returns its continuation, then whichever
-// later step (or the base) next implements transform() will receive the
-// update value that had so far been running - as well as any dependencies
-// the compute() step returned, of course!
-//
-// Please note that a compositional step which transforms *should not*
-// specify, in its flags, {update: true}. Just provide the transform()
-// function in its expose descriptor; it will be automatically detected
-// and used when appropriate.
-//
-// It's actually possible for a step to specify both transform and compute,
-// in which case the transform() implementation will only be selected if
-// the composition's base is {update: true}. It's not exactly known why you
-// would want to specify unique-but-related transform and compute behavior,
-// but the basic possibility was too cool to skip out on.
-//
-// == Nesting compositions: ==
-//
-// Compositional steps are so convenient that you just might want to bundle
-// them together, and form a whole new step-shaped unit of its own!
-//
-// In order to allow for this while helping to ensure internal dependencies
-// remain neatly isolated from the composition which nests your bundle,
-// the compositeFrom() function will accept and adapt to a base that
-// specifies the {compose: true} flag, just like the steps preceding it.
-//
-// The continuation function that gets provided to the base will be mildly
-// special - after all, nothing follows the base within the composition's
-// own list! Instead of appending dependencies alongside any previously
-// provided ones to be available to the next step, the base's continuation
-// function should be used to define "exports" of the composition as a
-// whole. It's similar to the usual behavior of the continuation, just
-// expanded to the scope of the composition instead of following steps.
-//
-// For example, suppose your composition (which you expect to include in
-// other compositions) brings about several private, hash-prefixed
-// dependencies to contribute to its own results. Those dependencies won't
-// end up "bleeding" into the dependency list of whichever composition is
-// nesting this one - they will totally disappear once all the steps in
-// the nested composition have finished up.
-//
-// To "export" the results of processing all those dependencies (provided
-// that's something you want to do and this composition isn't used purely
-// for a conditional early-exit), you'll want to define them in the
-// continuation passed to the base. (Customarily, those should start with
-// a hash just like the exports from any other compositional step; they're
-// still dynamically provided dependencies!)
-//
-// Another way to "export" dependencies is by using calling *any* step's
-// `continuation.raise()` function. This is sort of like early exiting,
-// but instead of quitting out the whole entire property, it will just
-// break out of the current, nested composition's list of steps, acting
-// as though the composition had finished naturally. The dependencies
-// passed to `raise` will be the ones which get exported.
-//
-// Since `raise` is another way to export dependencies, if you're using
-// dynamic export names, you should specify `mapContinuation` on the step
-// calling `continuation.raise` as well.
-//
-// An important note on `mapDependencies` here: A nested composition gets
-// free access to all the ordinary properties defined on the thing it's
-// working on, but if you want it to depend on *private* dependencies -
-// ones prefixed with '#' - which were provided by some other compositional
-// step preceding wherever this one gets nested, then you *have* to use
-// `mapDependencies` to gain access. Check out the section on "cache-safe
-// dependency names" for information on this syntax!
-//
-// Also - on rare occasion - you might want to make a reusable composition
-// that itself causes the composition *it's* nested in to raise. If that's
-// the case, give `composition.raiseAbove()` a go! This effectively means
-// kicking out of *two* layers of nested composition - the one including
-// the step with the `raiseAbove` call, and the composition which that one
-// is nested within. You don't need to use `raiseAbove` if the reusable
-// utility function just returns a single compositional step, but if you
-// want to make use of other compositional steps, it gives you access to
-// the same conditional-raise capabilities.
-//
-// Have some syntax sugar! Since nested compositions are defined by having
-// the base be {compose: true}, the composition will infer as much if you
-// don't specifying the base's flags at all. Simply use the same shorthand
-// syntax as for other compositional steps, and it'll work out cleanly!
-//
-
 const globalCompositeCache = {};
 
 const _valueIntoToken = shape =>