@lihaoyi I quickly tried to implement the named tuple syntax for case class constructors. It was very easy to do. The original JSON definitions I posted now compile with meaningful static types. Here are some variations. So, yes, it looks like statically typed JSON is entirely doable with this.
I think I will file an amendmend to the named tuple SIP to support this use case.
Expanding on this. Here’s one of the data values again:
val b1: BuildDescription = (
declarationMap = true,
esModuleInterop = true,
baseUrl = ".",
rootDir = "typescript",
declaration = true,
outDir = pubBundledOut,
deps = [junitInterface, commonsIo],
plugins = [
( transform = "typescript-transform-paths" ),
( transform = "typescript-transform-paths",
afterDeclarations = true
)
],
aliases = ["someValue", "some-value", "a value"],
moduleResolution = "node",
module = "CommonJS",
target = "ES2020"
)
And here are the case classes defining the schema:
case class BuildDescription(
declarationMap: Boolean = false,
esModuleInterop: Boolean = true,
baseUrl: String = ".",
rootDir: String = "",
declaration: Boolean = false,
outDir: String = ".",
deps: Seq[Dep] = [junitInterface, commonsIo],
plugins: List[Plugin] = [],
aliases: IArray[String] = [],
moduleResolution: String = "",
module: String = "",
target: String = "",
other: String = ""
)
case class Plugin(
transform: String,
afterDeclarations: Boolean = false
)
The first case class contains various collections in its fields, let’s assume that’s done for efficiency considerations. But the actual value just uses [...]
everywhere. This is as it should be! The person defining the schema will also write the code to process it and therefore will take care choosing the right collection types. The person defininig the data value should not care about this at all – all that matters is that some sequence of values is defined. So I would argue that in this case it’s actually a good thing that the type is not manifest in the value.