Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added indent with indicators to yaml-v12 #406

Merged
merged 12 commits into from
Jun 14, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,9 @@ object Printer {
case object Folded extends StringStyle
}

sealed trait NonPrintableStyle
object NonPrintableStyle {
case object Binary extends NonPrintableStyle
case object Escape extends NonPrintableStyle
}
}
8 changes: 5 additions & 3 deletions circe-yaml-v12/src/main/scala/io/circe/yaml/v12/Printer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import org.snakeyaml.engine.v2.api.DumpSettings
import scala.collection.JavaConverters._

object Printer {
@deprecated("Use Printer.builder instead", since = "1.15.1")
final case class Config(
preserveOrder: Boolean = false,
dropNullKeys: Boolean = false,
Expand All @@ -39,6 +40,7 @@ object Printer {
explicitEnd: Boolean = false
)

@deprecated("Use Printer.builder instead", since = "1.15.1")
def make(config: Config = Config()): common.Printer = {
import config._
new PrinterImpl(
Expand Down Expand Up @@ -68,7 +70,7 @@ object Printer {
)
}

lazy val spaces2: common.Printer = make()
lazy val spaces4: common.Printer = make(Config(indent = 4))

def builder: PrinterBuilder = PrinterBuilder()
lazy val spaces2: common.Printer = PrinterBuilder().withIndent(2).build()
lazy val spaces4: common.Printer = PrinterBuilder().withIndent(4).build()
}
125 changes: 125 additions & 0 deletions circe-yaml-v12/src/main/scala/io/circe/yaml/v12/PrinterBuilder.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* Copyright 2016 circe
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.circe.yaml.v12

import io.circe.yaml.common
import io.circe.yaml.common.Printer._
import org.snakeyaml.engine.v2.api.DumpSettings
import org.snakeyaml.engine.v2.common.{ NonPrintableStyle => SnakeNonPrintableStyle }

import scala.collection.JavaConverters._

final case class PrinterBuilder private (
aheiska marked this conversation as resolved.
Show resolved Hide resolved
preserveOrder: Boolean = false,
dropNullKeys: Boolean = false,
indent: Int = 2,
maxScalarWidth: Int = 80,
splitLines: Boolean = true,
indicatorIndent: Int = 0,
indentWithIndicator: Boolean = false,
tags: Map[String, String] = Map.empty,
sequenceStyle: FlowStyle = FlowStyle.Block,
mappingStyle: FlowStyle = FlowStyle.Block,
stringStyle: StringStyle = StringStyle.Plain,
lineBreak: LineBreak = LineBreak.Unix,
explicitStart: Boolean = false,
explicitEnd: Boolean = false,
nonPrintableStyle: NonPrintableStyle = NonPrintableStyle.Escape
) {
def withPreserveOrder(preserveOrder: Boolean): PrinterBuilder =
copy(preserveOrder = preserveOrder)

def withDropNullKeys(dropNullKeys: Boolean): PrinterBuilder =
copy(dropNullKeys = dropNullKeys)

def withIndent(indent: Int): PrinterBuilder =
copy(indent = indent)

def withMaxScalarWidth(maxScalarWidth: Int): PrinterBuilder =
copy(maxScalarWidth = maxScalarWidth)

def withSplitLines(splitLines: Boolean): PrinterBuilder =
copy(splitLines = splitLines)

def withIndicatorIndent(indicatorIndent: Int): PrinterBuilder =
copy(indicatorIndent = indicatorIndent)

def withIndentWithIndicator(indentWithIndicator: Boolean): PrinterBuilder =
copy(indentWithIndicator = indentWithIndicator)

def withTags(tags: Map[String, String]): PrinterBuilder =
copy(tags = tags)

def withSequenceStyle(sequenceStyle: common.Printer.FlowStyle): PrinterBuilder =
copy(sequenceStyle = sequenceStyle)

def withMappingStyle(mappingStyle: common.Printer.FlowStyle): PrinterBuilder =
copy(mappingStyle = mappingStyle)

def withStringStyle(stringStyle: common.Printer.StringStyle): PrinterBuilder =
copy(stringStyle = stringStyle)

def withLineBreak(lineBreak: common.Printer.LineBreak): PrinterBuilder =
copy(lineBreak = lineBreak)

def withExplicitStart(explicitStart: Boolean): PrinterBuilder =
copy(explicitStart = explicitStart)

def withExplicitEnd(explicitEnd: Boolean): PrinterBuilder =
copy(explicitEnd = explicitEnd)

def withNonPrintableStyle(nonPrintableStyle: NonPrintableStyle): PrinterBuilder =
copy(nonPrintableStyle = nonPrintableStyle)

def build(): common.Printer =
new PrinterImpl(
stringStyle,
preserveOrder,
dropNullKeys,
mappingStyle,
sequenceStyle,
DumpSettings
.builder()
.setIndent(indent)
.setWidth(maxScalarWidth)
.setSplitLines(splitLines)
.setIndicatorIndent(indicatorIndent)
.setIndentWithIndicator(indentWithIndicator)
.setTagDirective(tags.asJava)
.setDefaultScalarStyle(stringStyle.toScalarStyle)
.setExplicitStart(explicitStart)
.setExplicitEnd(explicitEnd)
.setBestLineBreak {
lineBreak match {
case LineBreak.Unix => "\n"
case LineBreak.Windows => "\r\n"
case LineBreak.Mac => "\r"
}
}
.setNonPrintableStyle {
nonPrintableStyle match {
case NonPrintableStyle.Binary => SnakeNonPrintableStyle.BINARY
case NonPrintableStyle.Escape => SnakeNonPrintableStyle.ESCAPE
}
}
.build()
)
}

object PrinterBuilder {
def apply(): PrinterBuilder = new PrinterBuilder()
}
64 changes: 51 additions & 13 deletions circe-yaml-v12/src/test/scala/io/circe/yaml/v12/PrinterTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class PrinterTests extends AnyFreeSpec with Matchers {
val json = Json.obj("foo" -> Json.arr((0 until 3).map(_.toString).map(Json.fromString): _*))

"Block" in {
val printer = Printer.make(Printer.Config(sequenceStyle = FlowStyle.Block, mappingStyle = FlowStyle.Block))
val printer = Printer.builder.withSequenceStyle(FlowStyle.Block).withMappingStyle(FlowStyle.Block).build()
printer.pretty(json) shouldEqual
"""foo:
|- '0'
Expand All @@ -39,7 +39,7 @@ class PrinterTests extends AnyFreeSpec with Matchers {
}

"Flow" in {
val printer = Printer.make(Printer.Config(sequenceStyle = FlowStyle.Flow, mappingStyle = FlowStyle.Flow))
val printer = Printer.builder.withSequenceStyle(FlowStyle.Block).withMappingStyle(FlowStyle.Flow).build()
printer.pretty(json) shouldEqual
"""{foo: ['0', '1', '2']}
|""".stripMargin
Expand All @@ -50,7 +50,7 @@ class PrinterTests extends AnyFreeSpec with Matchers {
val kvPairs = Seq("d" -> 4, "a" -> 1, "b" -> 2, "c" -> 3)
val json = Json.obj(kvPairs.map { case (k, v) => k -> Json.fromInt(v) }: _*)
"true" in {
val printer = Printer.make(Printer.Config(preserveOrder = true))
val printer = Printer.builder.withPreserveOrder(true).build()
printer.pretty(json) shouldEqual
"""d: 4
|a: 1
Expand All @@ -68,36 +68,36 @@ class PrinterTests extends AnyFreeSpec with Matchers {
val json = Json.obj("foo" -> Json.fromString(foosPlain))

"Plain" in {
val printer = Printer.make(Printer.Config(splitLines = false, stringStyle = StringStyle.Plain))
val printer = Printer.builder.withSplitLines(false).withStringStyle(StringStyle.Plain).build()
printer.pretty(json) shouldEqual
s"""foo: $foosPlain
|""".stripMargin
}

"Double quoted" in {
val printer = Printer.make(Printer.Config(stringStyle = StringStyle.DoubleQuoted))
val printer = Printer.builder.withStringStyle(StringStyle.DoubleQuoted).build()
printer.pretty(json) shouldEqual
s"""foo: "${foosSplit.mkString("\\\n \\ ")}"
|""".stripMargin
}

"Single quoted" in {
val printer = Printer.make(Printer.Config(stringStyle = StringStyle.SingleQuoted))
val printer = Printer.builder.withStringStyle(StringStyle.SingleQuoted).build()
printer.pretty(json) shouldEqual
s"""foo: '${foosSplit.mkString("\n ")}'
|""".stripMargin
}

"Folded" in {
val printer = Printer.make(Printer.Config(stringStyle = StringStyle.Folded))
val printer = Printer.builder.withStringStyle(StringStyle.Folded).build()
printer.pretty(json) shouldEqual
s"""foo: >-
| $foosFolded
|""".stripMargin
}

"Literal" in {
val printer = Printer.make(Printer.Config(stringStyle = StringStyle.Literal))
val printer = Printer.builder.withStringStyle(StringStyle.Literal).build()
printer.pretty(json) shouldEqual
s"""foo: |-
| $foosPlain
Expand All @@ -108,7 +108,7 @@ class PrinterTests extends AnyFreeSpec with Matchers {

"Plain with newlines" in {
val json = Json.obj("foo" -> Json.fromString("abc\nxyz\n"))
val printer = Printer.make(Printer.Config(stringStyle = StringStyle.Plain))
val printer = Printer.builder.withStringStyle(StringStyle.Plain).build()
printer.pretty(json) shouldEqual
s"""foo: |
| abc
Expand All @@ -118,7 +118,8 @@ class PrinterTests extends AnyFreeSpec with Matchers {

"Drop null keys" in {
val json = Json.obj("nullField" -> Json.Null, "nonNullField" -> Json.fromString("foo"))
Printer.make(Printer.Config(dropNullKeys = true)).pretty(json) shouldEqual "nonNullField: foo\n"
val printer = Printer.builder.withDropNullKeys(true).build()
printer.pretty(json) shouldEqual "nonNullField: foo\n"
}

"Root integer" in {
Expand All @@ -140,19 +141,56 @@ class PrinterTests extends AnyFreeSpec with Matchers {
val json = Json.arr(Json.fromString("foo"), Json.fromString("bar"))

"Unix" in {
Printer.make(Printer.Config(lineBreak = LineBreak.Unix)).pretty(json) shouldEqual
Printer.builder.withLineBreak(LineBreak.Unix).build().pretty(json) shouldEqual
"- foo\n- bar\n"
}

"Windows" in {
Printer.make(Printer.Config(lineBreak = LineBreak.Windows)).pretty(json) shouldEqual
Printer.builder.withLineBreak(LineBreak.Windows).build().pretty(json) shouldEqual
"- foo\r\n- bar\r\n"
}

"Mac" in {
Printer.make(Printer.Config(lineBreak = LineBreak.Mac)).pretty(json) shouldEqual
Printer.builder.withLineBreak(LineBreak.Mac).build().pretty(json) shouldEqual
"- foo\r- bar\r"
}
}

"Indicator indent" - {
val firstEl = Json.obj("a" -> Json.fromString("b"), "c" -> Json.fromString("d"))
val secondEl = Json.obj("aa" -> Json.fromString("bb"), "cc" -> Json.fromString("dd"))
val json = Json.obj("root" -> Json.arr(firstEl, secondEl))

"Default" in {
Printer.spaces2.pretty(json) shouldEqual
"""root:
|- a: b
| c: d
|- aa: bb
| cc: dd
|""".stripMargin
}

"Indent without indentWithIndicator" in {
Printer.builder.withIndicatorIndent(2).build().pretty(json) shouldEqual
"""root:
| -
| a: b
| c: d
| -
| aa: bb
| cc: dd
|""".stripMargin
}

"Indent with indentWithIndicator" in {
Printer.builder.withIndentWithIndicator(true).withIndicatorIndent(2).build().pretty(json) shouldEqual
"""root:
| - a: b
| c: d
| - aa: bb
| cc: dd
|""".stripMargin
}
}
}
Loading
Loading