Repository: decorators-squad/eo-yaml
Pull request #496 (2022-03-27 08:55:20)

#494 Support for bracket notation.
PR for #494 


Patch:
diff --git a/src/main/java/com/amihaiemil/eoyaml/ReadYamlMapping.java b/src/main/java/com/amihaiemil/eoyaml/ReadYamlMapping.java
index 33dcc9e..bd525f6 100644
--- a/src/main/java/com/amihaiemil/eoyaml/ReadYamlMapping.java
+++ b/src/main/java/com/amihaiemil/eoyaml/ReadYamlMapping.java
@@ -161,11 +161,11 @@ final class ReadYamlMapping extends BaseYamlMapping {
                 final String key;
                 if(trimmed.startsWith("-")) {
                     key = trimmed.substring(
-                        1, trimmed.indexOf(":")
+                        1, trimmed.lastIndexOf(":")
                     ).trim();
                 } else {
                     key = trimmed.substring(
-                        0, trimmed.indexOf(":")
+                        0, trimmed.lastIndexOf(":")
                     ).trim();
                 }
                 if(!key.isEmpty()) {
@@ -241,21 +241,22 @@ final class ReadYamlMapping extends BaseYamlMapping {
         for(final String tryKey : keys) {
             for (final YamlLine line : this.significant) {
                 final String trimmed = line.trimmed();
-                if(trimmed.matches("^-?[ ]*" + Pattern.quote(tryKey) + ":")
-                    || trimmed.matches("^" + Pattern.quote(tryKey) + ":[ ]*>$")
-                    || trimmed.matches("^" + Pattern.quote(tryKey) + ":[ ]*\\|[+-]?$")
+                final String relaxedKey = relaxed(tryKey);
+                if(trimmed.matches("^-?[ ]*" + Pattern.quote(relaxedKey) + ":")
+                    || trimmed.matches("^" + Pattern.quote(relaxedKey) + ":[ ]*>$")
+                    || trimmed.matches("^" + Pattern.quote(relaxedKey) + ":[ ]*\\|[+-]?$")
                 ) {
                     value = this.significant.toYamlNode(
                         line, this.guessIndentation
                     );
-                } else if (trimmed.matches(tryKey + ":[ ]*\\{}")) {
+                } else if (trimmed.matches(relaxedKey + ":[ ]*\\{}")) {
                     value = new EmptyYamlMapping(new ReadYamlMapping(
                             line.number(),
                             this.all.line(line.number()),
                             this.all,
                             this.guessIndentation
                     ));
-                } else if (trimmed.matches(tryKey + ":[ ]*\\[]")) {
+                } else if (trimmed.matches(relaxedKey + ":[ ]*\\[]")) {
                     value = new EmptyYamlSequence(new ReadYamlSequence(
                             this.all.line(line.number()),
                             this.all,
@@ -276,6 +277,27 @@ final class ReadYamlMapping extends BaseYamlMapping {
         return null;
     }
 
+    /**
+     * Escape [ and ] for regex matching when key starts with "[ and ends with
+     * "].
+     * @param key Provided key.
+     * @return Relaxed key for pattern matching.
+     */
+    private String relaxed(final String key){
+        final String regexEscape;
+        if(key.startsWith("\"[") && key.endsWith("]\"")){
+            final int openIndex = 1;
+            final int closedIndex = key.length() - 1;
+            final StringBuilder builder = new StringBuilder(key);
+            builder.insert(openIndex, "\\\\");
+            builder.insert(closedIndex, "\\\\");
+            regexEscape = builder.toString();
+        }else {
+            regexEscape = key;
+        }
+        return regexEscape;
+    }
+
     /**
      * The YamlNode value associated with a YamlNode key
      * (a "complex" key starting with '?').


Test patch:
diff --git a/src/test/java/com/amihaiemil/eoyaml/RtYamlInputTest.java b/src/test/java/com/amihaiemil/eoyaml/RtYamlInputTest.java
index cd988c0..ee654ad 100644
--- a/src/test/java/com/amihaiemil/eoyaml/RtYamlInputTest.java
+++ b/src/test/java/com/amihaiemil/eoyaml/RtYamlInputTest.java
@@ -35,6 +35,7 @@ import java.util.Set;
 import org.apache.commons.io.IOUtils;
 import org.hamcrest.MatcherAssert;
 import org.hamcrest.Matchers;
+import org.junit.Ignore;
 import org.junit.Test;
 
 /**
@@ -879,6 +880,43 @@ public final class RtYamlInputTest {
         );
     }
 
+
+    /**
+     * Do a round-trip test on the bracketed-key sample file.
+     *
+     * <a href="https://github.com/decorators-squad/eo-yaml/issues/494">#494</a>
+     * based on
+     * <a href="https://github.com/decorators-squad/eo-yaml/issues/495">PR</a>
+     *
+     * @throws IOException When there's a problem reading the sample files.
+     */
+    @Test
+    public void supportsBracketedNotation() throws IOException {
+        final String filename = "issue_494_bracketed_keys.yml";
+        final String fileContents = readTestResource(filename).trim();
+
+        final YamlMapping read = new RtYamlInput(
+            new FileInputStream("src/test/resources/" + filename)
+        ).readYamlMapping();
+
+        MatcherAssert.assertThat(read.type(), Matchers.equalTo(Node.MAPPING));
+        MatcherAssert.assertThat(
+            read.asMapping().keys().size(),
+            Matchers.equalTo(1));
+
+        final YamlNode topLevelMapping = read.asMapping().value("a_mapping");
+        MatcherAssert.assertThat(
+            topLevelMapping.type(),
+            Matchers.equalTo(Node.MAPPING));
+        MatcherAssert.assertThat(
+            topLevelMapping.asMapping().keys().size(),
+            Matchers.equalTo(1));
+
+        final String pretty = read.toString().trim();
+
+        MatcherAssert.assertThat(pretty, Matchers.equalTo(fileContents));
+    }
+
     /**
      * Read a test resource file's contents.
      * @param fileName File to read.
diff --git a/src/test/resources/issue_494_bracketed_keys.yml b/src/test/resources/issue_494_bracketed_keys.yml
new file mode 100644
index 0000000..1694003
--- /dev/null
+++ b/src/test/resources/issue_494_bracketed_keys.yml
@@ -0,0 +1,2 @@
+a_mapping:
+  "[bracketed:key]": val0
\ No newline at end of file