Skip to content

Commit

Permalink
make the generator take named args. Tidy Makefile (#5)
Browse files Browse the repository at this point in the history
* make the generator take named args. Tidy Makefile

* address comments
  • Loading branch information
hughsimpson authored Mar 16, 2021
1 parent a7d1778 commit 879d376
Show file tree
Hide file tree
Showing 211 changed files with 105 additions and 181 deletions.
27 changes: 13 additions & 14 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ SBT=sbt -DARTIFACTORY_USER="${ARTIFACTORY_USER}" -DARTIFACTORY_PWD="${ARTIFACTOR
SBT_G=sbt -DARTIFACTORY_USER="${ARTIFACTORY_USER}" -DARTIFACTORY_PWD="${ARTIFACTORY_PWD}" -Dversion="${G_VERSION}"
# Why sed and not grep, you ask? Because grep on mac takes the -E flag, but takes -P on *nix
BENCH_NUMBER=$(shell echo ${CIRCLE_JOB} | sed 's/benchmark//')
CORE_FILES=$(shell for i in address Age annotation attachment backboneElement codeableConcept coding contactDetail contactPoint Contributor Count DataRequirement Distance dosage duration element Expression extension humanName identifier meta money ParameterDefinition period quantity range ratio reference RelatedArtifact Resource SampledData Signature timing TriggerDefinition UsageContext; do echo "./generator/src/main/resources/resourceModel/$${i}.json"; done | xargs | sed 's/ /,/g')
HL7_FILES=$(shell ls generator/src/main/resources/resourceModel/*.json | grep -vE '/(address|Age|annotation|attachment|backboneElement|codeableConcept|coding|contactDetail|contactPoint|Contributor|Count|DataRequirement|Distance|dosage|duration|element|Expression|extension|humanName|identifier|meta|money|ParameterDefinition|period|quantity|range|ratio|reference|RelatedArtifact|Resource|SampledData|Signature|timing|TriggerDefinition|UsageContext).json' | xargs | sed -E 's:(^| ):\1./:g' | sed 's/ /,/g')
CORE_MODULES=core hl7
US_MODULES=usbase uscore
ALL_MODULES=$(CORE_MODULES) $(US_MODULES)
Expand Down Expand Up @@ -76,23 +74,24 @@ publish-all-local:
$(SBT) common/publishLocal common/publishM2 macros/publishLocal macros/publishM2 $(foreach i,$(ALL_MODULES),$i/publishLocal $i/publishM2 $iJava/publishLocal $iJava/publishM2)

build-hl7-class-models:
$(SBT) 'project generator' 'run "generate" "$(CORE_FILES)" "$(HL7_FILES)" \
"./.ignore/dummy=" \
"_java" \
"./generated_typescript" \
"" \
true'
$(SBT) 'project generator' 'run "generate" \
--javaPackageSuffix=_java \
--typescriptDir="./generated_typescript"'
$(SBT) $(foreach i,$(CORE_MODULES),$i/scalafmtAll)
$(SBT) $(foreach i,$(CORE_MODULES),$iJava/javafmt)
./apply_patches.sh

build-all-class-models-dry:
$(SBT) 'project generator' 'run "generate" \
--models="usbase=fhir/spec/hl7.fhir.r4.examples/4.0.1/package/StructureDefinition-*;uscore=fhir/spec/hl7.fhir.us.core/3.1.0/package/StructureDefinition-*" \
--javaPackageSuffix=_java \
--moduleDependencies="usbase<uscore" \
--dryRun'
build-all-class-models:
$(SBT) 'project generator' 'run "generate" "$(CORE_FILES)" "$(HL7_FILES)" \
"usbase=fhir/spec/hl7.fhir.r4.examples/4.0.1/package/StructureDefinition-*;uscore=fhir/spec/hl7.fhir.us.core/3.1.0/package/StructureDefinition-*" \
"_java" \
"./.ignore/typescript" \
"usbase<uscore" \
true'
$(SBT) 'project generator' 'run "generate" \
--models="usbase=fhir/spec/hl7.fhir.r4.examples/4.0.1/package/StructureDefinition-*;uscore=fhir/spec/hl7.fhir.us.core/3.1.0/package/StructureDefinition-*" \
--javaPackageSuffix=_java \
--moduleDependencies="usbase<uscore"'
$(SBT) $(foreach i,$(ALL_MODULES),$i/scalafmtAll)
$(SBT) $(foreach i,$(ALL_MODULES),$iJava/javafmt)
./apply_patches.sh
Expand Down
22 changes: 3 additions & 19 deletions docs/documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,26 +244,10 @@ If you're using intelliJ the highlighting is misleading here, since it will info
## Generation

Lit can be used to generate new class models from your existing fhir profiles. Simply specify the module name and the location of the profiles in the args for the generator, when running it. Module dependencies can also be specified, in case your profiles depend on ones defined outside of the core and hl7 modules. e.g.
// TODO: this really hammers home the issues with how the generator is currently called. At the very least we need to have a saner directory structure the core files, named args, and default arguments.
```
# Should just be generator/src/main/resources/resourceModel/core/*.json
CORE_FILES=$(for i in address Age annotation attachment backboneElement codeableConcept coding contactDetail contactPoint Contributor Count DataRequirement Distance dosage duration element Expression extension humanName identifier meta money ParameterDefinition period quantity range ratio reference RelatedArtifact Resource SampledData Signature timing TriggerDefinition UsageContext; do echo "./generator/src/main/resources/resourceModel/$${i}.json"; done | xargs | sed 's/ /,/g')
# Should just be generator/src/main/resources/resourceModel/hl7/*.json
HL7_FILES=$(ls generator/src/main/resources/resourceModel/*.json | grep -vE '/(address|Age|annotation|attachment|backboneElement|codeableConcept|coding|contactDetail|contactPoint|Contributor|Count|DataRequirement|Distance|dosage|duration|element|Expression|extension|humanName|identifier|meta|money|ParameterDefinition|period|quantity|range|ratio|reference|RelatedArtifact|Resource|SampledData|Signature|timing|TriggerDefinition|UsageContext).json' | xargs | sed -E 's:(^| ):\1./:g' | sed 's/ /,/g')
'project generator' 'run \
# might be redundant, but might not. Not too bad. Think I'll keep it
"generate" \
# should be --modelOverrides="core=$(CORE_FILES);hl7=$(HL7_FILES)" and also be the default, and thus be omittable.
"$(CORE_FILES)" "$(HL7_FILES)" \
# should be --models="..."
"usbase=fhir/spec/hl7.fhir.r4.examples/4.0.1/package/StructureDefinition-*;uscore=fhir/spec/hl7.fhir.us.core/3.1.0/package/StructureDefinition-*" \
# should be --javaPackageSuffix=_java, and when unspecified we shouldn't generate java code
"_java" \
# should be --typescriptDir=...; when unspecified, we shouldn't generate typescript code -- this .ignore hack shouldn't be necessary
"./.ignore/typescript" \
# should be --modelDependencies="usbase<uscore"; should default to empty string
"usbase<uscore" \
# should be inverted as `--dryRun=false`, default to false, and be specifiable as just `--dryRun`
true'
--models="usbase=fhir/spec/hl7.fhir.r4.examples/4.0.1/package/StructureDefinition-*;uscore=fhir/spec/hl7.fhir.us.core/3.1.0/package/StructureDefinition-*" \
--javaPackageSuffix=_java \
--moduleDependencies="usbase<uscore"
```
80 changes: 26 additions & 54 deletions generator/src/main/scala/com/babylonhealth/lit/Autogenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import io.circe.parser.decode
import com.babylonhealth.lit.ElementTreee._
import com.babylonhealth.lit.core.serdes.objectDecoder
import com.babylonhealth.lit.hl7.BINDING_STRENGTH
import com.babylonhealth.lit.hl7.model.{ElementDefinition, StructureDefinition}
import com.babylonhealth.lit.languages.{JavaGenerator, ScalaCodegen, TypescriptCodegen}
import com.babylonhealth.lit.hl7.model.{ ElementDefinition, StructureDefinition }
import com.babylonhealth.lit.languages.{ JavaGenerator, ScalaCodegen, TypescriptCodegen }

trait FHIRFetcher {}

Expand Down Expand Up @@ -126,15 +126,11 @@ object Autogenerator extends Commonish with Logging with FileUtils with JavaGene
}

def getStrings(
overridingModels: Seq[SourceFile],
resourceModels: Seq[SourceFile],
javaDirSuffix: String,
typescriptOutputLocation: Option[String],
moduleDependencies: ModuleDependencies,
args: MainArgs,
extensions: Map[String, Seq[ClassGenInfo]],
fetchValueSet: (String, BINDING_STRENGTH) => Option[CodeValueSet]): AllGeneratedFiles = {

val sortedLocations = sortLocationsByBase(overridingModels, resourceModels)
val sortedLocations = sortLocationsByBase(args.modelOverrides, args.models)
println("Sorted models")
val modules = sortedLocations.foldLeft(Seq.empty[String]) { (acc, n) =>
val currModule = acc.lastOption contains n.targetModule
Expand Down Expand Up @@ -166,7 +162,7 @@ object Autogenerator extends Commonish with Logging with FileUtils with JavaGene
val valueSetDecls: ValueSetDecls = ValueSetDecls(topLevelClasses.classes.flatMap {
_._2.flatMap { case (pkg, x) => x.valueSets.map { case (k, v) => (pkg, k, v) } }
}.toSeq).stripVersions
val valueSetEarliestDeclarations: ValueSetDecls = valueSetDecls.earliestDeclarations(moduleDependencies)
val valueSetEarliestDeclarations: ValueSetDecls = valueSetDecls.earliestDeclarations(args.moduleDependencies)

val scalaClassGenInfo: Seq[ClassGenInfo] = {

Expand All @@ -187,9 +183,9 @@ object Autogenerator extends Commonish with Logging with FileUtils with JavaGene
element,
backboneElement,
topLevelClasses,
moduleDependencies,
args.moduleDependencies,
pkgAndValueSet,
ElementTreee.getUnionTypes.values.map(moduleDependencies leastCommon _._1.toSet).toSet
ElementTreee.getUnionTypes.values.map(args.moduleDependencies leastCommon _._1.toSet).toSet
))
catch {
case NonFatal(ex) =>
Expand All @@ -200,24 +196,18 @@ object Autogenerator extends Commonish with Logging with FileUtils with JavaGene
}.toSeq
}
allFHIRClasses ++ valueSetFiles ++ extensions("scala") ++
ScalaCodegen.genPackageObjectFiles(moduleDependencies, ElementTreee.getUnionTypes)
ScalaCodegen.genPackageObjectFiles(args.moduleDependencies, ElementTreee.getUnionTypes)
}

val javaClassGenInfo: JavaClassGenInfo = {
val javaClassGenInfo: Option[JavaClassGenInfo] = args.javaPackageSuffix.map { j =>
val bar: Seq[ClassGenInfo] = valueSetEarliestDeclarations.byPackage.flatMap { case (pkg, ps) =>
generateCodeAliases(pkg, javaDirSuffix, ps.toMap)
generateCodeAliases(pkg, j, ps.toMap)
}.toSeq
JavaClassGenInfo(
topLevelClasses.classes.toSeq.flatMap { case (o, m) =>
m.flatMap { case (p, k) =>
val javaPackageStr = (s"com.babylonhealth.lit.$p$javaDirSuffix")
try genTheJavaForClass(
k,
javaPackageStr,
p,
valueSetEarliestDeclarations,
moduleDependencies,
javaDirSuffix)
val javaPackageStr = (s"com.babylonhealth.lit.$p$j")
try genTheJavaForClass(k, javaPackageStr, p, valueSetEarliestDeclarations, args.moduleDependencies, j)
catch {
case NonFatal(ex) =>
log.error(s"Unable to gen Java file for $p.$o", ex)
Expand All @@ -229,7 +219,7 @@ object Autogenerator extends Commonish with Logging with FileUtils with JavaGene
)
}

val typescriptClassGenInfo: Option[Seq[ClassGenInfo]] = typescriptOutputLocation.map { o =>
val typescriptClassGenInfo: Option[Seq[ClassGenInfo]] = args.typescriptDir.map { o =>
topLevelClasses.classes.toSeq.flatMap { case (o, m) =>
m.flatMap { case (p, k) =>
try TypescriptCodegen.genTypescriptForClass(k)
Expand All @@ -245,32 +235,18 @@ object Autogenerator extends Commonish with Logging with FileUtils with JavaGene
AllGeneratedFiles(scalaClassGenInfo, javaClassGenInfo, typescriptClassGenInfo)
}
def generateAndWriteOutput(
overridingModels: Seq[SourceFile],
resourceModels: Seq[SourceFile],
javaDirSuffix: String,
typescriptOutputLocation: Option[String],
moduleDependencies: ModuleDependencies,
writeCode: Boolean,
args: MainArgs,
extensions: Map[String, Seq[ClassGenInfo]],
fetchValueSet: (String, BINDING_STRENGTH) => Option[CodeValueSet]): Unit = {
println("Trying to generate files")
val AllGeneratedFiles(scalaClassGenInfo, javaClassGenInfo, typescriptClassGenInfo) =
getStrings(
overridingModels,
resourceModels,
javaDirSuffix,
typescriptOutputLocation,
moduleDependencies,
extensions,
fetchValueSet)
def javaOutputLocation(pkg: String): String =
s"./$pkg$javaDirSuffix/src/main/java/com/babylonhealth/lit/$pkg$javaDirSuffix"
def javaOutputLocations(pkg: String): Seq[String] = {
val dir = javaOutputLocation(pkg)
Seq(s"$dir/builders", s"$dir/codes")
}
getStrings(args, extensions, fetchValueSet)
def javaOutputLocation(pkg: String): Option[String] =
args.javaPackageSuffix.map(j => s"./$pkg$j/src/main/java/com/babylonhealth/lit/$pkg$j")
def javaOutputLocations(pkg: String): Seq[String] =
javaOutputLocation(pkg).toSeq.flatMap(dir => Seq(s"$dir/builders", s"$dir/codes"))
println("Successfully generated files")
if (writeCode) { // create the directories fresh
if (!args.dryRun) { // create the directories fresh
scalaClassGenInfo
.map(_.pkg)
.distinct
Expand All @@ -281,19 +257,15 @@ object Autogenerator extends Commonish with Logging with FileUtils with JavaGene
scalaClassGenInfo foreach { case ClassGenInfo(fc, fileName, pkg) =>
write(s"$pkg/src/main/scala/com/babylonhealth/lit/$pkg/model/$fileName.scala", fc)
}
javaClassGenInfo.builders foreach { case ClassGenInfo(fc, fileName, pkg) =>
if (pkg == null) println(s"NULL WAT??? 111 ${fileName} :: ${pkg}")
else
write(s"${javaOutputLocation(pkg)}/builders/$fileName.java", fc)
javaClassGenInfo.toSeq.flatMap(_.builders) foreach { case ClassGenInfo(fc, fileName, pkg) =>
write(s"${javaOutputLocation(pkg).get}/builders/$fileName.java", fc)
}
javaClassGenInfo.codes foreach { case ClassGenInfo(fc, fileName, pkg) =>
if (pkg == null) println(s"NULL WAT 222 ${fileName} :: ${pkg}??? ")
else
write(s"${javaOutputLocation(pkg)}/codes/$fileName.java", fc)
javaClassGenInfo.toSeq.flatMap(_.codes) foreach { case ClassGenInfo(fc, fileName, pkg) =>
write(s"${javaOutputLocation(pkg).get}/codes/$fileName.java", fc)
}
if (typescriptClassGenInfo.nonEmpty) new File(typescriptOutputLocation.get).mkdirs()
if (typescriptClassGenInfo.nonEmpty) new File(args.typescriptDir.get).mkdirs()
typescriptClassGenInfo.foreach(c =>
write(s"${typescriptOutputLocation.get}/DomainModel.ts", c.map(_.fileContents).mkString("\n\n")))
write(s"${args.typescriptDir.get}/DomainModel.ts", c.map(_.fileContents).mkString("\n\n")))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import scala.util.Try
import io.circe.Json
import io.circe.parser.parse

object FileUtils extends FileUtils
trait FileUtils extends common.FileUtils {
def getFileAsJson(file: File): Json =
if (!file.exists()) {
Expand Down
Loading

0 comments on commit 879d376

Please sign in to comment.