« get me outta code hell

html: refactor attributes toString logic - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/util
diff options
context:
space:
mode:
author(quasar) nebula <qznebula@protonmail.com>2023-12-29 18:18:03 -0400
committer(quasar) nebula <qznebula@protonmail.com>2023-12-30 12:29:51 -0400
commit64759fd0b49a6d07e70ef116d8b6fdfd1a01a223 (patch)
tree41d4ae7c421f96ae42672561babfb6549233bb2a /src/util
parent9e815d7d7a58a0fc746277e43d3b2f033d8d4e12 (diff)
html: refactor attributes toString logic
Diffstat (limited to 'src/util')
-rw-r--r--src/util/html.js87
1 files changed, 65 insertions, 22 deletions
diff --git a/src/util/html.js b/src/util/html.js
index 5b6743e..f01e2d8 100644
--- a/src/util/html.js
+++ b/src/util/html.js
@@ -502,28 +502,71 @@ export class Attributes {
   }
 
   toString() {
-    return Object.entries(this.attributes)
-      .map(([key, val]) => {
-        if (typeof val === 'undefined' || val === null)
-          return [key, val, false];
-        else if (typeof val === 'string')
-          return [key, val, true];
-        else if (typeof val === 'boolean')
-          return [key, val, val];
-        else if (typeof val === 'number')
-          return [key, val.toString(), true];
-        else if (Array.isArray(val))
-          return [key, val.filter(Boolean).join(' '), val.length > 0];
-        else
-          throw new Error(`Attribute value for ${key} should be primitive or array, got ${typeof val}`);
-      })
-      .filter(([_key, _val, keep]) => keep)
-      .map(([key, val]) =>
-        typeof val === 'boolean'
-          ? `${key}`
-          : `${key}="${this.#escapeAttributeValue(val)}"`
-      )
-      .join(' ');
+    const attributeKeyValues =
+      Object.entries(this.attributes)
+        .map(([key, value]) =>
+          (this.#keepAttributeValue(value)
+            ? [key, this.#transformAttributeValue(value), true]
+            : [key, undefined, false]))
+        .filter(([_key, _value, keep]) => keep)
+        .map(([key, value]) => [key, value]);
+
+    const attributeParts =
+      attributeKeyValues
+        .map(([key, value]) =>
+          (typeof value === 'boolean'
+            ? `${key}`
+            : `${key}="${this.#escapeAttributeValue(value)}"`));
+
+    return attributeParts.join(' ');
+  }
+
+  #keepAttributeValue(value) {
+    switch (typeof value) {
+      case 'undefined':
+        return false;
+
+      case 'object':
+        if (Array.isArray(value)) {
+          return value.some(Boolean);
+        } else if (value === null) {
+          return false;
+        } else {
+          // Other objects are an error.
+          break;
+        }
+
+      case 'boolean':
+        return value;
+
+      case 'string':
+      case 'number':
+        return true;
+
+      case 'array':
+        return value.some(Boolean);
+    }
+
+    throw new Error(
+      `Attribute value for ${key} should be primitive or array, ` +
+      `got ${typeAppearance(val)}`);
+  }
+
+  #transformAttributeValue(value) {
+    switch (typeof value) {
+      case 'boolean':
+        return value;
+
+      case 'number':
+        return value.toString();
+
+      // If it's a kept object, it's an array.
+      case 'object':
+        return value.filter(Boolean).join(' ');
+
+      default:
+        return value;
+    }
   }
 
   #escapeAttributeValue(value) {