« get me outta code hell

validators: isContentString: indicate actions to take - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/data/things/validators.js
diff options
context:
space:
mode:
author(quasar) nebula <qznebula@protonmail.com>2024-01-06 12:43:24 -0400
committer(quasar) nebula <qznebula@protonmail.com>2024-01-06 12:50:32 -0400
commitd6ea75273f7e76e5190e8ebb2ad195adfa7460ff (patch)
tree5f023c098779152f23a27d92d383a706046ba11d /src/data/things/validators.js
parent8b1ea1a61d4aef404224b72b90200466d65d2562 (diff)
validators: isContentString: indicate actions to take
Diffstat (limited to 'src/data/things/validators.js')
-rw-r--r--src/data/things/validators.js81
1 files changed, 68 insertions, 13 deletions
diff --git a/src/data/things/validators.js b/src/data/things/validators.js
index fb6f1da..b462be4 100644
--- a/src/data/things/validators.js
+++ b/src/data/things/validators.js
@@ -408,18 +408,49 @@ export const validateAllPropertyValues = (validator) =>
     [validateProperties.validateOtherKeys]: validator,
   });
 
-const illegalCharactersInContent = [
-  '\u200b',
+const illegalContentSpec = [
+  {
+    illegal: '\u200b',
+    action: 'delete',
+    annotation: `zero-width space`,
+  },
+  {
+    illegal: '\xa0',
+    action: 'replace',
+    with: ' ',
+    annotation: `non-breaking space`,
+    withAnnotation: `normal space`,
+  },
 ];
 
+for (const entry of illegalContentSpec) {
+  entry.test = string =>
+    string.startsWith(entry.illegal);
+
+  if (entry.action === 'replace') {
+    entry.enact = string =>
+      string.replaceAll(entry.illegal, entry.with);
+  }
+}
+
 const illegalContentRegexp =
-  new RegExp(`[${illegalCharactersInContent.join('')}]+`, 'g');
+  new RegExp(
+    illegalContentSpec
+      .map(entry => entry.illegal)
+      .map(illegal => `${illegal}+`)
+      .join('|'),
+    'g');
+
+const illegalCharactersInContent =
+  illegalContentSpec
+    .map(entry => entry.illegal)
+    .join('');
 
 const legalContentNearEndRegexp =
-  new RegExp(`[^${illegalCharactersInContent.join('')}]+$`);
+  new RegExp(`[^${illegalCharactersInContent}]+$`);
 
 const legalContentNearStartRegexp =
-  new RegExp(`^[^${illegalCharactersInContent.join('')}]+`);
+  new RegExp(`^[^${illegalCharactersInContent}]+`);
 
 const trimWhitespaceNearBothSidesRegexp =
   /^ +| +$/gm;
@@ -436,13 +467,14 @@ export function isContentString(content) {
   });
 
   const illegalAggregate = openAggregate({
-    message:
-      `Illegal characters found in content string\n` +
-      `(These probably look like normal characters, so try typing\n` +
-      ` the character that belongs into data manually, where marked)`,
+    message: `Illegal characters found in content string`,
   });
 
   for (const {match, where} of matchMultiline(content, illegalContentRegexp)) {
+    const {annotation, action, ...options} =
+      illegalContentSpec
+        .find(entry => entry.test(match[0]));
+
     const matchStart = match.index;
     const matchEnd = match.index + match[0].length;
 
@@ -459,10 +491,10 @@ export function isContentString(content) {
         ?.[0];
 
     const beforePart =
-      before && colors.green(`"${before}"`);
+      before && `"${before}"`;
 
     const afterPart =
-      after && colors.green(`"${after}"`);
+      after && `"${after}"`;
 
     const surroundings =
       (before && after
@@ -474,10 +506,33 @@ export function isContentString(content) {
         : ``);
 
     const illegalPart =
-      colors.red(`"${match[0]}"`);
+      colors.red(
+        (annotation
+          ? `"${match[0]}" (${annotation})`
+          : `"${match[0]}"`));
+
+    const replacement =
+      (action === 'replace'
+        ? options.enact(match[0])
+        : null);
+
+    const replaceWithPart =
+      (action === 'replace'
+        ? colors.green(
+            (options.withAnnotation
+              ? `"${replacement}" (${options.withAnnotation})`
+              : `"${replacement}"`))
+        : null);
+
+    const actionPart =
+      (action === `delete`
+        ? `Delete ${illegalPart}`
+     : action === 'replace'
+        ? `Replace ${illegalPart} with ${replaceWithPart}`
+        : `Matched ${illegalPart}`);
 
     const parts = [
-      `Matched ${illegalPart}`,
+      actionPart,
       surroundings,
       `(${where})`,
     ].filter(Boolean);