« 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/thing.js2
-rw-r--r--src/find-reverse.js100
-rw-r--r--src/find.js80
-rw-r--r--src/reverse.js32
-rw-r--r--src/write/build-modes/repl.js3
5 files changed, 157 insertions, 60 deletions
diff --git a/src/data/thing.js b/src/data/thing.js
index 78ad3642..4c3ba3e4 100644
--- a/src/data/thing.js
+++ b/src/data/thing.js
@@ -16,6 +16,8 @@ export default class Thing extends CacheableObject {
   static findSpecs = Symbol.for('Thing.findSpecs');
   static findThisThingOnly = Symbol.for('Thing.findThisThingOnly');
 
+  static reverseSpecs = Symbol.for('Thing.reverseSpecs');
+
   static yamlDocumentSpec = Symbol.for('Thing.yamlDocumentSpec');
   static getYamlLoadingSpec = Symbol.for('Thing.getYamlLoadingSpec');
 
diff --git a/src/find-reverse.js b/src/find-reverse.js
new file mode 100644
index 00000000..47e0e268
--- /dev/null
+++ b/src/find-reverse.js
@@ -0,0 +1,100 @@
+// Helpers common to #find and #reverse logic.
+
+import thingConstructors from '#things';
+
+export function getAllSpecs({
+  word,
+  constructorKey,
+
+  hardcodedSpecs,
+  postprocessSpec,
+}) {
+  try {
+    thingConstructors;
+  } catch (error) {
+    throw new Error(`Thing constructors aren't ready yet, can't get all ${word} specs`);
+  }
+
+  const specs = {...hardcodedSpecs};
+
+  for (const thingConstructor of Object.values(thingConstructors)) {
+    const thingSpecs = thingConstructor[constructorKey];
+    if (!thingSpecs) continue;
+
+    for (const [key, spec] of Object.entries(thingSpecs)) {
+      specs[key] =
+        postprocessSpec(spec, {
+          thingConstructor,
+        });
+    }
+  }
+
+  return specs;
+}
+
+export function findSpec(key, {
+  word,
+  constructorKey,
+
+  hardcodedSpecs,
+  postprocessSpec,
+}) {
+  if (Object.hasOwn(hardcodedSpecs, key)) {
+    return hardcodedSpecs[key];
+  }
+
+  try {
+    thingConstructors;
+  } catch (error) {
+    throw new Error(`Thing constructors aren't ready yet, can't check if "${word}.${key}" available`);
+  }
+
+  for (const thingConstructor of Object.values(thingConstructors)) {
+    const thingSpecs = thingConstructor[constructorKey];
+    if (!thingSpecs) continue;
+
+    if (Object.hasOwn(thingSpecs, key)) {
+      return postprocessSpec(thingSpecs[key], {
+        thingConstructor,
+      });
+    }
+  }
+
+  throw new Error(`"${word}.${key}" isn't available`);
+}
+
+export function tokenProxy({
+  findSpec,
+  prepareBehavior,
+
+  handle: customHandle =
+    (_key) => undefined,
+
+  decorate =
+    (_token, _key) => {},
+}) {
+  return new Proxy({}, {
+    get: (store, key) => {
+      const custom = customHandle(key);
+      if (custom !== undefined) {
+        return custom;
+      }
+
+      if (!Object.hasOwn(store, key)) {
+        let behavior = (...args) => {
+          // This will error if the spec isn't available...
+          const spec = findSpec(key);
+
+          // ...or, if it is available, replace this function with the
+          // ready-for-use find function made out of that spec.
+          return (behavior = prepareBehavior(spec))(...args);
+        };
+
+        store[key] = (...args) => behavior(...args);
+        decorate(store[key], key);
+      }
+
+      return store[key];
+    },
+    });
+}
diff --git a/src/find.js b/src/find.js
index d647419a..29f32dad 100644
--- a/src/find.js
+++ b/src/find.js
@@ -5,6 +5,8 @@ import {compareObjects, stitchArrays, typeAppearance} from '#sugar';
 import thingConstructors from '#things';
 import {isFunction, validateArrayItems} from '#validators';
 
+import {findSpec, getAllSpecs, tokenProxy} from './find-reverse.js';
+
 function warnOrThrow(mode, message) {
   if (mode === 'error') {
     throw new Error(message);
@@ -240,6 +242,14 @@ const hardcodedFindSpecs = {
   },
 };
 
+const findReverseHelperConfig = {
+  word: `find`,
+  constructorKey: Symbol.for('Thing.findSpecs'),
+
+  hardcodedSpecs: hardcodedFindSpecs,
+  postprocessSpec: postprocessFindSpec,
+};
+
 export function postprocessFindSpec(spec, {thingConstructor}) {
   const newSpec = {...spec};
 
@@ -261,52 +271,11 @@ export function postprocessFindSpec(spec, {thingConstructor}) {
 }
 
 export function getAllFindSpecs() {
-  try {
-    thingConstructors;
-  } catch (error) {
-    throw new Error(`Thing constructors aren't ready yet, can't get all find specs`);
-  }
-
-  const findSpecs = {...hardcodedFindSpecs};
-
-  for (const thingConstructor of Object.values(thingConstructors)) {
-    const thingFindSpecs = thingConstructor[Symbol.for('Thing.findSpecs')];
-    if (!thingFindSpecs) continue;
-
-    for (const [key, spec] of Object.entries(thingFindSpecs)) {
-      findSpecs[key] =
-        postprocessFindSpec(spec, {
-          thingConstructor,
-        });
-    }
-  }
-
-  return findSpecs;
+  return getAllSpecs(findReverseHelperConfig);
 }
 
 export function findFindSpec(key) {
-  if (Object.hasOwn(hardcodedFindSpecs, key)) {
-    return hardcodedFindSpecs[key];
-  }
-
-  try {
-    thingConstructors;
-  } catch (error) {
-    throw new Error(`Thing constructors aren't ready yet, can't check if "find.${key}" available`);
-  }
-
-  for (const thingConstructor of Object.values(thingConstructors)) {
-    const thingFindSpecs = thingConstructor[Symbol.for('Thing.findSpecs')];
-    if (!thingFindSpecs) continue;
-
-    if (Object.hasOwn(thingFindSpecs, key)) {
-      return postprocessFindSpec(thingFindSpecs[key], {
-        thingConstructor,
-      });
-    }
-  }
-
-  throw new Error(`"find.${key}" isn't available`);
+  return findSpec(key, findReverseHelperConfig);
 }
 
 export const findTokenKey = Symbol.for('find.findTokenKey');
@@ -425,27 +394,18 @@ export function findMixed(config) {
   return findMixedStore.get(config);
 }
 
-export default new Proxy({}, {
-  get: (store, key) => {
+export default tokenProxy({
+  findSpec: findFindSpec,
+  prepareBehavior: findHelper,
+
+  handle(key) {
     if (key === 'mixed') {
       return findMixed;
     }
+  },
 
-    if (!Object.hasOwn(store, key)) {
-      let behavior = (...args) => {
-        // This will error if the find spec isn't available...
-        const findSpec = findFindSpec(key);
-
-        // ...or, if it is available, replace this function with the
-        // ready-for-use find function made out of that find spec.
-        return (behavior = findHelper(findSpec))(...args);
-      };
-
-      store[key] = (...args) => behavior(...args);
-      store[key][findTokenKey] = key;
-    }
-
-    return store[key];
+  decorate(token, key) {
+    token[findTokenKey] = key;
   },
 });
 
diff --git a/src/reverse.js b/src/reverse.js
new file mode 100644
index 00000000..b5a4bf4c
--- /dev/null
+++ b/src/reverse.js
@@ -0,0 +1,32 @@
+import {findSpec, getAllSpecs, tokenProxy} from './find-reverse.js';
+
+const hardcodedReverseSpecs = {};
+
+const findReverseHelperConfig = {
+  word: `reverse`,
+  constructorKey: Symbol.for('Thing.reverseSpecs'),
+
+  hardcodedSpecs: hardcodedReverseSpecs,
+  postprocessSpec: postprocessReverseSpec,
+};
+
+export function postprocessReverseSpec(spec, {thingConstructor}) {
+  const newSpec = {...spec};
+
+  void thingConstructor;
+
+  return newSpec;
+}
+
+export function getAllReverseSpecs() {
+  return getAllSpecs(findReverseHelperConfig);
+}
+
+export function findReverseSpec(key) {
+  return findSpec(key, findReverseHelperConfig);
+}
+
+export default tokenProxy({
+  findSpec: findReverseSpec,
+  prepareBehavior: spec => from => ({spec, from}),
+});
diff --git a/src/write/build-modes/repl.js b/src/write/build-modes/repl.js
index 957d2c2d..ff64ee82 100644
--- a/src/write/build-modes/repl.js
+++ b/src/write/build-modes/repl.js
@@ -36,6 +36,7 @@ import * as path from 'node:path';
 import * as repl from 'node:repl';
 
 import _find, {bindFind} from '#find';
+import _reverse from '#reverse';
 import CacheableObject from '#cacheable-object';
 import {logWarn} from '#cli';
 import {debugComposite} from '#composite';
@@ -95,6 +96,8 @@ export async function getContextAssignments({
     find,
     bindFind,
 
+    _reverse,
+
     showAggregate,
   };