« get me outta code hell

data: yaml: arrays of subdocs - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/data
diff options
context:
space:
mode:
author(quasar) nebula <qznebula@protonmail.com>2025-04-02 15:09:54 -0300
committer(quasar) nebula <qznebula@protonmail.com>2025-04-10 16:02:38 -0300
commit4030a62fc518627071dc792e2754d9d99fa46546 (patch)
tree398a663318653d641a98ea92f4d4d5e67a0fea6d /src/data
parent883c5209f4e78600b851238646bbdcaafdcc210b (diff)
data: yaml: arrays of subdocs
Diffstat (limited to 'src/data')
-rw-r--r--src/data/yaml.js100
1 files changed, 78 insertions, 22 deletions
diff --git a/src/data/yaml.js b/src/data/yaml.js
index c2bdc69a..d30bb54c 100644
--- a/src/data/yaml.js
+++ b/src/data/yaml.js
@@ -207,7 +207,12 @@ function makeProcessDocument(thingConstructor, {
     const fieldValues = {};
 
     const subdocSymbol = Symbol('subdoc');
-    const subdocSetups = {};
+    const subdocLayouts = {};
+
+    const isSubdocToken = value =>
+      typeof value === 'object' &&
+      value !== null &&
+      Object.hasOwn(value, subdocSymbol);
 
     const transformUtilities = {
       ...thingConstructors,
@@ -267,12 +272,15 @@ function makeProcessDocument(thingConstructor, {
         }
       }
 
-      if (
-        typeof propertyValue === 'object' &&
-        propertyValue !== null &&
-        Object.hasOwn(propertyValue, subdocSymbol)
-      ) {
-        subdocSetups[field] = propertyValue[subdocSymbol];
+      if (isSubdocToken(propertyValue)) {
+        subdocLayouts[field] = propertyValue[subdocSymbol];
+        continue;
+      }
+
+      if (Array.isArray(propertyValue) && propertyValue.every(isSubdocToken)) {
+        subdocLayouts[field] =
+          propertyValue
+            .map(token => token[subdocSymbol]);
         continue;
       }
 
@@ -280,31 +288,76 @@ function makeProcessDocument(thingConstructor, {
     }
 
     const subdocErrors = [];
-    for (const [field, setup] of Object.entries(subdocSetups)) {
+
+    const followSubdocSetup = setup => {
+      let error = null;
+
       let subthing;
       try {
         const result = bouncer(setup.data, setup.documentType);
         subthing = result.thing;
         result.aggregate.close();
       } catch (caughtError) {
-        if (!subthing) {
-          skippedFields.add(field);
+        error = caughtError;
+      }
+
+      if (subthing) {
+        if (setup.bindInto) {
+          subthing[setup.bindInto] = thing;
         }
 
-        subdocErrors.push(new SubdocError(
-          field, setup, {cause: caughtError}));
+        if (setup.provide) {
+          Object.assign(subthing, setup.provide);
+        }
       }
 
-      if (setup.bindInto) {
-        subthing[setup.bindInto] = thing;
-      }
+      return {error, subthing};
+    };
 
-      if (setup.provide) {
-        Object.assign(subthing, setup.provide);
-      }
+    for (const [field, layout] of Object.entries(subdocLayouts)) {
+      if (Array.isArray(layout)) {
+        const subthings = [];
+        let anySucceeded = false;
+        let anyFailed = false;
+
+        for (const [index, setup] of layout.entries()) {
+          const {subthing, error} = followSubdocSetup(setup);
+          if (error) {
+            subdocErrors.push(new SubdocError(
+              {field, index},
+              setup,
+              {cause: error}));
+          }
 
-      if (subthing) {
-        fieldValues[field] = subthing;
+          if (subthing) {
+            subthings.push(subthing);
+            anySucceeded = true;
+          } else {
+            anyFailed = true;
+          }
+        }
+
+        if (anySucceeded) {
+          fieldValues[field] = subthings;
+        } else if (anyFailed) {
+          skippedFields.add(field);
+        }
+      } else {
+        const setup = layout;
+        const {subthing, error} = followSubdocSetup(setup);
+
+        if (error) {
+          subdocErrors.push(new SubdocError(
+            {field},
+            setup,
+            {cause: error}));
+        }
+
+        if (subthing) {
+          fieldValues[field] = subthing;
+        } else {
+          skippedFields.add(field);
+        }
       }
     }
 
@@ -441,9 +494,12 @@ export class SkippedFieldsSummaryError extends Error {
 }
 
 export class SubdocError extends Error {
-  constructor(field, setup, options) {
+  constructor({field, index = null}, setup, options) {
     const fieldText =
-      colors.green(`"${field}"`);
+      (index === null
+        ? colors.green(`"${field}"`)
+        : colors.yellow(`#${index + 1}`) + ' in ' +
+          colors.green(`"${field}"`));
 
     const constructorText =
       setup.documentType.name;