All Downloads are FREE. Search and download functionalities are using the official Maven repository.

aml4s-snake_3.0.3.0.source-code.SnakePrinter.scala Maven / Gradle / Ivy

/*
 * Copyright 2023 Hossein Naderi
 *
 * 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 dev.hnaderi.yaml4s
package snakeyaml

import org.snakeyaml.engine.v2.api.DumpSettings
import org.snakeyaml.engine.v2.api.StreamDataWriter
import org.snakeyaml.engine.v2.common
import org.snakeyaml.engine.v2.emitter.Emitter
import org.snakeyaml.engine.v2.nodes._
import org.snakeyaml.engine.v2.serializer.Serializer

import java.io.StringWriter
import Conversions._

private[yaml4s] trait SnakePrinter extends Printer {

  override def print[T: Visitable](t: T): String = {
    val writer = new StreamToStringWriter
    val options = DumpSettings.builder().build()
    val serializer = new Serializer(options, new Emitter(options, writer))
    serializer.emitStreamStart()
    serializer.serializeDocument(toNode(t))
    serializer.emitStreamEnd()
    writer.toString
  }

  override def printDocuments[T: Visitable](ts: Iterable[T]): String = {
    val writer = new StreamToStringWriter
    val options = DumpSettings.builder().build()
    val serializer = new Serializer(options, new Emitter(options, writer))
    serializer.emitStreamStart()
    ts.foreach(t => serializer.serializeDocument(toNode(t)))
    serializer.emitStreamEnd()
    writer.toString
  }

  private[this] class StreamToStringWriter
      extends StringWriter
      with StreamDataWriter {
    override def flush(): Unit = super.flush() // to fix "conflicting members"
  }

  private def isBad(s: String): Boolean =
    s.indexOf('\u0085') >= 0 || s.indexOf('\ufeff') >= 0
  private def hasNewline(s: String): Boolean = s.indexOf('\n') >= 0

  private def scalarStyle(value: String): common.ScalarStyle =
    if (isBad(value)) common.ScalarStyle.DOUBLE_QUOTED
    else common.ScalarStyle.PLAIN

  private def stringScalarStyle(
      value: String
  ): common.ScalarStyle = // TODO config
    if (isBad(value)) common.ScalarStyle.DOUBLE_QUOTED
    else if (hasNewline(value)) common.ScalarStyle.LITERAL
    else common.ScalarStyle.PLAIN

  private def scalarNode(tag: Tag, value: String) =
    new ScalarNode(tag, value, scalarStyle(value))
  private def stringNode(value: String) =
    new ScalarNode(Tag.STR, value, stringScalarStyle(value))
  private def keyNode(value: String) =
    new ScalarNode(Tag.STR, value, scalarStyle(value))

  private def toNode[T](t: T)(implicit vis: Visitable[T]): Node =
    vis.visit(
      t,
      new Visitor[T, Node] {
        override def onNull: Node = scalarNode(Tag.NULL, "null")
        override def onBoolean(value: Boolean): Node =
          scalarNode(Tag.BOOL, value.toString)
        override def onNumber(value: YamlNumber): Node =
          scalarNode(if (value.isWhole) Tag.INT else Tag.FLOAT, value.toString)
        override def onString(value: String): Node = stringNode(value)
        override def onArray(value: Iterable[T]): Node =
          new SequenceNode(
            Tag.SEQ,
            value.map(vis.visit(_, this)).toList.asJava,
            common.FlowStyle.FLOW // TODO config
          )
        override def onObject(fields: Iterable[(String, T)]): Node = {
          val map = fields.toMap
          val keys = fields.map(_._1)
          val childNodes = keys.flatMap { key =>
            val value = map(key)
            Some(new NodeTuple(keyNode(key), vis.visit(value, this)))
          }
          new MappingNode(
            Tag.MAP,
            childNodes.toList.asJava,
            common.FlowStyle.AUTO
          )
        }
      }
    )

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy