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

laika.api.config.ConfigEncoder.scala Maven / Gradle / Ivy

/*
 * Copyright 2012-2020 the original author or authors.
 *
 * 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 laika.api.config

import cats.data.NonEmptyChain
import laika.api.config.ConfigValue.*
import laika.ast.{ Element, Path }
import laika.config.PlatformDateTime

import java.net.URI

/** A type class that can encode a value of type T as a ConfigValue.
  *
  * @author Jens Halm
  */
trait ConfigEncoder[-T] { self =>
  def apply(value: T): ConfigValue

  def contramap[B](f: B => T): ConfigEncoder[B] = new ConfigEncoder[B] {
    def apply(value: B) = self.apply(f(value))
  }

}

/** Companion containing default encoder implementations for simple values and Seq's.
  */
object ConfigEncoder {

  implicit val boolean: ConfigEncoder[Boolean] = new ConfigEncoder[Boolean] {
    def apply(value: Boolean) = BooleanValue(value)
  }

  implicit val string: ConfigEncoder[String] = new ConfigEncoder[String] {
    def apply(value: String) = StringValue(value)
  }

  implicit val int: ConfigEncoder[Int] = new ConfigEncoder[Int] {
    def apply(value: Int) = LongValue(value.toLong)
  }

  implicit val double: ConfigEncoder[Double] = new ConfigEncoder[Double] {
    def apply(value: Double) = DoubleValue(value)
  }

  implicit val path: ConfigEncoder[Path] = new ConfigEncoder[Path] {
    def apply(value: Path) = StringValue(value.toString)
  }

  implicit val date: ConfigEncoder[PlatformDateTime.Type] =
    new ConfigEncoder[PlatformDateTime.Type] {

      def apply(value: PlatformDateTime.Type) =
        StringValue(
          PlatformDateTime.format(value, "yyyy-MM-dd'T'HH:mm:ss").getOrElse(value.toString)
        )

    }

  implicit val uri: ConfigEncoder[URI] = new ConfigEncoder[URI] {
    def apply(value: URI) = StringValue(value.toString)
  }

  implicit val astValue: ConfigEncoder[Element] = new ConfigEncoder[Element] {
    def apply(value: Element) = ASTValue(value)
  }

  implicit val configValue: ConfigEncoder[ConfigValue] = new ConfigEncoder[ConfigValue] {
    def apply(value: ConfigValue) = value
  }

  implicit def seq[T](implicit elementEncoder: ConfigEncoder[T]): ConfigEncoder[Seq[T]] =
    new ConfigEncoder[Seq[T]] {
      def apply(value: Seq[T]) = ArrayValue(value.map(elementEncoder.apply))
    }

  implicit def nec[T](implicit elementEncoder: ConfigEncoder[T]): ConfigEncoder[NonEmptyChain[T]] =
    new ConfigEncoder[NonEmptyChain[T]] {

      def apply(value: NonEmptyChain[T]) = ArrayValue(
        value.map(elementEncoder.apply).toChain.toList
      )

    }

  implicit def map[T](implicit elementEncoder: ConfigEncoder[T]): ConfigEncoder[Map[String, T]] =
    new ConfigEncoder[Map[String, T]] {

      def apply(value: Map[String, T]) = ObjectValue(
        value.toSeq.map(entry => Field(entry._1, elementEncoder(entry._2)))
      )

    }

  def apply[T](f: T => ConfigValue): ConfigEncoder[T] = new ConfigEncoder[T] {
    def apply(value: T) = f(value)
  }

  class ObjectBuilder(delegate: ConfigBuilder) {

    /** Returns a new builder instance adding the specified value to the existing set of values.
      */
    def withValue[T](key: String, value: T)(implicit encoder: ConfigEncoder[T]): ObjectBuilder =
      withValue(Key.parse(key), value)

    /** Returns a new builder instance adding the specified value to the existing set of values.
      */
    def withValue[T](key: Key, value: T)(implicit encoder: ConfigEncoder[T]): ObjectBuilder =
      new ObjectBuilder(delegate.withValue(key, value))

    /** Returns a new builder instance adding the specified value to the existing set of values if it is non-empty.
      */
    def withValue[T](key: String, value: Option[T])(implicit
        encoder: ConfigEncoder[T]
    ): ObjectBuilder =
      value.fold(this)(withValue(Key.parse(key), _))

    /** Returns a new builder instance adding the specified value to the existing set of values if it is non-empty.
      */
    def withValue[T](key: Key, value: Option[T])(implicit
        encoder: ConfigEncoder[T]
    ): ObjectBuilder =
      value.fold(this)(withValue(key, _))

    def build: ObjectValue = delegate.asObjectValue

  }

  object ObjectBuilder {
    val empty: ObjectBuilder = new ObjectBuilder(ConfigBuilder.empty)
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy