diff --git a/.bsp/sbt.json b/.bsp/sbt.json index dcffaa0..d541e04 100644 --- a/.bsp/sbt.json +++ b/.bsp/sbt.json @@ -1 +1 @@ -{"name":"sbt","version":"1.8.0","bspVersion":"2.1.0-M1","languages":["scala"],"argv":["/usr/lib/jvm/java-17-openjdk-amd64/bin/java","-Xms100m","-Xmx100m","-classpath","/home/labra/.cache/sbt/boot/sbt-launch/1.9.8/sbt-launch-1.9.8.jar","-Dsbt.script=/usr/bin/sbt","xsbt.boot.Boot","-bsp"]} \ No newline at end of file +{"name":"sbt","version":"1.10.1","bspVersion":"2.1.0-M1","languages":["scala"],"argv":["/usr/lib/jvm/java-17-openjdk-amd64/bin/java","-Xms100m","-Xmx100m","-classpath","/home/labra/.cache/sbt/boot/sbt-launch/1.10.1/sbt-launch-1.10.1.jar","-Dsbt.script=/usr/bin/sbt","xsbt.boot.Boot","-bsp"]} \ No newline at end of file diff --git a/.scalafmt.conf b/.scalafmt.conf new file mode 100644 index 0000000..ee7753a --- /dev/null +++ b/.scalafmt.conf @@ -0,0 +1,2 @@ +version = "3.7.15" +runner.dialect = scala213 \ No newline at end of file diff --git a/build.sbt b/build.sbt index 9810298..ff08104 100644 --- a/build.sbt +++ b/build.sbt @@ -1,29 +1,28 @@ -lazy val scala212 = "2.12.17" +lazy val scala212 = "2.12.19" lazy val scala213 = "2.13.10" -lazy val scala3 = "3.2.1" +lazy val scala3 = "3.2.1" lazy val supportedScalaVersions = List( scala3, - scala213, + scala213, scala212 ) val Java11 = JavaSpec.temurin("11") // "adopt@1.11" -lazy val srdfVersion = "0.1.125" -lazy val shaclexVersion = "0.2.4" -lazy val shaclsVersion = "0.1.83" -lazy val shexsVersion = "0.2.33" +lazy val srdfVersion = "0.1.125" +lazy val shaclexVersion = "0.2.4" +lazy val shaclsVersion = "0.1.83" +lazy val shexsVersion = "0.2.33" // Dependency versions -lazy val munitVersion = "0.7.29" -lazy val munitEffectVersion = "1.0.7" - -lazy val plantumlVersion = "1.2017.12" -lazy val logbackVersion = "1.2.11" -lazy val loggingVersion = "3.9.4" -lazy val scallopVersion = "4.1.0" +lazy val munitVersion = "0.7.29" +lazy val munitEffectVersion = "1.0.7" +lazy val plantumlVersion = "1.2017.12" +lazy val logbackVersion = "1.2.11" +lazy val loggingVersion = "3.9.4" +lazy val scallopVersion = "4.1.0" // Compiler plugin dependency versions // lazy val simulacrumVersion = "0.19.0" @@ -32,25 +31,26 @@ lazy val scallopVersion = "4.1.0" // Dependency modules // lazy val logbackClassic = "ch.qos.logback" % "logback-classic" % logbackVersion -lazy val munit = "org.scalameta" %% "munit" % munitVersion -lazy val munitEffect = "org.typelevel" %% "munit-cats-effect-3" % munitEffectVersion - -lazy val plantuml = "net.sourceforge.plantuml" % "plantuml" % plantumlVersion -lazy val scalaLogging = "com.typesafe.scala-logging" %% "scala-logging" % loggingVersion -lazy val scallop = "org.rogach" %% "scallop" % scallopVersion +lazy val munit = "org.scalameta" %% "munit" % munitVersion +lazy val munitEffect = + "org.typelevel" %% "munit-cats-effect-3" % munitEffectVersion + +lazy val plantuml = "net.sourceforge.plantuml" % "plantuml" % plantumlVersion +lazy val scalaLogging = + "com.typesafe.scala-logging" %% "scala-logging" % loggingVersion +lazy val scallop = "org.rogach" %% "scallop" % scallopVersion // lazy val scalactic = "org.scalactic" %% "scalactic" % scalacticVersion // lazy val scalaTest = "org.scalatest" %% "scalatest" % scalaTestVersion -lazy val shex = "es.weso" %% "shex" % shexsVersion -lazy val shacl = "es.weso" %% "shacl" % shaclsVersion -lazy val schema = "es.weso" %% "schema" % shaclexVersion -lazy val schemaInfer = "es.weso" %% "schemainfer" % shaclexVersion -lazy val sgraph = "es.weso" %% "sgraph" % shaclexVersion -lazy val srdfJena = "es.weso" %% "srdfjena" % srdfVersion -lazy val utilsTest = "es.weso" %% "utilstest" % shaclexVersion +lazy val shex = "es.weso" %% "shex" % shexsVersion +lazy val shacl = "es.weso" %% "shacl" % shaclsVersion +lazy val schema = "es.weso" %% "schema" % shaclexVersion +lazy val schemaInfer = "es.weso" %% "schemainfer" % shaclexVersion +lazy val sgraph = "es.weso" %% "sgraph" % shaclexVersion +lazy val srdfJena = "es.weso" %% "srdfjena" % srdfVersion +lazy val utilsTest = "es.weso" %% "utilstest" % shaclexVersion lazy val MUnitFramework = new TestFramework("munit.Framework") - // Compiler plugin modules // lazy val simulacrum = "com.github.mpilquist" %% "simulacrum" % simulacrumVersion @@ -58,23 +58,31 @@ ThisBuild / githubWorkflowJavaVersions := Seq(Java11) lazy val umlShaclex = project .in(file(".")) - .enablePlugins(ScalaUnidocPlugin, - SiteScaladocPlugin, - AsciidoctorPlugin, - SbtNativePackager, - WindowsPlugin, - JavaAppPackaging - ) + .enablePlugins( + ScalaUnidocPlugin, + SiteScaladocPlugin, + AsciidoctorPlugin, + SbtNativePackager, + WindowsPlugin, + JavaAppPackaging + ) // .settings( // buildInfoKeys := BuildInfoKey.ofN(name, version, scalaVersion, sbtVersion), // buildInfoPackage := "es.weso.shaclex.buildinfo" // ) .settings(commonSettings, publishSettings) .settings( - unidocProjectFilter in (ScalaUnidoc, unidoc) := inAnyProject -- inProjects(noDocProjects: _*), + unidocProjectFilter in (ScalaUnidoc, unidoc) := inAnyProject -- inProjects( + noDocProjects: _* + ), siteSubdirName in ScalaUnidoc := "scaladoc/latest", - addMappingsToSiteDir(mappings in (ScalaUnidoc, packageDoc), siteSubdirName in ScalaUnidoc), - unidocProjectFilter in (ScalaUnidoc, unidoc) := inAnyProject -- inProjects(noDocProjects: _*), + addMappingsToSiteDir( + mappings in (ScalaUnidoc, packageDoc), + siteSubdirName in ScalaUnidoc + ), + unidocProjectFilter in (ScalaUnidoc, unidoc) := inAnyProject -- inProjects( + noDocProjects: _* + ), mappings in makeSite ++= Seq( file("src/assets/favicon.ico") -> "favicon.ico" ), @@ -91,9 +99,9 @@ lazy val umlShaclex = project srdfJena ), testFrameworks += MUnitFramework, - cancelable in Global := true, - fork := true, - crossScalaVersions := supportedScalaVersions, + cancelable in Global := true, + fork := true, + crossScalaVersions := supportedScalaVersions // crossScalaVersions := Nil, // publish / skip := true ) @@ -156,17 +164,23 @@ lazy val commonSettings = compilationSettings ++ sharedDependencies ++ Seq( lazy val publishSettings = Seq( sonatypeProfileName := ("es.weso"), - homepage := Some(url("https://github.com/labra/umlShaclex")), - licenses := Seq("MIT" -> url("http://opensource.org/licenses/MIT")), - scmInfo := Some(ScmInfo(url("https://github.com/labra/umlShaclex"), "scm:git:git@github.com:labra/umlShaclex.git")), + homepage := Some(url("https://github.com/labra/umlShaclex")), + licenses := Seq("MIT" -> url("http://opensource.org/licenses/MIT")), + scmInfo := Some( + ScmInfo( + url("https://github.com/labra/umlShaclex"), + "scm:git:git@github.com:labra/umlShaclex.git" + ) + ), autoAPIMappings := true, - apiURL := Some(url("http://labra.github.io/umlShaclex/latest/api/")), + apiURL := Some(url("http://labra.github.io/umlShaclex/latest/api/")), developers := List( Developer( - id="labra", - name="Jose Emilio Labra Gayo", - email="jelabra@gmail.com", - url=url("https://weso.labra.es") - )), - publishMavenStyle := true, + id = "labra", + name = "Jose Emilio Labra Gayo", + email = "jelabra@gmail.com", + url = url("https://weso.labra.es") + ) + ), + publishMavenStyle := true ) diff --git a/project/build.properties b/project/build.properties index 8b9a0b0..ee4c672 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.8.0 +sbt.version=1.10.1 diff --git a/project/metals.sbt b/project/metals.sbt index aaf3382..ac57eb4 100644 --- a/project/metals.sbt +++ b/project/metals.sbt @@ -3,6 +3,6 @@ // This file enables sbt-bloop to create bloop config files. -addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.5.17") +addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.5.18") // format: on diff --git a/project/plugins.sbt b/project/plugins.sbt index f339c32..083c803 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,11 +1,15 @@ -addSbtPlugin("com.codecommit" % "sbt-github-actions" % "0.14.2") -addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.2.0") -addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.11.0") -addSbtPlugin("com.github.sbt" % "sbt-unidoc" % "0.5.0") -addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.10") -addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "1.0.2") -addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "1.4.1") -addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.9.9") -addSbtPlugin("org.lyranthe.sbt" % "partial-unification" % "1.1.2") -addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.0") -addCompilerPlugin("com.olegpy" %% "better-monadic-for" % "0.3.1") +addSbtPlugin("com.codecommit" % "sbt-github-actions" % "0.14.2") +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.2.0") +addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.11.0") +addSbtPlugin("com.github.sbt" % "sbt-unidoc" % "0.5.0") +addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.10") +addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "1.0.2") +addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "1.4.1") +addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.10.0") +addSbtPlugin("org.lyranthe.sbt" % "partial-unification" % "1.1.2") +addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.0") +addCompilerPlugin("com.olegpy" %% "better-monadic-for" % "0.3.1") + +ThisBuild / libraryDependencySchemes ++= Seq( + "org.scala-lang.modules" %% "scala-xml" % VersionScheme.Always +) diff --git a/project/project/metals.sbt b/project/project/metals.sbt index aaf3382..ac57eb4 100644 --- a/project/project/metals.sbt +++ b/project/project/metals.sbt @@ -3,6 +3,6 @@ // This file enables sbt-bloop to create bloop config files. -addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.5.17") +addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.5.18") // format: on diff --git a/project/project/project/metals.sbt b/project/project/project/metals.sbt index aaf3382..ac57eb4 100644 --- a/project/project/project/metals.sbt +++ b/project/project/project/metals.sbt @@ -3,6 +3,6 @@ // This file enables sbt-bloop to create bloop config files. -addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.5.17") +addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.5.18") // format: on diff --git a/src/main/scala/es/weso/uml/ShEx2UML.scala b/src/main/scala/es/weso/uml/ShEx2UML.scala index 8259e05..9dafc97 100644 --- a/src/main/scala/es/weso/uml/ShEx2UML.scala +++ b/src/main/scala/es/weso/uml/ShEx2UML.scala @@ -10,11 +10,11 @@ import es.weso.rdf.PREFIXES._ import es.weso.shex._ import es.weso.uml.UMLDiagram._ import es.weso.uml.{ - Optional => UMLOptional, - Star => UMLStar, - Plus => UMLPlus, - IntMax => UMLIntMax, - _ + Optional => UMLOptional, + Star => UMLStar, + Plus => UMLPlus, + IntMax => UMLIntMax, + _ } import es.weso.shex.implicits.showShEx._ import es.weso.rdf.operations.Comparisons._ @@ -22,21 +22,20 @@ import RDF2UML._ object ShEx2UML { - def schema2Uml(schema: Schema): Either[String,(UML,List[String])] = { - val (warnings, (state,maybe)) = - cnvSchema(schema).value.run(StateValue(UML.empty,0)).run + def schema2Uml(schema: Schema): Either[String, (UML, List[String])] = { + val (warnings, (state, maybe)) = + cnvSchema(schema).value.run(StateValue(UML.empty, 0)).run maybe.map(_ => ((state.uml, warnings))) } - type Id = Int case class StateValue(uml: UML, currentId: Id) - type Logged[A] = Writer[List[String],A] - type S[A] = StateT[Logged,StateValue,A] - type Converter[A] = EitherT[S,String,A] + type Logged[A] = Writer[List[String], A] + type S[A] = StateT[Logged, StateValue, A] + type Converter[A] = EitherT[S, String, A] - private def ok[A](x:A): Converter[A] = + private def ok[A](x: A): Converter[A] = EitherT.pure[S, String](x) private def err[A](s: String): Converter[A] = @@ -67,19 +66,23 @@ object ShEx2UML { EitherT.liftF(s) } - private def cnvList[A,B](vs: List[A], cnv: A => Converter[B]): Converter[List[B]] = - vs.map(cnv(_)).sequence[Converter,B] + private def cnvList[A, B]( + vs: List[A], + cnv: A => Converter[B] + ): Converter[List[B]] = + vs.map(cnv(_)).sequence[Converter, B] private def newLabel(maybeLbl: Option[ShapeLabel]): Converter[NodeId] = maybeLbl match { case Some(lbl) => mkLabel(lbl) - case None => for { - uml <- getUML - newId <- generateId - (uml1,id) = uml.newLabel(BNodeLabel(BNode("L" + newId))) - _ <- setUML(uml1) - } yield id + case None => + for { + uml <- getUML + newId <- generateId + (uml1, id) = uml.newLabel(BNodeLabel(BNode("L" + newId))) + _ <- setUML(uml1) + } yield id } private def mkLabel(lbl: ShapeLabel): Converter[NodeId] = for { @@ -89,16 +92,16 @@ object ShEx2UML { } yield id private def newLabels(lbls: List[ShapeLabel]): Converter[List[NodeId]] = - lbls.map(mkLabel(_)).sequence[Converter,NodeId] + lbls.map(mkLabel(_)).sequence[Converter, NodeId] private def cnvSchema(schema: Schema): Converter[Unit] = { schema.shapes match { case None => err(s"No shapes in schema") case Some(shapes) => { def cmb(x: Unit, s: ShapeExpr): Converter[Unit] = for { - id <- newLabel(s.id) + id <- newLabel(shapeExprId(s)) cls <- { - cnvShapeExpr(id, s, schema.prefixMap) + cnvShapeExpr(id, s, shapeExprId(s), schema.prefixMap) } _ <- updateUML(_.addClass(cls)) } yield (()) @@ -107,276 +110,419 @@ object ShEx2UML { } } - private def cnvShapeExpr(id: Id, se: ShapeExpr, pm: PrefixMap): Converter[UMLClass] = se match { - case _: ShapeOr => { - log(s"Not implemented ShapeOr $se", UMLClass(id,"OR not implemented yet", None, List(), List())) + private def shapeExprId(se: ShapeExpr): Option[ShapeLabel] = { + se match { + case sd: ShapeDecl => { + println(s"Obtaining id from shape decl: ${sd.lbl}") + Some(sd.lbl) + } + case _ => se.id } - case sa: ShapeAnd => for { - entries <- cnvListShapeExprEntries(sa.shapeExprs, id, pm) - } yield { - val (label,href) = mkLabelHref(se.id,pm) - UMLClass(id, label, href, entries, List()) + } + + private def cnvShapeExpr( + id: Id, + se: ShapeExpr, + label: Option[ShapeLabel], + pm: PrefixMap + ): Converter[UMLClass] = se match { + case _: ShapeOr => { + log( + s"Not implemented ShapeOr $se", + UMLClass(id, "OR not implemented yet", None, List(), List()) + ) } - case sn: ShapeNot => - log(s"Not implemented ShapeNot $sn", UMLClass(id,"NOT not implemented yet", None, List(), List())) - case sd: ShapeDecl => - log(s"Not implemented declarations of abstract shapes yet", UMLClass(id,"Not implemented ShapeDecl",None, List(), List())) + case sa: ShapeAnd => + for { + entries <- cnvListShapeExprEntries(sa.shapeExprs, id, label, pm) + } yield { + val (lbl, href) = mkLabelHref(label, pm) + UMLClass(id, lbl, href, entries, List()) + } + case sn: ShapeNot => + log( + s"Not implemented ShapeNot $sn", + UMLClass(id, "NOT not implemented yet", None, List(), List()) + ) + case sd: ShapeDecl => + // log(s"Not implemented declarations of abstract shapes yet", UMLClass(id,"Not implemented ShapeDecl",None, List(), List())) + cnvShapeExpr(id, sd.shapeExpr, label, pm) case s: Shape => { for { - entries <- cnvShape(s,id,pm) + entries <- cnvShape(s, id, pm) _extends <- newLabels(s._extends.getOrElse(List())) } yield { - val (label,href) = mkLabel(se.id, pm) - UMLClass(id,label,href,entries, _extends) + val (lbl, href) = mkLabel(label, pm) + UMLClass(id, lbl, href, entries, _extends) } } - case s: NodeConstraint => for { - entries <- cnvNodeConstraint(s,pm) - } yield { - val (label,href) = mkLabel(s.id, pm) - UMLClass(id, label, href, entries, List()) - } - case s: ShapeExternal => ok(UMLClass(id,"External",None,List(),List())) - case sr: ShapeRef => for { - rid <- newLabel(Some(sr.reference)) - _ <- updateUML(_.addLink(Inheritance(id,rid))) - } yield { - val (labelShape,hrefShape) = mkLabel(se.id, pm) - UMLClass(id,labelShape,hrefShape,List(),List()) - } - + case s: NodeConstraint => + for { + entries <- cnvNodeConstraint(s, pm) + } yield { + val (lbl, href) = mkLabel(label, pm) + UMLClass(id, lbl, href, entries, List()) + } + case s: ShapeExternal => ok(UMLClass(id, "External", None, List(), List())) + case sr: ShapeRef => + for { + rid <- newLabel(Some(sr.reference)) + _ <- updateUML(_.addLink(Inheritance(id, rid))) + } yield { + val (labelShape, hrefShape) = mkLabel(label, pm) + UMLClass(id, labelShape, hrefShape, List(), List()) + } } - private def mkLabel(maybeLabel: Option[ShapeLabel], pm: PrefixMap):(String,Option[String]) = + private def mkLabel( + maybeLabel: Option[ShapeLabel], + pm: PrefixMap + ): (String, Option[String]) = maybeLabel match { case None => ("?", None) - case Some(lbl) => lbl match { - case Start => ("Start", None) - case i: IRILabel => (iri2Label(i.iri,pm), Some(i.iri.str)) - case b: BNodeLabel => (b.bnode.id, None) - } + case Some(lbl) => + lbl match { + case Start => ("Start", None) + case i: IRILabel => (iri2Label(i.iri, pm), Some(i.iri.str)) + case b: BNodeLabel => (b.bnode.id, None) + } } - private def cnvListShapeExprEntries(se: List[ShapeExpr], - id: NodeId, - pm: PrefixMap - ): Converter[List[List[UMLEntry]]] = { - def cmb(xss: List[List[UMLEntry]], se: ShapeExpr): Converter[List[List[UMLEntry]]] = for { - fs <- cnvShapeExprEntries(se,id,pm) + private def cnvListShapeExprEntries( + se: List[ShapeExpr], + id: NodeId, + label: Option[ShapeLabel], + pm: PrefixMap + ): Converter[List[List[UMLEntry]]] = { + def cmb( + xss: List[List[UMLEntry]], + se: ShapeExpr + ): Converter[List[List[UMLEntry]]] = for { + fs <- cnvShapeExprEntries(se, id, label, pm) } yield fs ++ xss val zero: List[List[UMLEntry]] = List(List()) se.reverse.foldM(zero)(cmb) } - - private def cnvShapeExprEntries(se: ShapeExpr, id: NodeId, pm: PrefixMap): Converter[List[List[UMLEntry]]] = se match { - case sa: ShapeAnd => for { - ess <- cnvListShapeExprEntries(sa.shapeExprs,id,pm) - } yield ess - case so: ShapeOr => log(s"Nested OR not supported yet $so", List(List())) + private def cnvShapeExprEntries( + se: ShapeExpr, + id: NodeId, + label: Option[ShapeLabel], + pm: PrefixMap + ): Converter[List[List[UMLEntry]]] = se match { + case sa: ShapeAnd => + for { + ess <- cnvListShapeExprEntries(sa.shapeExprs, id, label, pm) + } yield ess + case so: ShapeOr => log(s"Nested OR not supported yet $so", List(List())) case sn: ShapeNot => log(s"Nested NOT not supported yet $sn", List(List())) - case s: Shape => cnvShape(s,id,pm) - case nk: NodeConstraint => for { - vcs <- cnvNodeConstraint(nk,pm) - } yield vcs + case s: Shape => cnvShape(s, id, pm) + case nk: NodeConstraint => + for { + vcs <- cnvNodeConstraint(nk, pm) + } yield vcs case s: ShapeExternal => ok(List(List(UML.external))) - case sr: ShapeRef => cnvShapeRef(sr,id,pm) - case sd: ShapeDecl => log(s"Nested ShapeDecl not supported yet $sd", List(List())) + case sr: ShapeRef => cnvShapeRef(sr, id, pm) + case sd: ShapeDecl => + log(s"Nested ShapeDecl not supported yet $sd", List(List())) } - private def cnvShape(s: Shape, id: NodeId, pm: PrefixMap): Converter[List[List[UMLEntry]]] = for { - closedEntries <- if (s.isClosed) - ok(List(List(UML.umlClosed))) - else ok(List()) + private def cnvShape( + s: Shape, + id: NodeId, + pm: PrefixMap + ): Converter[List[List[UMLEntry]]] = for { + closedEntries <- + if (s.isClosed) + ok(List(List(UML.umlClosed))) + else ok(List()) extraEntries <- { val extras = s.extra.getOrElse(List()) if (extras.isEmpty) ok(List()) - else ok(List(List(Constant(s"EXTRA ${extras.map(pm.qualify(_)).mkString(" ")}")))) + else + ok( + List( + List(Constant(s"EXTRA ${extras.map(pm.qualify(_)).mkString(" ")}")) + ) + ) } // TODO virtual inheritedEntries <- s._extends match { - case None => ok(List()) - case Some(ls) => cnvExtends(ls,id) + case None => ok(List()) + case Some(ls) => cnvExtends(ls, id) } exprEntries <- s.expression match { - case None => ok(List()) + case None => ok(List()) case Some(e) => cnvTripleExpr(e, id, pm) } } yield mkList(closedEntries, extraEntries, inheritedEntries, exprEntries) - private def cnvShapeRef(sr: ShapeRef, id: NodeId, pm:PrefixMap): Converter[List[List[UMLEntry]]] = { + private def cnvShapeRef( + sr: ShapeRef, + id: NodeId, + pm: PrefixMap + ): Converter[List[List[UMLEntry]]] = { for { - rid <- newLabel(Some(sr.reference)) - _ <- updateUML(_.addLink(Inheritance(id,rid))) + rid <- newLabel(Some(sr.reference)) + _ <- updateUML(_.addLink(Inheritance(id, rid))) } yield { - List() + List() } } - private def cnvExtends(ls: List[ShapeLabel], - id: NodeId - ): Converter[List[List[UMLEntry]]] = { - log("cnvExtends (we don't do anything here as it is already handled at shape)", List()) + private def cnvExtends( + ls: List[ShapeLabel], + id: NodeId + ): Converter[List[List[UMLEntry]]] = { + log( + "cnvExtends (we don't do anything here as it is already handled at shape)", + List() + ) } - private def cnvNodeConstraint(nc: NodeConstraint, pm: PrefixMap): Converter[List[List[ValueConstraint]]] = for { + private def cnvNodeConstraint( + nc: NodeConstraint, + pm: PrefixMap + ): Converter[List[List[ValueConstraint]]] = for { nks <- cnvNodeKind(nc.nodeKind) - dt <- cnvDatatype(nc.datatype,pm) - facets <- cnvFacets(nc.xsFacets,pm) - values <- cnvValues(nc.values,pm) - } yield mkLs(nks,dt,facets,values) - - private def cnvShapeOrInline(es: List[ShapeExpr], pm: PrefixMap): Converter[List[List[ValueConstraint]]] = { + dt <- cnvDatatype(nc.datatype, pm) + facets <- cnvFacets(nc.xsFacets, pm) + values <- cnvValues(nc.values, pm) + } yield mkLs(nks, dt, facets, values) + + private def cnvShapeOrInline( + es: List[ShapeExpr], + pm: PrefixMap + ): Converter[List[List[ValueConstraint]]] = { for { values <- cnvList(es, cnvFlat(pm)) } yield List(List(ValueExpr("OR", values))) } - private def cnvShapeAndInline(es: List[ShapeExpr], pm: PrefixMap): Converter[List[List[ValueConstraint]]] = + private def cnvShapeAndInline( + es: List[ShapeExpr], + pm: PrefixMap + ): Converter[List[List[ValueConstraint]]] = for { values <- cnvList(es, cnvFlat(pm)) } yield List(List(ValueExpr("AND", values))) - private def cnvFacets(fs: List[XsFacet], pm:PrefixMap): Converter[List[ValueConstraint]] = { + private def cnvFacets( + fs: List[XsFacet], + pm: PrefixMap + ): Converter[List[ValueConstraint]] = { val zero: List[ValueConstraint] = List() - def cmb(next: List[ValueConstraint], c: XsFacet): Converter[List[ValueConstraint]] = for { - v <- cnvFacet(c,pm) + def cmb( + next: List[ValueConstraint], + c: XsFacet + ): Converter[List[ValueConstraint]] = for { + v <- cnvFacet(c, pm) } yield v :: next fs.foldM(zero)(cmb) } - private def cnvFacet(facet: XsFacet, pm:PrefixMap): Converter[ValueConstraint] = facet match { - case MinLength(v) => ok(Constant(s"MinLength($v)")) - case MaxLength(v) => ok(Constant(s"MaxLength($v)")) - case Length(v) => ok(Constant(s"Length($v)")) - case Pattern(r,flags) => ok(Constant(s"/$r/${flags.getOrElse("")}")) - case MinInclusive(n) => ok(Constant(s">= ${cnvNumericLiteral(n)}")) - case MaxInclusive(n) => ok(Constant(s"<= ${cnvNumericLiteral(n)}")) - case MinExclusive(n) => ok(Constant(s"> ${cnvNumericLiteral(n)}")) - case MaxExclusive(n) => ok(Constant(s"< ${cnvNumericLiteral(n)}")) - case TotalDigits(n) => ok(Constant(s"TotalDigits($n)")) + private def cnvFacet( + facet: XsFacet, + pm: PrefixMap + ): Converter[ValueConstraint] = facet match { + case MinLength(v) => ok(Constant(s"MinLength($v)")) + case MaxLength(v) => ok(Constant(s"MaxLength($v)")) + case Length(v) => ok(Constant(s"Length($v)")) + case Pattern(r, flags) => ok(Constant(s"/$r/${flags.getOrElse("")}")) + case MinInclusive(n) => ok(Constant(s">= ${cnvNumericLiteral(n)}")) + case MaxInclusive(n) => ok(Constant(s"<= ${cnvNumericLiteral(n)}")) + case MinExclusive(n) => ok(Constant(s"> ${cnvNumericLiteral(n)}")) + case MaxExclusive(n) => ok(Constant(s"< ${cnvNumericLiteral(n)}")) + case TotalDigits(n) => ok(Constant(s"TotalDigits($n)")) case FractionDigits(n) => ok(Constant(s"FractionDigits($n)")) } private def cnvNumericLiteral(l: NumericLiteral): String = l match { - case NumericInt(_,repr) => repr - case NumericDouble(_,repr) => repr - case NumericDecimal(_,repr) => repr + case NumericInt(_, repr) => repr + case NumericDouble(_, repr) => repr + case NumericDecimal(_, repr) => repr } - private def cnvValues(vs: Option[List[ValueSetValue]], pm:PrefixMap): Converter[List[ValueConstraint]] = + private def cnvValues( + vs: Option[List[ValueSetValue]], + pm: PrefixMap + ): Converter[List[ValueConstraint]] = vs match { case None => ok(List()) - case Some(vs) => for { - values <- cnvList(vs, cnvValue(_: ValueSetValue, pm)) - } yield List(ValueSet(values)) + case Some(vs) => + for { + values <- cnvList(vs, cnvValue(_: ValueSetValue, pm)) + } yield List(ValueSet(values)) } - private def cnvValue(v: ValueSetValue, pm: PrefixMap): Converter[Value] = v match { - case IRIValue(iri) => ok(Value(iri2Label(iri,pm),Some(iri.str))) - case StringValue(str) => ok(Value(str,None)) - case DatatypeString(s,iri) => ok(Value("\"" + s + "\"^^" + iri2Label(iri,pm), None)) - case LangString(s,lang) => ok(Value("\"" + s + "\"@" + lang.lang,None)) - case IRIStem(stem) => ok(Value(s"${iri2Label(stem,pm)}~",None)) - case IRIStemRange(stem,excs) => log(s"Not implemented IRIStemRange($stem,$excs) yet", Value(s"IRIStemRange($stem,$excs)",None)) - case LanguageStem(lang) => ok(Value(s"@${lang.lang}~",None)) - case LanguageStemRange(lang,excs) => log(s"Not implemented LanguageStemRange($lang,$excs) yet", Value(s"LanguageStemRange($lang,$excs)", None)) - case LiteralStem(stem) => ok(Value("\"" + "\"" + stem + "\"~",None)) - case LiteralStemRange(stem,excs) => log(s"Not implemented LiteralStemRange($stem,$excs) yet", Value(s"LanguageStemRange($stem,$excs)",None)) - case Language(lang) => ok(Value(s"@${lang.lang}",None)) - } + private def cnvValue(v: ValueSetValue, pm: PrefixMap): Converter[Value] = + v match { + case IRIValue(iri) => ok(Value(iri2Label(iri, pm), Some(iri.str))) + case StringValue(str) => ok(Value(str, None)) + case DatatypeString(s, iri) => + ok(Value("\"" + s + "\"^^" + iri2Label(iri, pm), None)) + case LangString(s, lang) => ok(Value("\"" + s + "\"@" + lang.lang, None)) + case IRIStem(stem) => ok(Value(s"${iri2Label(stem, pm)}~", None)) + case IRIStemRange(stem, excs) => + log( + s"Not implemented IRIStemRange($stem,$excs) yet", + Value(s"IRIStemRange($stem,$excs)", None) + ) + case LanguageStem(lang) => ok(Value(s"@${lang.lang}~", None)) + case LanguageStemRange(lang, excs) => + log( + s"Not implemented LanguageStemRange($lang,$excs) yet", + Value(s"LanguageStemRange($lang,$excs)", None) + ) + case LiteralStem(stem) => ok(Value("\"" + "\"" + stem + "\"~", None)) + case LiteralStemRange(stem, excs) => + log( + s"Not implemented LiteralStemRange($stem,$excs) yet", + Value(s"LanguageStemRange($stem,$excs)", None) + ) + case Language(lang) => ok(Value(s"@${lang.lang}", None)) + } - private def cnvDatatype(dt: Option[IRI], pm:PrefixMap): Converter[List[ValueConstraint]] = dt match { - case None => ok(List()) - case Some(iri) => ok(List(UML.datatype(iri2Label(iri,pm), iri.str))) + private def cnvDatatype( + dt: Option[IRI], + pm: PrefixMap + ): Converter[List[ValueConstraint]] = dt match { + case None => ok(List()) + case Some(iri) => ok(List(UML.datatype(iri2Label(iri, pm), iri.str))) } - private def cnvNodeKind(nk: Option[NodeKind]): Converter[List[ValueConstraint]] = nk match { - case None => ok(List()) - case Some(IRIKind) => ok(List(UML.iriKind)) - case Some(BNodeKind) => ok(List(UML.bnodeKind)) - case Some(LiteralKind) => ok(List(UML.literalKind)) + private def cnvNodeKind( + nk: Option[NodeKind] + ): Converter[List[ValueConstraint]] = nk match { + case None => ok(List()) + case Some(IRIKind) => ok(List(UML.iriKind)) + case Some(BNodeKind) => ok(List(UML.bnodeKind)) + case Some(LiteralKind) => ok(List(UML.literalKind)) case Some(NonLiteralKind) => ok(List(UML.nonLiteralKind)) } - private def cnvTripleExpr(e: TripleExpr, id: NodeId, pm: PrefixMap): Converter[List[List[UMLEntry]]] = e match { - case eo: EachOf => cnvEachOf(eo,id,pm) - case oo: OneOf => log(s"Id:Not supported oneOf yet: $oo", List(List(Constant("OneOf not implemented")))) - case i: Inclusion => log(s"Not supported inclusion $i yet", List()) - case e: Expr => log(s"Not supported Expr $e yet", List()) - case tc: TripleConstraint => cnvTripleConstraint(tc,id,pm) + private def cnvTripleExpr( + e: TripleExpr, + id: NodeId, + pm: PrefixMap + ): Converter[List[List[UMLEntry]]] = e match { + case eo: EachOf => cnvEachOf(eo, id, pm) + case oo: OneOf => + log( + s"Id:Not supported oneOf yet: $oo", + List(List(Constant("OneOf not implemented"))) + ) + case i: Inclusion => log(s"Not supported inclusion $i yet", List()) + case e: Expr => log(s"Not supported Expr $e yet", List()) + case tc: TripleConstraint => cnvTripleConstraint(tc, id, pm) } - private def cnvEachOf(eo: EachOf, id: NodeId, pm: PrefixMap): Converter[List[List[UMLEntry]]] = { + private def cnvEachOf( + eo: EachOf, + id: NodeId, + pm: PrefixMap + ): Converter[List[List[UMLEntry]]] = { val zero: List[List[UMLEntry]] = List() - def cmb(next: List[List[UMLEntry]], te: TripleExpr): Converter[List[List[UMLEntry]]] = for { - es <- cnvTripleExpr(te,id,pm) + def cmb( + next: List[List[UMLEntry]], + te: TripleExpr + ): Converter[List[List[UMLEntry]]] = for { + es <- cnvTripleExpr(te, id, pm) } yield es ++ next eo.expressions.reverse.foldM(zero)(cmb) } - private def cnvTripleConstraint(tc: TripleConstraint, - id: NodeId, - pm: PrefixMap): Converter[List[List[UMLEntry]]] = { + private def cnvTripleConstraint( + tc: TripleConstraint, + id: NodeId, + pm: PrefixMap + ): Converter[List[List[UMLEntry]]] = { val card = cnvCard(tc.min, tc.max) - val (label,href) = predicate2lbl(tc.predicate,pm) - + val (label, href) = predicate2lbl(tc.predicate, pm) + tc.valueExpr match { - case None => + case None => // err(s"No value expr for triple constraint $tc") ok(List(List(UMLField(label, Some(href), List(NoConstraint()), card)))) - case Some(se) => se match { - case r: ShapeRef => for { - rid <- newLabel(Some(r.reference)) - _ <- if (!tc.inverse) updateUML(_.addLink(Relationship(id, rid, label, href, card))) - else updateUML(_.addLink(Relationship(rid, id, label, href, card))) - } yield { - List() + case Some(se) => + se match { + case r: ShapeRef => + for { + rid <- newLabel(Some(r.reference)) + _ <- + if (!tc.inverse) + updateUML(_.addLink(Relationship(id, rid, label, href, card))) + else + updateUML(_.addLink(Relationship(rid, id, label, href, card))) + } yield { + List() + } + case nc: NodeConstraint => + for { + constraints <- cnvNodeConstraint(nc, pm) + } yield { + List(List(UMLField(label, Some(href), constraints.flatten, card))) + } + case _ if se === Shape.empty => + ok( + List( + List(UMLField(label, Some(href), List(UML.anyConstraint), card)) + ) + ) + + case s: Shape => + for { + sid <- newLabel(s.id) + entries <- cnvShape(s, sid, pm) + (labelShape, hrefShape) = mkLabel(s.id, pm) + cls = UMLClass(sid, labelShape, hrefShape, entries, List()) + _ <- updateUML(_.addClass(cls)) + _ <- updateUML( + _.addLink(Relationship(id, sid, label, href, card)) + ) + } yield List() + case so: ShapeOr => + for { + vso <- cnvShapeOrInline(so.shapeExprs, pm) + } yield List(List(UMLField(label, Some(href), vso.flatten, card))) + case so: ShapeAnd => + for { + vso <- cnvShapeAndInline(so.shapeExprs, pm) + } yield List(List(UMLField(label, Some(href), vso.flatten, card))) + + case _ => + log( + s"Complex shape $se in triple constraint with predicate ${label} not implemented yet", + List() + ) } - case nc: NodeConstraint => for { - constraints <- cnvNodeConstraint(nc, pm) - } yield { - List(List(UMLField(label, Some(href), constraints.flatten, card))) - } - case _ if se === Shape.empty => - ok(List(List(UMLField(label, Some(href), List(UML.anyConstraint), card)))) - - case s: Shape => for { - sid <- newLabel(s.id) - entries <- cnvShape(s, sid, pm) - (labelShape,hrefShape) = mkLabel(s.id, pm) - cls = UMLClass(sid,labelShape,hrefShape,entries, List()) - _ <- updateUML(_.addClass(cls)) - _ <- updateUML(_.addLink(Relationship(id,sid,label,href,card))) - } yield - List() - case so: ShapeOr => for { - vso <- cnvShapeOrInline(so.shapeExprs,pm) - } yield List(List(UMLField(label, Some(href), vso.flatten, card))) - case so: ShapeAnd => for { - vso <- cnvShapeAndInline(so.shapeExprs,pm) - } yield List(List(UMLField(label, Some(href), vso.flatten, card))) - - case _ => log(s"Complex shape $se in triple constraint with predicate ${label} not implemented yet", List()) - } } } - private def cnvFlat(pm: PrefixMap)(se: ShapeExpr): Converter[ValueConstraint] = se match { - case sr:ShapeRef => sr.reference.toRDFNode.toIRI match { - case Left(e) => err(e) - case Right(iri) => ok(DatatypeConstraint(iri2Label(iri,pm),iri.str)) - } - case nc:NodeConstraint => for { - vs <- cnvNodeConstraint(nc,pm) - single <- vs match { - case List(List(vc)) => ok(vc) - case _ => log(s"cnvFlat: result of cnvNodeConstraint($nc) = $vs (too complex)",Constant(s"Complex nodeConstraint")) + private def cnvFlat( + pm: PrefixMap + )(se: ShapeExpr): Converter[ValueConstraint] = se match { + case sr: ShapeRef => + sr.reference.toRDFNode.toIRI match { + case Left(e) => err(e) + case Right(iri) => ok(DatatypeConstraint(iri2Label(iri, pm), iri.str)) } - } yield single - case s: Shape => log(s"Complex shape: ${s.show}", Constant(s"Complex shape")) + case nc: NodeConstraint => + for { + vs <- cnvNodeConstraint(nc, pm) + single <- vs match { + case List(List(vc)) => ok(vc) + case _ => + log( + s"cnvFlat: result of cnvNodeConstraint($nc) = $vs (too complex)", + Constant(s"Complex nodeConstraint") + ) + } + } yield single + case s: Shape => + log(s"Complex shape: ${s.show}", Constant(s"Complex shape")) case _ => err(s"cnvFlat. Unexpected shape expr $se") } @@ -389,18 +535,18 @@ object ShEx2UML { case _ => false } */ - private def cnvCard(min: Int, max: Max): UMLCardinality = (min,max) match { - case (0,es.weso.shex.Star) => UMLStar - case (1,es.weso.shex.Star) => UMLPlus + private def cnvCard(min: Int, max: Max): UMLCardinality = (min, max) match { + case (0, es.weso.shex.Star) => UMLStar + case (1, es.weso.shex.Star) => UMLPlus case (0, es.weso.shex.IntMax(1)) => UMLOptional case (1, es.weso.shex.IntMax(1)) => NoCard - case (m, es.weso.shex.Star) => Range(m,Unbounded) - case (m,es.weso.shex.IntMax(n)) => Range(m,UMLIntMax(n)) + case (m, es.weso.shex.Star) => Range(m, Unbounded) + case (m, es.weso.shex.IntMax(n)) => Range(m, UMLIntMax(n)) } private def predicate2lbl(iri: IRI, pm: PrefixMap): (Name, HRef) = iri match { - case `rdf:type` => ("a",iri.str) - case _ => (iri2Label(iri,pm), iri.str) + case `rdf:type` => ("a", iri.str) + case _ => (iri2Label(iri, pm), iri.str) } private def mkLs[A](ls: List[A]*): List[List[A]] = { @@ -419,4 +565,4 @@ object ShEx2UML { lss.foldLeft(zero)(cmb) } -} \ No newline at end of file +} diff --git a/src/main/scala/es/weso/uml/UML.scala b/src/main/scala/es/weso/uml/UML.scala index d4d6e9f..abcc10f 100644 --- a/src/main/scala/es/weso/uml/UML.scala +++ b/src/main/scala/es/weso/uml/UML.scala @@ -11,69 +11,77 @@ import net.sourceforge.plantuml.FileFormatOption import cats.effect.IO import net.sourceforge.plantuml.core.DiagramDescription -/** - * Represents a UML-like class diagram that can be serialized to PlantUML syntax - * @param labels associates ShapeLabels to NodeIds - * @param components associates NodeIds to UMLComponents - * @param links list of links +/** Represents a UML-like class diagram that can be serialized to PlantUML + * syntax + * @param labels + * associates ShapeLabels to NodeIds + * @param components + * associates NodeIds to UMLComponents + * @param links + * list of links */ -case class UML(labels: Map[ShapeLabel,NodeId], - components: Map[NodeId, UMLComponent], - links: List[UMLLink] - ) { - - /** - * Adds a label to a UML diagram - * If exists, return the existing nodeId - * @param label Shape label - * @return a pair with the updated UML diagram and the nodeId +case class UML( + labels: Map[ShapeLabel, NodeId], + components: Map[NodeId, UMLComponent], + links: List[UMLLink] +) { + + /** Adds a label to a UML diagram If exists, return the existing nodeId + * @param label + * Shape label + * @return + * a pair with the updated UML diagram and the nodeId */ def newLabel(label: ShapeLabel): (UML, NodeId) = { - labels.get(label).fold{ - val id = this.labels.size - (this.copy(labels = this.labels.updated(label, id)), id) - } { id => - (this, id) - } + labels + .get(label) + .fold { + val id = this.labels.size + (this.copy(labels = this.labels.updated(label, id)), id) + } { id => + (this, id) + } } - /** - * Get nodeId of a shape label - * @param label shape label + /** Get nodeId of a shape label + * @param label + * shape label * @return */ def getId(label: ShapeLabel): Option[NodeId] = labels.get(label) def addClass(cls: UMLClass): UML = { - this.copy(components = components.updated(cls.id,cls)) + this.copy(components = components.updated(cls.id, cls)) } def addLink(link: UMLLink): UML = this.copy(links = link :: links) - - private def strHref(href: Option[HRef], - lbl: Name): String = href match { - case None => "" + private def strHref(href: Option[HRef], lbl: Name): String = href match { + case None => "" case Some(href) => s"[[${href} ${lbl}]]" } def cnvValueConstraint(vc: ValueConstraint): String = vc match { case Constant(c) => c case ValueSet(vs) => { - "[ " + vs.map{ v => v.href match { - case None => v.name - case Some(href) => s"[[${href} ${v.name}]]" } - }.mkString(" ") + " ]" + "[ " + vs + .map { v => + v.href match { + case None => v.name + case Some(href) => s"[[${href} ${v.name}]]" + } + } + .mkString(" ") + " ]" } - case DatatypeConstraint(name,href) => { + case DatatypeConstraint(name, href) => { s"[[${href} ${name}]] " } - case RefConstraint(name,href) => { + case RefConstraint(name, href) => { s"[[${href} @${name}]] " } - case ValueExpr(op,vs) => vs.map(cnvValueConstraint(_)).mkString(s" ${op} ") - case NoConstraint() => s"." + case ValueExpr(op, vs) => vs.map(cnvValueConstraint(_)).mkString(s" ${op} ") + case NoConstraint() => s"." } def cnvFieldExpr(fe: FieldExpr): String = { @@ -81,13 +89,15 @@ case class UML(labels: Map[ShapeLabel,NodeId], } def cnvEntry(entry: UMLEntry): String = entry match { - case field: UMLField => cnvField(field) + case field: UMLField => cnvField(field) case vc: ValueConstraint => cnvValueConstraint(vc) - case fe: FieldExpr => cnvFieldExpr(fe) + case fe: FieldExpr => cnvFieldExpr(fe) } def cnvField(field: UMLField): String = - s"${strHref(field.href,field.name)} : ${field.valueConstraints.map(cnvValueConstraint(_)).mkString(" ")} ${field.card}" + s"${strHref(field.href, field.name)} : ${field.valueConstraints + .map(cnvValueConstraint(_)) + .mkString(" ")} ${field.card}" def cnvComponent(c: UMLComponent): String = c match { case cls: UMLClass => cnvClass(cls) @@ -96,7 +106,10 @@ case class UML(labels: Map[ShapeLabel,NodeId], def cnvClass(cls: UMLClass): String = { val sb = new StringBuilder - sb.append(s"""class "${cls.label}" as ${cls.id} <<(S,#FF7700)>> ${strHref(cls.href, cls.label)} {\n""") + sb.append(s"""class "${cls.label}" as ${cls.id} <<(S,#FF7700)>> ${strHref( + cls.href, + cls.label + )} {\n""") cls.entries.foreach { entryLs => entryLs.foreach { entry => sb.append(cnvEntry(entry)) @@ -120,94 +133,116 @@ case class UML(labels: Map[ShapeLabel,NodeId], } def cnvLink(link: UMLLink): String = link match { - case r: Relationship => s"""${r.source} --> "${r.card}" ${r.target} : [[${r.href} ${r.label}]]\n""" + case r: Relationship => + s"""${r.source} --> "${r.card}" ${r.target} : [[${r.href} ${r.label}]]\n""" case r: Inheritance => s"""${r.source} --|> ${r.target} \n""" } def toPlantUML(options: PlantUMLOptions): String = { val sb = new StringBuilder sb.append("@startuml\n") - components.values.foreach { - c => sb.append(cnvComponent(c)) + components.values.foreach { c => + sb.append(cnvComponent(c)) } links.foreach { link => sb.append(cnvLink(link)) } - components.values.foreach { - cls => sb.append(cnvExtends(cls)) + components.values.foreach { cls => + sb.append(cnvExtends(cls)) } options.watermark match { case None => () - case Some(watermarkFooter) => sb.append(s"\nright footer $watermarkFooter\n") + case Some(watermarkFooter) => + sb.append(s"\nright footer $watermarkFooter\n") } sb.append("@enduml\n") sb.toString } - /** - * Convert a UML diagram to some format - * @param options plantUML options - * @param format output format + /** Convert a UML diagram to some format + * @param options + * plantUML options + * @param format + * output format * @return */ - def toFormat(options: PlantUMLOptions, format: net.sourceforge.plantuml.FileFormat): IO[String] = try { - val reader: SourceStringReader = new SourceStringReader(this.toPlantUML(options)) + def toFormat( + options: PlantUMLOptions, + format: net.sourceforge.plantuml.FileFormat + ): IO[String] = try { + val reader: SourceStringReader = new SourceStringReader( + this.toPlantUML(options) + ) val os: ByteArrayOutputStream = new ByteArrayOutputStream() - val d: DiagramDescription = reader.outputImage(os, new FileFormatOption(format)) + val d: DiagramDescription = + reader.outputImage(os, new FileFormatOption(format)) // System.out.println(s"Generated diagram description: ${d.getDescription}") os.close val outStr: String = new String(os.toByteArray(), Charset.forName("UTF-8")) IO.pure(outStr) } catch { - case e: Exception => IO.raiseError(new RuntimeException(s"Exception converting to format: ${format}: ${e.getMessage}")) + case e: Exception => + IO.raiseError( + new RuntimeException( + s"Exception converting to format: ${format}: ${e.getMessage}" + ) + ) } - /** - * Converts a diagram to SVG - * @param options PlantUML options - * @return an IO action that generates the SVG representation of the UML diagram + /** Converts a diagram to SVG + * @param options + * PlantUML options + * @return + * an IO action that generates the SVG representation of the UML diagram */ - def toSVG(options: PlantUMLOptions): IO[String] = this.toFormat(options,FileFormat.SVG) + def toSVG(options: PlantUMLOptions): IO[String] = + this.toFormat(options, FileFormat.SVG) private def label2Json(label: ShapeLabel): Json = label match { - case IRILabel(iri) => Json.fromString(iri.toString) + case IRILabel(iri) => Json.fromString(iri.toString) case BNodeLabel(bn) => Json.fromString(bn.id) - case Start => Json.fromString("START") + case Start => Json.fromString("START") } private def node2Json(node: NodeId): Json = Json.fromInt(node) private def labelPair2Json(pair: (ShapeLabel, NodeId)): Json = { - val (label,node) = pair + val (label, node) = pair Json.fromFields( List( ("shapeLabel", label2Json(label)), ("node", node2Json(node)) - )) + ) + ) } private def componentPair2Json(pair: (NodeId, UMLComponent)): Json = { val (node, component) = pair - Json.fromFields(List( - ("node", node2Json(node)), - ("component", component.toJson) - )) + Json.fromFields( + List( + ("node", node2Json(node)), + ("component", component.toJson) + ) + ) } - /** - * Convert the UML diagram to JSON - * @return JSON representation of the diagram + /** Convert the UML diagram to JSON + * @return + * JSON representation of the diagram */ def toJson: Json = Json.fromFields( List( ("labels", Json.fromValues(labels.toList.map(labelPair2Json(_)))), - ("components", Json.fromValues(components.toList.map(componentPair2Json(_)))), - ("links",Json.fromValues(links.map(_.toJson))) + ( + "components", + Json.fromValues(components.toList.map(componentPair2Json(_))) + ), + ("links", Json.fromValues(links.map(_.toJson))) ) ) } object UML { - def empty: UML = UML(Map(),Map(), List()) + def empty: UML = UML(Map(), Map(), List()) lazy val external = Constant("External") lazy val iriKind = Constant("IRI") lazy val bnodeKind = Constant("BNode") @@ -215,6 +250,6 @@ object UML { lazy val literalKind = Constant("Literal") lazy val umlClosed = Constant("Closed") lazy val anyConstraint = Constant(".") - def datatype(label: String, href: String) = DatatypeConstraint(label,href) + def datatype(label: String, href: String) = DatatypeConstraint(label, href) }