Skip to main content

EmitterConfig

EmitterConfig controls how ScalaEmitter formats Scala code. Customize indentation, import sorting, trailing commas, and target Scala version (2 vs 3) by creating a configured instance.

Use Cases

  • Configuring code style (indentation, commas) to match your project conventions
  • Targeting Scala 3 features (enums, derives) or Scala 2 fallback syntax
  • Controlling import statement ordering
  • Emitting code for different codebases with different style preferences

Configuration Fields

FieldTypeDefaultDescription
indentWidthInt2Spaces per indentation level
sortImportsBooleantrueSort import statements alphabetically
trailingCommasBooleantrueAdd trailing commas in collections
scala3SyntaxBooleantrueTarget Scala 3 syntax features

Construction

Create a default configuration:

import zio.blocks.codegen.emit._

val default = EmitterConfig()
// indentWidth=2, sortImports=true, trailingCommas=true, scala3Syntax=true

With custom settings:

import zio.blocks.codegen.emit._

val custom = EmitterConfig(
indentWidth = 4,
sortImports = true,
trailingCommas = false,
scala3Syntax = false
)

Key Operations

All EmitterConfig instances provide these operations:

Accessing Configuration

Read configuration values:

import zio.blocks.codegen.emit._

val config = EmitterConfig(indentWidth = 4)

config.indentWidth // 4
config.sortImports // true (default)
config.trailingCommas // true (default)
config.scala3Syntax // true (default)

Building with Copy

Modify a configuration:

import zio.blocks.codegen.emit._

val base = EmitterConfig()

val scala2Config = base.copy(
scala3Syntax = false
)

val wideIndentConfig = base.copy(
indentWidth = 4
)

Examples

Here are practical examples showing different configuration scenarios:

Example 1: Standard Configuration

The default configuration for most projects:

import zio.blocks.codegen.ir._
import zio.blocks.codegen.emit._

val file = ScalaFile(
packageDecl = PackageDecl("com.example"),
types = List(
CaseClass("User", List(
Field("id", TypeRef.Long),
Field("name", TypeRef.String)
))
)
)

val config = EmitterConfig()

Emits:

import zio.blocks.codegen.emit._
ScalaEmitter.emit(file, config)
// res5: String = """package com.example
//
// case class User(
// id: Long,
// name: String,
// )
// """

Example 2: Wide Indentation (4 spaces)

For projects preferring 4-space indentation:

import zio.blocks.codegen.ir._
import zio.blocks.codegen.emit._

val file = ScalaFile(
packageDecl = PackageDecl("com.example"),
types = List(
SealedTrait(
"Result",
cases = List(
SealedTraitCase.CaseClassCase(
CaseClass("Success", List(
Field("value", TypeRef.String)
))
),
SealedTraitCase.CaseObjectCase("Failure")
)
)
)
)

val config = EmitterConfig(indentWidth = 4)

Emits with 4-space indentation:

import zio.blocks.codegen.emit._
ScalaEmitter.emit(file, config)
// res7: String = """package com.example
//
// sealed trait Result
//
// object Result {
// case class Success(
// value: String,
// ) extends Result
// case object Failure extends Result
// }
// """

Example 3: Scala 2 Compatibility

Target Scala 2 syntax for older codebases:

import zio.blocks.codegen.ir._
import zio.blocks.codegen.emit._

val file = ScalaFile(
packageDecl = PackageDecl("com.legacy"),
imports = List(
Import.WildcardImport("scala.collection")
),
types = List(
Enum(
name = "Color",
cases = List(
EnumCase.SimpleCase("Red"),
EnumCase.SimpleCase("Blue")
)
)
)
)

val scala2Config = EmitterConfig(
scala3Syntax = false
)

Emits sealed trait syntax (Scala 2 compatible):

import zio.blocks.codegen.emit._
ScalaEmitter.emit(file, scala2Config)
// res9: String = """package com.legacy
//
// import scala.collection._
//
// sealed trait Color
//
// object Color {
// case object Red extends Color
// case object Blue extends Color
// }
// """

Example 4: No Trailing Commas

For projects with strict no-trailing-commas rules:

import zio.blocks.codegen.ir._
import zio.blocks.codegen.emit._

val file = ScalaFile(
packageDecl = PackageDecl("com.strict"),
types = List(
CaseClass(
"Options",
List(
Field("a", TypeRef.String),
Field("b", TypeRef.Int),
Field("c", TypeRef.Boolean)
)
)
)
)

val config = EmitterConfig(
trailingCommas = false
)

Emits without trailing comma on last field:

import zio.blocks.codegen.emit._
ScalaEmitter.emit(file, config)
// res11: String = """package com.strict
//
// case class Options(
// a: String,
// b: Int,
// c: Boolean
// )
// """

Example 5: Unsorted Imports

For projects that manage imports manually:

import zio.blocks.codegen.ir._
import zio.blocks.codegen.emit._

val file = ScalaFile(
packageDecl = PackageDecl("com.example"),
imports = List(
Import.WildcardImport("zio"),
Import.SingleImport("scala.collection", "Seq"),
Import.WildcardImport("scala")
),
types = List(
CaseClass("Data", List(
Field("items", TypeRef("Seq", List(TypeRef.String)))
))
)
)

val config = EmitterConfig(
sortImports = false // Keep imports in declaration order
)

Preserves import order:

import zio.blocks.codegen.emit._
ScalaEmitter.emit(file, config)
// res13: String = """package com.example
//
// import zio.*
// import scala.collection.Seq
// import scala.*
//
// case class Data(
// items: Seq[String],
// )
// """

Example 6: Custom Combination

Combining multiple preferences:

import zio.blocks.codegen.ir._
import zio.blocks.codegen.emit._

val file = ScalaFile(
packageDecl = PackageDecl("com.myproject"),
imports = List(
Import.WildcardImport("zio")
),
types = List(
SealedTrait(
"Response",
cases = List(
SealedTraitCase.CaseClassCase(
CaseClass("Ok", List(
Field("data", TypeRef.String),
Field("status", TypeRef.Int)
))
),
SealedTraitCase.CaseObjectCase("Error")
)
)
)
)

val config = EmitterConfig(
indentWidth = 4,
sortImports = true,
trailingCommas = false,
scala3Syntax = false
)

Emits:

import zio.blocks.codegen.emit._
ScalaEmitter.emit(file, config)
// res15: String = """package com.myproject
//
// import zio._
//
// sealed trait Response
//
// object Response {
// case class Ok(
// data: String,
// status: Int
// ) extends Response
// case object Error extends Response
// }
// """

Cross-Scala Behavior

The scala3Syntax field affects code generation:

Scala 3 Features

When targeting Scala 3, the emitter uses:

  • Enums: enum Color { case Red; case Blue }
  • Derives (case classes only): derives Show, Eq (sealed traits and enums do not emit derives)
  • Wildcard imports: import scala.collection.*
  • Rename imports: import foo.{bar as baz}
  • Opaque types: opaque type UserId = Long

Scala 2 Fallback

When targeting Scala 2, the emitter uses:

  • Sealed traits instead of enums: sealed trait Color + case object Red
  • Implicit/given syntax converts to Scala 2 compatible form
  • Wildcard imports: import scala.collection._
  • Rename imports: import foo.{bar => baz}
  • Type aliases instead of opaque types: type UserId = Long