Skip to content

Commit

Permalink
Support defining new components, and define material Container
Browse files Browse the repository at this point in the history
  • Loading branch information
nafg committed Dec 14, 2023
1 parent feebeca commit 7356a26
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 38 deletions.
31 changes: 29 additions & 2 deletions overrides.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ mui:
filterOptions:
type:
args:
- base: jsAny
- arrayOf: jsAny
- jsObject
result:
base: jsAny
arrayOf: jsAny
Breadcrumbs:
moduleTrait: FacadeModule.ArrayChildren
ButtonGroup:
Expand All @@ -73,6 +73,33 @@ mui:
props:
children:
type: vdomNode
classes:
type: jsObject
component:
type: elementType
disableGutters:
type: bool
fixed:
type: bool
maxWidth:
type:
base:
anyOf:
- string
- bool
presets:
- name: xs
code: '"xs"'
- name: sm
code: '"sm"'
- name: md
code: '"md"'
- name: lg
code: '"lg"'
- name: xl
code: '"xl"'
- name: "false"
code: 'false'
Dialog:
props:
onClose:
Expand Down
20 changes: 13 additions & 7 deletions project/ComponentInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,23 @@ case class ComponentInfo(name: String, description: String, propsMap: SortedMap[
lazy val maybeChildrenProp = propsMap.get("children")
def withProp(propInfo: PropInfo) = copy(propsMap = propsMap + (propInfo.name -> propInfo))
}
object ComponentInfo {

object ComponentInfo {
private def makePropsMap(infos: Seq[PropInfo]) = SortedMap(infos.map(p => p.name -> p)*)

def read(jsonObject: collection.Map[String, ujson.Value]) = {
val propInfos =
PropInfo.readAll(jsonObject("props").obj - "key")
.filterNot(_.description.contains("@ignore"))
def apply(name: String, description: String, propInfos: Seq[PropInfo]): ComponentInfo =
ComponentInfo(
name = name,
description = description,
propsMap = makePropsMap(propInfos)
)

def read(jsonObject: collection.Map[String, ujson.Value]) =
apply(
name = jsonObject("displayName").str,
description = jsonObject("description").str,
propsMap = makePropsMap(propInfos)
propInfos =
PropInfo.readAll(jsonObject("props").obj - "key")
.filterNot(_.description.contains("@ignore"))
)
}
}
45 changes: 31 additions & 14 deletions project/FacadeGenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -207,34 +207,51 @@ object FacadeGenerator {
overrides: Overrides,
logger: Logger
): Seq[File] = {
val scalaPackage = "io.github.nafg.scalajs.facades." + scalaSubPackage
val outputDir = base / scalaPackage.split('.').toList
val scalaPackage = "io.github.nafg.scalajs.facades." + scalaSubPackage
val outputDir = base / scalaPackage.split('.').toList
os.makeDir.all(outputDir)
val docgenOutput = runReactDocGen(base, repoDir, subDir)
val docgenOutput = runReactDocGen(base, repoDir, subDir)
if (BooleanProp.keyExists("docgen.dump").value) {
println("Result:")
println(ujson.read(docgenOutput).render(indent = 2))
println()
}
val componentInfos = ujson.read(docgenOutput).obj.values.collect {

val readComponentInfos = ujson.read(docgenOutput).obj.values.toSeq.collect {
case value if Set("props", "displayName").forall(value.obj.contains) =>
val componentInfo = ComponentInfo.read(value.obj)
overrides.getPropInfoOverrides(componentInfo).foldLeft(componentInfo) {
case (componentInfo, (propName, Overrides.PropInfoOverride(typ, required))) =>
componentInfo.withProp(
componentInfo.propsMap.get(propName) match {
case None => PropInfo(propName, typ.getOrElse(PropTypeInfo.jsAny))
case Some(propInfo) =>
propInfo.copy(
required = required.getOrElse(propInfo.required),
`type` = typ.getOrElse(propInfo.`type`)
)
componentInfo.propsMap.get(propName)
.map { existingPropInfo =>
existingPropInfo.copy(
required = required.getOrElse(existingPropInfo.required),
`type` = typ.getOrElse(existingPropInfo.`type`)
)
}
)
.orElse(typ.map(propTypeInfo => PropInfo(propName, propTypeInfo)))
.fold(componentInfo)(componentInfo.withProp)
}
}

for (componentInfo <- componentInfos.toSeq) yield processComponent(
val componentInfos =
readComponentInfos ++
(overrides.components -- readComponentInfos.map(_.name).toSet).map { case (name, overrides) =>
ComponentInfo(
name = name,
description = "",
propInfos = overrides.props.toSeq.map { case (propName, Overrides.PropInfoOverride(typ, required)) =>
PropInfo(
name = propName,
identifier = Identifier(propName),
`type` = typ.getOrElse(PropTypeInfo.jsAny),
required = required.getOrElse(false)
)
}
)
}

for (componentInfo <- componentInfos) yield processComponent(
info = componentInfo,
scalaPackage = scalaPackage,
jsPackage = jsPackage,
Expand Down
19 changes: 16 additions & 3 deletions project/FacadeGeneratorPlugin.scala
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import java.io.FileReader

import _root_.io.circe.yaml.v12.Parser
import cats.data.Validated
import cats.implicits.toShow
import sbt.*
import sbt.Keys.*
import sbt.util.StampedFormat.UnitJsonFormat
import scalajsbundler.sbtplugin.ScalaJSBundlerPlugin
import _root_.io.circe.yaml.parser


object FacadeGeneratorPlugin extends AutoPlugin {
Expand All @@ -20,8 +22,19 @@ object FacadeGeneratorPlugin extends AutoPlugin {
runYarnInstall.value
val logger = streams.value.log
val overrides =
parser.parse(new FileReader("overrides.yml")).toTry.get
.as[Map[String, Overrides]].toTry.get.apply(scalaSubPackage)
Parser.default.parse(new FileReader("overrides.yml")).toTry.get
.asAccumulating[Map[String, Overrides]] match {
case Validated.Invalid(errors) =>
errors.toList.foreach(failure => logger.error(failure.show))
sys.error(errors.toString)
case Validated.Valid(map) => map(scalaSubPackage)
}
val overridesString = pprint.apply(overrides).render
logger.info(
overridesString.linesWithSeparators
.map(s"[${scalaSubPackage}] " + _)
.mkString
)
FacadeGenerator.run(
base = os.Path((Compile / sourceManaged).value),
repoDir = reactDocGenDir.value,
Expand Down
22 changes: 10 additions & 12 deletions project/PropTypeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ object PropTypeInfo {
override def safeCode = code
override def presets: Seq[Preset] = Nil
}
private object Simple {
object Simple {
case object bool extends Simple("Boolean")
case object int extends Simple("Int")
case object double extends Simple("Double")
Expand Down Expand Up @@ -58,7 +58,7 @@ object PropTypeInfo {
vdomElement
)

case class Sequence(base: PropTypeInfo) extends Simple(s"Seq[${base.safeCode /* temp */}]", base.imports)
case class Sequence(arrayOf: PropTypeInfo) extends Simple(s"Seq[${arrayOf.code}]", arrayOf.imports)
object Sequence {
implicit lazy val codecSequence: Codec[Sequence] = deriveConfiguredCodec[Sequence]
}
Expand Down Expand Up @@ -90,8 +90,6 @@ object PropTypeInfo {
.getOrElse(React(str))
}
}

// implicit val simpleCodec: Codec[PropTypeInfo.Simple] = Codec.from(Simple.decodeSimple, Simple.encodeSimple)
}
case class Function(args: Seq[PropTypeInfo], result: PropTypeInfo) extends PropTypeInfo {
override def code =
Expand All @@ -118,7 +116,7 @@ object PropTypeInfo {
)
override def sequence: PropTypeInfo = Simple.Sequence(this)
}
case class Enum(base: Simple, override val presets: Seq[Preset]) extends PropTypeInfo {
case class WithPresets(base: PropTypeInfo, override val presets: Seq[Preset]) extends PropTypeInfo {
override def code = base.code
override def safeCode = base.safeCode
override def imports = base.imports
Expand All @@ -143,7 +141,7 @@ object PropTypeInfo {
val vdomNode: PropTypeInfo = Simple.vdomNode
val vdomElement: PropTypeInfo = Simple.vdomElement
val element: PropTypeInfo = Simple.element
def stringEnum(values: String*): PropTypeInfo = Enum(Simple.string, values.map(Preset.string))
def stringEnum(values: String*): PropTypeInfo = WithPresets(Simple.string, values.map(Preset.string))

private val stringEnumValueRE = "'(.*)'".r
private val litEnumValueRE = """(true|false|-?\d+\.\d+|-?\d+)""".r
Expand All @@ -155,7 +153,7 @@ object PropTypeInfo {
case PropType.ArrayOf(param) => apply(param).sequence
case PropType.Union(types) => Union(types.map(apply))
case PropType.Enum(base, values) =>
Enum(Simple.fromPropType(base),
WithPresets(Simple.fromPropType(base),
values.collect {
case litEnumValueRE(s) => Preset.literal(s)
case stringEnumValueRE(s) => Preset.string(s)
Expand All @@ -164,14 +162,14 @@ object PropTypeInfo {
}

private implicit val presetCodec: Codec[PropTypeInfo.Preset] = deriveConfiguredCodec
private implicit val enumCodec: Codec[PropTypeInfo.Enum] = deriveConfiguredCodec
private implicit val enumCodec: Codec[PropTypeInfo.WithPresets] = deriveConfiguredCodec
private implicit val unionCodec: Codec[PropTypeInfo.Union] = deriveConfiguredCodec
private implicit val functionCodec: Codec[PropTypeInfo.Function] = deriveConfiguredCodec
implicit val encodePropTypeInfo: Encoder[PropTypeInfo] = Encoder.instance[PropTypeInfo] {
case s: Simple => Simple.encodeSimple(s)
case e: Enum => enumCodec(e)
case u: Union => unionCodec(u)
case f: Function => functionCodec(f)
case s: Simple => Simple.encodeSimple(s)
case e: WithPresets => enumCodec(e)
case u: Union => unionCodec(u)
case f: Function => functionCodec(f)
}
implicit val decodePropTypeInfo: Decoder[PropTypeInfo] =
unionCodec
Expand Down
1 change: 1 addition & 0 deletions project/build-build.sbt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
libraryDependencies += "com.lihaoyi" %% "os-lib" % "0.9.2"
libraryDependencies += "com.lihaoyi" %% "ujson" % "3.1.3"
libraryDependencies += "com.lihaoyi" %% "pprint" % "0.8.1"
libraryDependencies += "io.github.nafg.scalac-options" %% "scalac-options" % "0.2.0"
libraryDependencies += "io.circe" %% "circe-generic-extras" % "0.14.3"
libraryDependencies += "io.circe" %% "circe-yaml-v12" % "0.15.1"

0 comments on commit 7356a26

Please sign in to comment.