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

smithy4s.codegen.internals.LineSegment.scala Maven / Gradle / Ivy

There is a newer version: 0.19.0-41-91762fb
Show newest version
/*
 *  Copyright 2021-2024 Disney Streaming
 *
 *  Licensed under the Tomorrow Open Source Technology License, Version 1.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     https://disneystreaming.github.io/TOST-1.0.txt
 *
 *  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 smithy4s.codegen.internals

import cats.Show
import cats.data.Chain
import cats.implicits._

// LineSegment models segments of a line of code.
private[codegen] sealed trait LineSegment { self =>
  def toLine: Line = Line(Chain.one(self))
}
private[codegen] object LineSegment {
  // Models an Import statement, will be elided from the actual scala code
  case class Import(value: String) extends LineSegment
  object Import {
    implicit val importShow: Show[Import] = Show.show[Import](_.value)
  }
  // Models a general piece of scala code, no additional structure is known.
  case class Literal(value: String) extends LineSegment
  object Literal {
    implicit val literalShow: Show[Literal] = Show.show[Literal](_.value)
  }
  // Definition of a Scala Type like trait, class.
  case class NameDef(name: String) extends LineSegment {
    def toNameRef: NameRef = NameRef(name)
  }
  object NameDef {
    implicit val nameDefShow: Show[NameDef] = Show.show[NameDef](_.name)
  }
  // A Reference to a Scala type or value s.
  case class NameRef(
      rawPkg: List[String],
      name: String,
      typeParams: List[NameRef]
  ) extends LineSegment {
    self =>

    def nameDef: NameDef = NameDef(name)

    def down(name: String): NameRef = this.copy(
      rawPkg = rawPkg :+ this.name,
      name = name,
      typeParams = List.empty
    )

    def pkg: List[String] = rawPkg.map(CollisionAvoidance.protectKeyword(_))

    def asValue: String = s"${(pkg :+ name).mkString(".")}"

    def asImport: String = s"${(pkg :+ getNamePrefix).mkString(".")}"

    def isAutoImported: Boolean = {
      val value = pkg.mkString(".")
      NameRef.autoImportedNames.exists(_.equalsIgnoreCase(value))
    }
    def getNamePrefix: String = name.split("\\.").head
    def +(piece: String): NameRef = {
      self.copy(name = self.name + piece)
    }

    override def toLine: Line = {
      val paramLines =
        typeParams.map(_.toLine).foldLeft(Line.empty) { case (acc, i) =>
          if (acc.nonEmpty) acc + Literal(",") + Line.space + i else i
        }
      val selfLine = super.toLine
      if (paramLines.nonEmpty)
        selfLine + Literal("[") + paramLines + Literal("]")
      else selfLine
    }

  }

  object NameRef {
    val autoImportedNames: List[String] = List(
      "scala",
      "java.lang",
      "scala.Predef",
      "scala.collection.immutable"
    )
    implicit val nameRefShow: Show[NameRef] = Show.show[NameRef](_.asImport)
    def apply(pkg: String, name: String): NameRef =
      NameRef(pkg.split("\\.").toList, name, List.empty)
    def apply(fqn: String): NameRef = {
      val parts = fqn.split("\\.").toList.toNel.get
      NameRef(parts.toList.dropRight(1), parts.last, List.empty)
    }
    def apply(fqn: String, typeParams: List[NameRef]): NameRef =
      apply(fqn).copy(typeParams = typeParams)
  }

  implicit val lineSegmentShow: Show[LineSegment] = Show.show {
    case Import(value)  => value
    case Literal(value) => value
    case td: NameDef    => td.show
    case tr: NameRef    => tr.show
  }
  implicit val lineShow: Show[Line] =
    Show.show(line => line.segments.toList.map(_.show).mkString(""))

  implicit def chainShow[A: Show]: Show[Chain[A]] = Show.show { chain =>
    chain.toList.map(_.show).mkString
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy