From c06cdf2108e43adbf78231f5e57a89e068901778 Mon Sep 17 00:00:00 2001 From: Travis Brown Date: Thu, 8 Jun 2017 16:33:47 -0500 Subject: [PATCH] Support merge keys --- .../scala/io/circe/yaml/parser/package.scala | 14 ++++++- src/test/resources/test-yamls/merge-key.json | 40 +++++++++++++++++++ src/test/resources/test-yamls/merge-key.yml | 27 +++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 src/test/resources/test-yamls/merge-key.json create mode 100644 src/test/resources/test-yamls/merge-key.yml diff --git a/src/main/scala/io/circe/yaml/parser/package.scala b/src/main/scala/io/circe/yaml/parser/package.scala index d6039819..a7e3d969 100644 --- a/src/main/scala/io/circe/yaml/parser/package.scala +++ b/src/main/scala/io/circe/yaml/parser/package.scala @@ -4,6 +4,7 @@ import cats.syntax.either._ import io.circe._ import java.io.{Reader, StringReader} import org.yaml.snakeyaml.Yaml +import org.yaml.snakeyaml.constructor.SafeConstructor import org.yaml.snakeyaml.nodes._ import scala.collection.JavaConverters._ @@ -38,6 +39,15 @@ package object parser { None } + private[this] class FlatteningConstructor extends SafeConstructor { + def flatten(node: MappingNode): MappingNode = { + flattenMapping(node) + node + } + } + + private[this] val flattener: FlatteningConstructor = new FlatteningConstructor + private[this] def yamlToJson(node: Node): Either[ParsingFailure, Json] = { def convertScalarNode(node: ScalarNode) = Either.catchNonFatal(node.getTag match { @@ -61,7 +71,9 @@ package object parser { node match { case mapping: MappingNode => - mapping.getValue.asScala.foldLeft(Either.right[ParsingFailure, JsonObject](JsonObject.empty)) { + flattener.flatten(mapping).getValue.asScala.foldLeft( + Either.right[ParsingFailure, JsonObject](JsonObject.empty) + ) { (objEither, tup) => for { obj <- objEither key <- convertKeyNode(tup.getKeyNode) diff --git a/src/test/resources/test-yamls/merge-key.json b/src/test/resources/test-yamls/merge-key.json new file mode 100644 index 00000000..dae8042a --- /dev/null +++ b/src/test/resources/test-yamls/merge-key.json @@ -0,0 +1,40 @@ +[ + { + "x" : 1, + "y" : 2 + }, + { + "x" : 0, + "y" : 2 + }, + { + "r" : 1e1 + }, + { + "r" : 1 + }, + { + "x" : 1, + "y" : 2, + "r" : 1e1, + "label" : "center/big" + }, + { + "x" : 1, + "y" : 2, + "r" : 1e1, + "label" : "center/big" + }, + { + "x" : 1, + "y" : 2, + "r" : 1e1, + "label" : "center/big" + }, + { + "r" : 1e1, + "x" : 1, + "y" : 2, + "label" : "center/big" + } +] \ No newline at end of file diff --git a/src/test/resources/test-yamls/merge-key.yml b/src/test/resources/test-yamls/merge-key.yml new file mode 100644 index 00000000..ee4a48fe --- /dev/null +++ b/src/test/resources/test-yamls/merge-key.yml @@ -0,0 +1,27 @@ +--- +- &CENTER { x: 1, y: 2 } +- &LEFT { x: 0, y: 2 } +- &BIG { r: 10 } +- &SMALL { r: 1 } + +# All the following maps are equal: + +- # Explicit keys + x: 1 + y: 2 + r: 10 + label: center/big + +- # Merge one map + << : *CENTER + r: 10 + label: center/big + +- # Merge multiple maps + << : [ *CENTER, *BIG ] + label: center/big + +- # Override + << : [ *BIG, *LEFT, *SMALL ] + x: 1 + label: center/big