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

a8.shared.json.impl.JsValOps.scala Maven / Gradle / Ivy

There is a newer version: 1.0.0-20230212_1012_master
Show newest version
package a8.shared.json.impl

import a8.shared.Chord
import a8.shared.json.ast._

object JsValOps {

  object impl {
    implicit val implicitIndent: Chord.Indent = Chord.Indent(Chord.str("  "))
    val colonCh = Chord.str(":")
    val colonSpaceCh = Chord.str(": ")
    val leftBracketCh = Chord.str("[")
    val rightBracketCh = Chord.str("]")
    val leftCurlyCh = Chord.str("{")
    val rightCurlyCh = Chord.str("}")
    val trueCh = Chord.str("true")
    val falseCh = Chord.str("false")
    val nullCh = Chord.str("null")
    val nothingCh = Chord.str("")
    val newLineCh = Chord.str("\n")
    val doubleQuoteCh = Chord.str("\"")
    val commaNewLineCh = Chord.str(",\n")
  }
  import impl._

  /**
   * see here https://stackoverflow.com/questions/19176024/how-to-escape-special-characters-in-building-a-json-string
   */
  def toEscapedJsonChord(value: String): Chord = {
    val sb = new StringBuilder
    value
      .map {
        case '"' =>
          sb.append("\\\"")
        case '\\' =>
          sb.append("\\\\")
        case '\b' =>
          sb.append("\\b")
        case '\f' =>
          sb.append("\\f")
        case '\n' =>
          sb.append("\\n")
        case '\r' =>
          sb.append("\\r")
        case '\t' =>
          sb.append("\\t")
        case ch =>
          sb.append(ch)
      }
    doubleQuoteCh ~  Chord.str(sb.toString()) ~ doubleQuoteCh
  }

  def toPrettyJsonChord(JsVal: JsVal): Chord = {
    def impl(jv: JsVal): Chord =
      jv match {
        case jsd: JsDoc =>
          impl(jsd.value)
        case jn: JsNum =>
          Chord.str(jn.value.toString())
        case js: JsStr =>
          toEscapedJsonChord(js.value)
        case JsTrue =>
          trueCh
        case JsFalse =>
          falseCh
        case JsNull =>
          nullCh
        case JsNothing =>
          nothingCh
        case jarr: JsArr =>
          (
            leftBracketCh
              ~ Chord.indent (
                newLineCh
                ~ Chord.impl.IteratorChordWithSeparator(
                    () =>
                      jarr
                        .values
                        .iterator
                        .filterNot(_ == JsNothing)
                        .map(v => impl(v)),
                    commaNewLineCh,
                  )
              )
              ~ newLineCh
              ~ rightBracketCh
          )
        case jobj: JsObj =>
          (
            leftCurlyCh
              ~ Chord.indent (
                newLineCh
                ~ Chord.impl.IteratorChordWithSeparator(
                  () =>
                    jobj
                      .values
                      .iterator
                      .filterNot(_._2 == JsNothing)
                      .map(t => toEscapedJsonChord(t._1) ~ colonSpaceCh ~ impl(t._2)),
                  commaNewLineCh,
                )
              )
              ~ newLineCh
              ~ rightCurlyCh
          )

      }
    impl(JsVal)
  }

  def toCompactJsonChord(jv: JsVal, sortKeys: Boolean): Chord =
    jv match {
      case jsd: JsDoc =>
        toCompactJsonChord(jsd.value, sortKeys)
      case jn: JsNum =>
        Chord.str(jn.value.toString())
      case js: JsStr =>
        toEscapedJsonChord(js.value)
      case JsTrue =>
        trueCh
      case JsFalse =>
        falseCh
      case JsNull =>
        nullCh
      case JsNothing =>
        nothingCh
      case jarr: JsArr =>
        leftBracketCh ~
          Chord.impl.IteratorChordWithSeparator(
            () =>
              jarr
                .values
                .iterator
                .filterNot(_ == JsNothing)
                .map(v => toCompactJsonChord(v, sortKeys)),
            Chord.comma,
          ) ~
          rightBracketCh
      case jobj: JsObj =>
        // ??? TODO DRY this up
        if ( sortKeys ) {
          leftCurlyCh ~
            Chord.impl.IteratorChordWithSeparator(
              () =>
                jobj
                  .values
                  .toList
                  .sortBy(_._1)
                  .iterator
                  .filterNot(_._2 == JsNothing)
                  .map(t => toEscapedJsonChord(t._1) ~ colonCh ~ toCompactJsonChord(t._2, sortKeys)),
              Chord.comma,
            ) ~
            rightCurlyCh
        } else {
          leftCurlyCh ~
            Chord.impl.IteratorChordWithSeparator(
              () =>
                jobj
                  .values
                  .iterator
                  .filterNot(_._2 == JsNothing)
                  .map(t => toEscapedJsonChord(t._1) ~ colonCh ~ toCompactJsonChord(t._2,sortKeys)),
              Chord.comma,
            ) ~
            rightCurlyCh
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy